diff options
| author | Philipp Stephani | 2018-06-02 22:35:22 +0200 |
|---|---|---|
| committer | Philipp Stephani | 2018-06-09 18:47:10 +0200 |
| commit | b4dcac2d6ae376788dca11b88b874a9ecaf986df (patch) | |
| tree | e6185efc4660b5192f5c6c78017768e18ac9440b /src | |
| parent | ca369a8ca67a4cb279a5412cca36109e719a520e (diff) | |
| download | emacs-b4dcac2d6ae376788dca11b88b874a9ecaf986df.tar.gz emacs-b4dcac2d6ae376788dca11b88b874a9ecaf986df.zip | |
Make error checking for thread functions stricter.
* src/systhread.c (sys_thread_create): Change return type to bool.
Check for errors returned by pthread_attr_setstacksize and
pthread_attr_destroy.
(sys_mutex_init): Abort on errors. Enable mutex checks when checking
is enabled.
(sys_cond_init): Abort on errors.
(sys_mutex_lock, sys_mutex_unlock, sys_cond_wait)
(sys_cond_signal, sys_cond_broadcast, sys_cond_destroy): Check for
errors in debug mode.
Diffstat (limited to 'src')
| -rw-r--r-- | src/systhread.c | 78 | ||||
| -rw-r--r-- | src/systhread.h | 24 |
2 files changed, 79 insertions, 23 deletions
diff --git a/src/systhread.c b/src/systhread.c index e972ed398ac..d53b5c207b6 100644 --- a/src/systhread.c +++ b/src/systhread.c | |||
| @@ -18,6 +18,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 18 | 18 | ||
| 19 | #include <config.h> | 19 | #include <config.h> |
| 20 | #include <setjmp.h> | 20 | #include <setjmp.h> |
| 21 | #include <stdio.h> | ||
| 22 | #include <string.h> | ||
| 21 | #include "lisp.h" | 23 | #include "lisp.h" |
| 22 | 24 | ||
| 23 | #ifdef HAVE_NS | 25 | #ifdef HAVE_NS |
| @@ -80,11 +82,11 @@ sys_thread_equal (sys_thread_t t, sys_thread_t u) | |||
| 80 | return t == u; | 82 | return t == u; |
| 81 | } | 83 | } |
| 82 | 84 | ||
| 83 | int | 85 | bool |
| 84 | sys_thread_create (sys_thread_t *t, const char *name, | 86 | sys_thread_create (sys_thread_t *t, const char *name, |
| 85 | thread_creation_function *func, void *datum) | 87 | thread_creation_function *func, void *datum) |
| 86 | { | 88 | { |
| 87 | return 0; | 89 | return false; |
| 88 | } | 90 | } |
| 89 | 91 | ||
| 90 | void | 92 | void |
| @@ -103,43 +105,77 @@ sys_thread_yield (void) | |||
| 103 | void | 105 | void |
| 104 | sys_mutex_init (sys_mutex_t *mutex) | 106 | sys_mutex_init (sys_mutex_t *mutex) |
| 105 | { | 107 | { |
| 106 | pthread_mutex_init (mutex, NULL); | 108 | pthread_mutexattr_t *attr_ptr; |
| 109 | #ifdef ENABLE_CHECKING | ||
| 110 | pthread_mutexattr_t attr; | ||
| 111 | { | ||
| 112 | int error = pthread_mutexattr_init (&attr); | ||
| 113 | eassert (error == 0); | ||
| 114 | error = pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK); | ||
| 115 | eassert (error == 0); | ||
| 116 | } | ||
| 117 | attr_ptr = &attr; | ||
| 118 | #else | ||
| 119 | attr_ptr = NULL; | ||
| 120 | #endif | ||
| 121 | int error = pthread_mutex_init (mutex, attr_ptr); | ||
| 122 | /* We could get ENOMEM. Can't do anything except aborting. */ | ||
| 123 | if (error != 0) | ||
| 124 | { | ||
| 125 | fprintf (stderr, "\npthread_mutex_init failed: %s\n", strerror (error)); | ||
| 126 | emacs_abort (); | ||
| 127 | } | ||
| 128 | #ifdef ENABLE_CHECKING | ||
| 129 | error = pthread_mutexattr_destroy (&attr); | ||
| 130 | eassert (error == 0); | ||
| 131 | #endif | ||
| 107 | } | 132 | } |
| 108 | 133 | ||
| 109 | void | 134 | void |
| 110 | sys_mutex_lock (sys_mutex_t *mutex) | 135 | sys_mutex_lock (sys_mutex_t *mutex) |
| 111 | { | 136 | { |
| 112 | pthread_mutex_lock (mutex); | 137 | int error = pthread_mutex_lock (mutex); |
| 138 | eassert (error == 0); | ||
| 113 | } | 139 | } |
| 114 | 140 | ||
| 115 | void | 141 | void |
| 116 | sys_mutex_unlock (sys_mutex_t *mutex) | 142 | sys_mutex_unlock (sys_mutex_t *mutex) |
| 117 | { | 143 | { |
| 118 | pthread_mutex_unlock (mutex); | 144 | int error = pthread_mutex_unlock (mutex); |
| 145 | eassert (error == 0); | ||
| 119 | } | 146 | } |
| 120 | 147 | ||
| 121 | void | 148 | void |
| 122 | sys_cond_init (sys_cond_t *cond) | 149 | sys_cond_init (sys_cond_t *cond) |
| 123 | { | 150 | { |
| 124 | pthread_cond_init (cond, NULL); | 151 | int error = pthread_cond_init (cond, NULL); |
| 152 | /* We could get ENOMEM. Can't do anything except aborting. */ | ||
| 153 | if (error != 0) | ||
| 154 | { | ||
| 155 | fprintf (stderr, "\npthread_cond_init failed: %s\n", strerror (error)); | ||
| 156 | emacs_abort (); | ||
| 157 | } | ||
| 125 | } | 158 | } |
| 126 | 159 | ||
| 127 | void | 160 | void |
| 128 | sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex) | 161 | sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex) |
| 129 | { | 162 | { |
| 130 | pthread_cond_wait (cond, mutex); | 163 | int error = pthread_cond_wait (cond, mutex); |
| 164 | eassert (error == 0); | ||
| 131 | } | 165 | } |
| 132 | 166 | ||
| 133 | void | 167 | void |
| 134 | sys_cond_signal (sys_cond_t *cond) | 168 | sys_cond_signal (sys_cond_t *cond) |
| 135 | { | 169 | { |
| 136 | pthread_cond_signal (cond); | 170 | int error = pthread_cond_signal (cond); |
| 171 | eassert (error == 0); | ||
| 137 | } | 172 | } |
| 138 | 173 | ||
| 139 | void | 174 | void |
| 140 | sys_cond_broadcast (sys_cond_t *cond) | 175 | sys_cond_broadcast (sys_cond_t *cond) |
| 141 | { | 176 | { |
| 142 | pthread_cond_broadcast (cond); | 177 | int error = pthread_cond_broadcast (cond); |
| 178 | eassert (error == 0); | ||
| 143 | #ifdef HAVE_NS | 179 | #ifdef HAVE_NS |
| 144 | /* Send an app defined event to break out of the NS run loop. | 180 | /* Send an app defined event to break out of the NS run loop. |
| 145 | It seems that if ns_select is running the NS run loop, this | 181 | It seems that if ns_select is running the NS run loop, this |
| @@ -152,7 +188,8 @@ sys_cond_broadcast (sys_cond_t *cond) | |||
| 152 | void | 188 | void |
| 153 | sys_cond_destroy (sys_cond_t *cond) | 189 | sys_cond_destroy (sys_cond_t *cond) |
| 154 | { | 190 | { |
| 155 | pthread_cond_destroy (cond); | 191 | int error = pthread_cond_destroy (cond); |
| 192 | eassert (error == 0); | ||
| 156 | } | 193 | } |
| 157 | 194 | ||
| 158 | sys_thread_t | 195 | sys_thread_t |
| @@ -167,22 +204,25 @@ sys_thread_equal (sys_thread_t t, sys_thread_t u) | |||
| 167 | return pthread_equal (t, u); | 204 | return pthread_equal (t, u); |
| 168 | } | 205 | } |
| 169 | 206 | ||
| 170 | int | 207 | bool |
| 171 | sys_thread_create (sys_thread_t *thread_ptr, const char *name, | 208 | sys_thread_create (sys_thread_t *thread_ptr, const char *name, |
| 172 | thread_creation_function *func, void *arg) | 209 | thread_creation_function *func, void *arg) |
| 173 | { | 210 | { |
| 174 | pthread_attr_t attr; | 211 | pthread_attr_t attr; |
| 175 | int result = 0; | 212 | bool result = false; |
| 176 | 213 | ||
| 177 | if (pthread_attr_init (&attr)) | 214 | if (pthread_attr_init (&attr)) |
| 178 | return 0; | 215 | return false; |
| 179 | 216 | ||
| 180 | /* Avoid crash on macOS with deeply nested GC (Bug#30364). */ | 217 | /* Avoid crash on macOS with deeply nested GC (Bug#30364). */ |
| 181 | size_t stack_size; | 218 | size_t stack_size; |
| 182 | size_t required_stack_size = sizeof (void *) * 1024 * 1024; | 219 | size_t required_stack_size = sizeof (void *) * 1024 * 1024; |
| 183 | if (pthread_attr_getstacksize (&attr, &stack_size) == 0 | 220 | if (pthread_attr_getstacksize (&attr, &stack_size) == 0 |
| 184 | && stack_size < required_stack_size) | 221 | && stack_size < required_stack_size) |
| 185 | pthread_attr_setstacksize (&attr, required_stack_size); | 222 | { |
| 223 | if (pthread_attr_setstacksize (&attr, required_stack_size) != 0) | ||
| 224 | goto out; | ||
| 225 | } | ||
| 186 | 226 | ||
| 187 | if (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED)) | 227 | if (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED)) |
| 188 | { | 228 | { |
| @@ -193,7 +233,9 @@ sys_thread_create (sys_thread_t *thread_ptr, const char *name, | |||
| 193 | #endif | 233 | #endif |
| 194 | } | 234 | } |
| 195 | 235 | ||
| 196 | pthread_attr_destroy (&attr); | 236 | out: ; |
| 237 | int error = pthread_attr_destroy (&attr); | ||
| 238 | eassert (error == 0); | ||
| 197 | 239 | ||
| 198 | return result; | 240 | return result; |
| 199 | } | 241 | } |
| @@ -359,7 +401,7 @@ w32_beginthread_wrapper (void *arg) | |||
| 359 | (void)thread_start_address (arg); | 401 | (void)thread_start_address (arg); |
| 360 | } | 402 | } |
| 361 | 403 | ||
| 362 | int | 404 | bool |
| 363 | sys_thread_create (sys_thread_t *thread_ptr, const char *name, | 405 | sys_thread_create (sys_thread_t *thread_ptr, const char *name, |
| 364 | thread_creation_function *func, void *arg) | 406 | thread_creation_function *func, void *arg) |
| 365 | { | 407 | { |
| @@ -383,7 +425,7 @@ sys_thread_create (sys_thread_t *thread_ptr, const char *name, | |||
| 383 | rule in many places... */ | 425 | rule in many places... */ |
| 384 | thandle = _beginthread (w32_beginthread_wrapper, stack_size, arg); | 426 | thandle = _beginthread (w32_beginthread_wrapper, stack_size, arg); |
| 385 | if (thandle == (uintptr_t)-1L) | 427 | if (thandle == (uintptr_t)-1L) |
| 386 | return 0; | 428 | return false; |
| 387 | 429 | ||
| 388 | /* Kludge alert! We use the Windows thread ID, an unsigned 32-bit | 430 | /* Kludge alert! We use the Windows thread ID, an unsigned 32-bit |
| 389 | number, as the sys_thread_t type, because that ID is the only | 431 | number, as the sys_thread_t type, because that ID is the only |
| @@ -398,7 +440,7 @@ sys_thread_create (sys_thread_t *thread_ptr, const char *name, | |||
| 398 | Therefore, we return some more or less arbitrary value of the | 440 | Therefore, we return some more or less arbitrary value of the |
| 399 | thread ID from this function. */ | 441 | thread ID from this function. */ |
| 400 | *thread_ptr = thandle & 0xFFFFFFFF; | 442 | *thread_ptr = thandle & 0xFFFFFFFF; |
| 401 | return 1; | 443 | return true; |
| 402 | } | 444 | } |
| 403 | 445 | ||
| 404 | void | 446 | void |
diff --git a/src/systhread.h b/src/systhread.h index 5dbb12dffb6..3805cb261f1 100644 --- a/src/systhread.h +++ b/src/systhread.h | |||
| @@ -19,6 +19,18 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 19 | #ifndef SYSTHREAD_H | 19 | #ifndef SYSTHREAD_H |
| 20 | #define SYSTHREAD_H | 20 | #define SYSTHREAD_H |
| 21 | 21 | ||
| 22 | #include <stdbool.h> | ||
| 23 | |||
| 24 | #ifndef __has_attribute | ||
| 25 | # define __has_attribute(a) false | ||
| 26 | #endif | ||
| 27 | |||
| 28 | #if __has_attribute (__warn_unused_result__) | ||
| 29 | # define ATTRIBUTE_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) | ||
| 30 | #else | ||
| 31 | # define ATTRIBUTE_WARN_UNUSED_RESULT | ||
| 32 | #endif | ||
| 33 | |||
| 22 | #ifdef THREADS_ENABLED | 34 | #ifdef THREADS_ENABLED |
| 23 | 35 | ||
| 24 | #ifdef HAVE_PTHREAD | 36 | #ifdef HAVE_PTHREAD |
| @@ -99,12 +111,14 @@ extern void sys_cond_signal (sys_cond_t *); | |||
| 99 | extern void sys_cond_broadcast (sys_cond_t *); | 111 | extern void sys_cond_broadcast (sys_cond_t *); |
| 100 | extern void sys_cond_destroy (sys_cond_t *); | 112 | extern void sys_cond_destroy (sys_cond_t *); |
| 101 | 113 | ||
| 102 | extern sys_thread_t sys_thread_self (void); | 114 | extern sys_thread_t sys_thread_self (void) |
| 103 | extern bool sys_thread_equal (sys_thread_t, sys_thread_t); | 115 | ATTRIBUTE_WARN_UNUSED_RESULT; |
| 116 | extern bool sys_thread_equal (sys_thread_t, sys_thread_t) | ||
| 117 | ATTRIBUTE_WARN_UNUSED_RESULT; | ||
| 104 | 118 | ||
| 105 | extern int sys_thread_create (sys_thread_t *, const char *, | 119 | extern bool sys_thread_create (sys_thread_t *, const char *, |
| 106 | thread_creation_function *, | 120 | thread_creation_function *, void *) |
| 107 | void *); | 121 | ATTRIBUTE_WARN_UNUSED_RESULT; |
| 108 | 122 | ||
| 109 | extern void sys_thread_yield (void); | 123 | extern void sys_thread_yield (void); |
| 110 | 124 | ||