diff options
| author | Eli Zaretskii | 2013-08-30 17:19:16 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2013-08-30 17:19:16 +0300 |
| commit | dbe17fefccbff010bbbf6c4d0dccc7b2f3a5e201 (patch) | |
| tree | d6844a441dc78f6a18610e9f88d82e0c8f12f6db /src | |
| parent | 0e82377a2d9d8f815d2ef4ec09dc914f37fc87ac (diff) | |
| download | emacs-dbe17fefccbff010bbbf6c4d0dccc7b2f3a5e201.tar.gz emacs-dbe17fefccbff010bbbf6c4d0dccc7b2f3a5e201.zip | |
Enable thread support in the MS-Windows build.
src/systhread.h (w32thread_critsect, w32thread_cond_t, sys_mutex_t)
(sys_cond_t, sys_thread_t) [WINDOWSNT]: New data types.
src/systhread.c (sys_mutex_init, sys_mutex_lock, sys_mutex_unlock)
(sys_mutex_destroy, sys_cond_init, sys_cond_wait)
(sys_cond_signal, sys_cond_broadcast, sys_cond_destroy)
(sys_thread_self, sys_thread_equal, w32_beginthread_wrapper)
(sys_thread_create, sys_thread_yield) [WINDOWSNT]: New functions.
configure.ac (THREADS_ENABLED): Enable threads for MinGW, even
if pthreads is not available.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 11 | ||||
| -rw-r--r-- | src/systhread.c | 149 | ||||
| -rw-r--r-- | src/systhread.h | 34 |
3 files changed, 194 insertions, 0 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index a0682bdfd48..0aef16d34e3 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,14 @@ | |||
| 1 | 2013-08-30 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | * systhread.h (w32thread_critsect, w32thread_cond_t, sys_mutex_t) | ||
| 4 | (sys_cond_t, sys_thread_t) [WINDOWSNT]: New data types. | ||
| 5 | |||
| 6 | * systhread.c (sys_mutex_init, sys_mutex_lock, sys_mutex_unlock) | ||
| 7 | (sys_mutex_destroy, sys_cond_init, sys_cond_wait) | ||
| 8 | (sys_cond_signal, sys_cond_broadcast, sys_cond_destroy) | ||
| 9 | (sys_thread_self, sys_thread_equal, w32_beginthread_wrapper) | ||
| 10 | (sys_thread_create, sys_thread_yield) [WINDOWSNT]: New functions. | ||
| 11 | |||
| 1 | 2013-08-26 Eli Zaretskii <eliz@gnu.org> | 12 | 2013-08-26 Eli Zaretskii <eliz@gnu.org> |
| 2 | 13 | ||
| 3 | * callproc.c: | 14 | * callproc.c: |
diff --git a/src/systhread.c b/src/systhread.c index 8c9ec438d96..b154abaecd6 100644 --- a/src/systhread.c +++ b/src/systhread.c | |||
| @@ -197,6 +197,155 @@ sys_thread_yield (void) | |||
| 197 | sched_yield (); | 197 | sched_yield (); |
| 198 | } | 198 | } |
| 199 | 199 | ||
| 200 | #elif defined (WINDOWSNT) | ||
| 201 | |||
| 202 | #include <windows.h> | ||
| 203 | |||
| 204 | /* Cannot include <process.h> because of the local header by the same | ||
| 205 | name, sigh. */ | ||
| 206 | uintptr_t _beginthread (void (__cdecl *)(void *), unsigned, void *); | ||
| 207 | |||
| 208 | /* Mutexes are implemented as critical sections, because they are | ||
| 209 | faster than Windows mutex objects (implemented in userspace), and | ||
| 210 | satisfy the requirements, since we only needto synchronize within a | ||
| 211 | single process. */ | ||
| 212 | void | ||
| 213 | sys_mutex_init (sys_mutex_t *mutex) | ||
| 214 | { | ||
| 215 | InitializeCriticalSection ((LPCRITICAL_SECTION)mutex); | ||
| 216 | } | ||
| 217 | |||
| 218 | void | ||
| 219 | sys_mutex_lock (sys_mutex_t *mutex) | ||
| 220 | { | ||
| 221 | /* FIXME: What happens if the owning thread exits without releasing | ||
| 222 | the mutex? Accoding to MSDN, the result is undefined behavior. */ | ||
| 223 | EnterCriticalSection ((LPCRITICAL_SECTION)mutex); | ||
| 224 | } | ||
| 225 | |||
| 226 | void | ||
| 227 | sys_mutex_unlock (sys_mutex_t *mutex) | ||
| 228 | { | ||
| 229 | LeaveCriticalSection ((LPCRITICAL_SECTION)mutex); | ||
| 230 | } | ||
| 231 | |||
| 232 | void | ||
| 233 | sys_mutex_destroy (sys_mutex_t *mutex) | ||
| 234 | { | ||
| 235 | /* FIXME: According to MSDN, deleting a critical session that is | ||
| 236 | owned by a thread leaves the other threads waiting for the | ||
| 237 | critical session in an undefined state. Posix docs seems to say | ||
| 238 | the same about pthread_mutex_destroy. Do we need to protect | ||
| 239 | against such calamities? */ | ||
| 240 | DeleteCriticalSection ((LPCRITICAL_SECTION)mutex); | ||
| 241 | } | ||
| 242 | |||
| 243 | void | ||
| 244 | sys_cond_init (sys_cond_t *cond) | ||
| 245 | { | ||
| 246 | cond->events[CONDV_SIGNAL] = CreateEvent (NULL, FALSE, FALSE, NULL); | ||
| 247 | cond->events[CONDV_BROADCAST] = CreateEvent (NULL, TRUE, FALSE, NULL); | ||
| 248 | } | ||
| 249 | |||
| 250 | void | ||
| 251 | sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex) | ||
| 252 | { | ||
| 253 | /* FIXME: This implementation is simple, but incorrect. Stay tuned | ||
| 254 | for better and more complicated implementation. */ | ||
| 255 | LeaveCriticalSection ((LPCRITICAL_SECTION)mutex); | ||
| 256 | WaitForMultipleObjects (2, cond->events, FALSE, INFINITE); | ||
| 257 | EnterCriticalSection ((LPCRITICAL_SECTION)mutex); | ||
| 258 | } | ||
| 259 | |||
| 260 | void | ||
| 261 | sys_cond_signal (sys_cond_t *cond) | ||
| 262 | { | ||
| 263 | PulseEvent (cond->events[CONDV_SIGNAL]); | ||
| 264 | } | ||
| 265 | |||
| 266 | void | ||
| 267 | sys_cond_broadcast (sys_cond_t *cond) | ||
| 268 | { | ||
| 269 | PulseEvent (cond->events[CONDV_BROADCAST]); | ||
| 270 | } | ||
| 271 | |||
| 272 | void | ||
| 273 | sys_cond_destroy (sys_cond_t *cond) | ||
| 274 | { | ||
| 275 | CloseHandle (cond->events[CONDV_SIGNAL]); | ||
| 276 | CloseHandle (cond->events[CONDV_BROADCAST]); | ||
| 277 | } | ||
| 278 | |||
| 279 | sys_thread_t | ||
| 280 | sys_thread_self (void) | ||
| 281 | { | ||
| 282 | return (sys_thread_t) GetCurrentThreadId (); | ||
| 283 | } | ||
| 284 | |||
| 285 | int | ||
| 286 | sys_thread_equal (sys_thread_t one, sys_thread_t two) | ||
| 287 | { | ||
| 288 | return one == two; | ||
| 289 | } | ||
| 290 | |||
| 291 | static thread_creation_function *thread_start_address; | ||
| 292 | |||
| 293 | static void | ||
| 294 | w32_beginthread_wrapper (void *arg) | ||
| 295 | { | ||
| 296 | (void)thread_start_address (arg); | ||
| 297 | } | ||
| 298 | |||
| 299 | int | ||
| 300 | sys_thread_create (sys_thread_t *thread_ptr, const char *name, | ||
| 301 | thread_creation_function *func, void *arg) | ||
| 302 | { | ||
| 303 | /* FIXME: Do threads that run Lisp require some minimum amount of | ||
| 304 | stack? Zero here means each thread will get the same amount as | ||
| 305 | the main program. On GNU/Linux, it seems like the stack is 2MB | ||
| 306 | by default, overridden by RLIMIT_STACK at program start time. | ||
| 307 | Not sure what to do with this. See also the comment in | ||
| 308 | w32proc"new_child. */ | ||
| 309 | const unsigned stack_size = 0; | ||
| 310 | uintptr_t thandle; | ||
| 311 | |||
| 312 | /* _beginthread wants a void function, while we are passed a | ||
| 313 | function that returns a pointer. So we use a wrapper. */ | ||
| 314 | thread_start_address = func; | ||
| 315 | |||
| 316 | /* We use _beginthread rather than CreateThread because the former | ||
| 317 | arranges for the thread handle to be automatically closed when | ||
| 318 | the thread exits, thus preventing handle leaks and/or the need to | ||
| 319 | track all the threads and close their handles when they exit. | ||
| 320 | Also, MSDN seems to imply that code which uses CRT _must_ call | ||
| 321 | _beginthread, although if that is true, we already violate that | ||
| 322 | rule in many places... */ | ||
| 323 | thandle = _beginthread (w32_beginthread_wrapper, stack_size, arg); | ||
| 324 | if (thandle == (uintptr_t)-1L) | ||
| 325 | return errno; | ||
| 326 | |||
| 327 | /* Kludge alert! We use the Windows thread ID, an unsigned 32-bit | ||
| 328 | number, as the sys_thread_t type, because that ID is the only | ||
| 329 | unique identifier of a thread on Windows. But _beginthread | ||
| 330 | returns a handle of the thread, and there's no easy way of | ||
| 331 | getting the thread ID given a handle (GetThreadId is available | ||
| 332 | only since Vista, so we cannot use it portably). Fortunately, | ||
| 333 | the value returned by sys_thread_create is not used by its | ||
| 334 | callers; instead, run_thread, which runs in the context of the | ||
| 335 | new thread, calls sys_thread_self and uses its return value; | ||
| 336 | sys_thread_self in this implementation calls GetCurrentThreadId. | ||
| 337 | Therefore, we return some more or less arbitrary value of the | ||
| 338 | thread ID from this function. */ | ||
| 339 | *thread_ptr = thandle & 0xFFFFFFFF; | ||
| 340 | return 0; | ||
| 341 | } | ||
| 342 | |||
| 343 | void | ||
| 344 | sys_thread_yield (void) | ||
| 345 | { | ||
| 346 | Sleep (0); | ||
| 347 | } | ||
| 348 | |||
| 200 | #else | 349 | #else |
| 201 | 350 | ||
| 202 | #error port me | 351 | #error port me |
diff --git a/src/systhread.h b/src/systhread.h index eb9cde78b61..52735449a5e 100644 --- a/src/systhread.h +++ b/src/systhread.h | |||
| @@ -36,8 +36,42 @@ typedef pthread_t sys_thread_t; | |||
| 36 | 36 | ||
| 37 | #else /* HAVE_PTHREAD */ | 37 | #else /* HAVE_PTHREAD */ |
| 38 | 38 | ||
| 39 | #ifdef WINDOWSNT | ||
| 40 | |||
| 41 | /* This header is indirectly included in every source file. We don't | ||
| 42 | want to include windows.h in every source file, so we repeat | ||
| 43 | declarations of the few necessary data types here (under different | ||
| 44 | names, to avoid conflicts with files that do include | ||
| 45 | windows.h). */ | ||
| 46 | |||
| 47 | typedef struct { | ||
| 48 | struct _CRITICAL_SECTION_DEBUG *DebugInfo; | ||
| 49 | long LockCount; | ||
| 50 | long RecursionCount; | ||
| 51 | void *OwningThread; | ||
| 52 | void *LockSemaphore; | ||
| 53 | unsigned long SpinCount; | ||
| 54 | } w32thread_critsect; | ||
| 55 | |||
| 56 | enum { CONDV_SIGNAL = 0, CONDV_BROADCAST = 1, CONDV_MAX = 2 }; | ||
| 57 | |||
| 58 | typedef struct { | ||
| 59 | unsigned waiters_count; | ||
| 60 | w32thread_critsect waiters_count_lock; | ||
| 61 | void *events[CONDV_MAX]; | ||
| 62 | } w32thread_cond_t; | ||
| 63 | |||
| 64 | typedef w32thread_critsect sys_mutex_t; | ||
| 65 | |||
| 66 | typedef w32thread_cond_t sys_cond_t; | ||
| 67 | |||
| 68 | typedef unsigned long sys_thread_t; | ||
| 69 | |||
| 70 | #else /* !WINDOWSNT */ | ||
| 71 | |||
| 39 | #error port me | 72 | #error port me |
| 40 | 73 | ||
| 74 | #endif /* WINDOWSNT */ | ||
| 41 | #endif /* HAVE_PTHREAD */ | 75 | #endif /* HAVE_PTHREAD */ |
| 42 | 76 | ||
| 43 | #else /* THREADS_ENABLED */ | 77 | #else /* THREADS_ENABLED */ |