diff options
Diffstat (limited to 'arch/um/os-Linux/signal.c')
| -rw-r--r-- | arch/um/os-Linux/signal.c | 31 |
1 files changed, 28 insertions, 3 deletions
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 6b81739279d1..b897e8592d77 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include "user.h" | 15 | #include "user.h" |
| 16 | #include "signal_kern.h" | 16 | #include "signal_kern.h" |
| 17 | #include "sysdep/sigcontext.h" | 17 | #include "sysdep/sigcontext.h" |
| 18 | #include "sysdep/barrier.h" | ||
| 18 | #include "sigcontext.h" | 19 | #include "sigcontext.h" |
| 19 | #include "mode.h" | 20 | #include "mode.h" |
| 20 | #include "os.h" | 21 | #include "os.h" |
| @@ -34,8 +35,12 @@ | |||
| 34 | #define SIGALRM_BIT 2 | 35 | #define SIGALRM_BIT 2 |
| 35 | #define SIGALRM_MASK (1 << SIGALRM_BIT) | 36 | #define SIGALRM_MASK (1 << SIGALRM_BIT) |
| 36 | 37 | ||
| 37 | static int signals_enabled = 1; | 38 | /* These are used by both the signal handlers and |
| 38 | static int pending = 0; | 39 | * block/unblock_signals. I don't want modifications cached in a |
| 40 | * register - they must go straight to memory. | ||
| 41 | */ | ||
| 42 | static volatile int signals_enabled = 1; | ||
| 43 | static volatile int pending = 0; | ||
| 39 | 44 | ||
| 40 | void sig_handler(int sig, struct sigcontext *sc) | 45 | void sig_handler(int sig, struct sigcontext *sc) |
| 41 | { | 46 | { |
| @@ -152,6 +157,12 @@ int change_sig(int signal, int on) | |||
| 152 | void block_signals(void) | 157 | void block_signals(void) |
| 153 | { | 158 | { |
| 154 | signals_enabled = 0; | 159 | signals_enabled = 0; |
| 160 | /* This must return with signals disabled, so this barrier | ||
| 161 | * ensures that writes are flushed out before the return. | ||
| 162 | * This might matter if gcc figures out how to inline this and | ||
| 163 | * decides to shuffle this code into the caller. | ||
| 164 | */ | ||
| 165 | mb(); | ||
| 155 | } | 166 | } |
| 156 | 167 | ||
| 157 | void unblock_signals(void) | 168 | void unblock_signals(void) |
| @@ -171,9 +182,23 @@ void unblock_signals(void) | |||
| 171 | */ | 182 | */ |
| 172 | signals_enabled = 1; | 183 | signals_enabled = 1; |
| 173 | 184 | ||
| 185 | /* Setting signals_enabled and reading pending must | ||
| 186 | * happen in this order. | ||
| 187 | */ | ||
| 188 | mb(); | ||
| 189 | |||
| 174 | save_pending = pending; | 190 | save_pending = pending; |
| 175 | if(save_pending == 0) | 191 | if(save_pending == 0){ |
| 192 | /* This must return with signals enabled, so | ||
| 193 | * this barrier ensures that writes are | ||
| 194 | * flushed out before the return. This might | ||
| 195 | * matter if gcc figures out how to inline | ||
| 196 | * this (unlikely, given its size) and decides | ||
| 197 | * to shuffle this code into the caller. | ||
| 198 | */ | ||
| 199 | mb(); | ||
| 176 | return; | 200 | return; |
| 201 | } | ||
| 177 | 202 | ||
| 178 | pending = 0; | 203 | pending = 0; |
| 179 | 204 | ||
