Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(4888)

Side by Side Diff: Python/thread_nt.h

Issue 6132: Implement the GIL with critical sections in Windows
Patch Set: Created 2 years, 7 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 1
2 /* This code implemented by Dag.Gruneau@elsa.preseco.comm.se */ 2 /* This code implemented by Dag.Gruneau@elsa.preseco.comm.se */
3 /* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch@iso.ru */ 3 /* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch@iso.ru */
4 /* Eliminated some memory leaks, gsw@agere.com */ 4 /* Eliminated some memory leaks, gsw@agere.com */
5 /* EXPERIMENTAL critical section & semaphore code by Phillip Sitbon, phillip@sit bon.net */
5 6
6 #include <windows.h> 7 #include <windows.h>
7 #include <limits.h> 8 #include <limits.h>
8 #ifdef HAVE_PROCESS_H 9 #ifdef HAVE_PROCESS_H
9 #include <process.h> 10 #include <process.h>
10 #endif 11 #endif
11 12
12 typedef struct NRMUTEX { 13 #define WITH_CRITICAL_SECTION_LOCKING_BREAKING_THREAD_LOCKS
14 /* #define WITH_SEMAPHORE_LOCKING */
15
16 #ifdef WITH_CRITICAL_SECTION_LOCKING_BREAKING_THREAD_LOCKS
17 /* Implement locking as a pseudo-recursive critical section */
18
19 typedef CRITICAL_SECTION NTMUTEX;
20 typedef LPCRITICAL_SECTION PNTMUTEX;
21
22 BOOL
23 InitializeNtMutex(PNTMUTEX mutex)
24 {
25 » InitializeCriticalSection(mutex);
26 » /* Spin mutex would be: InitializeCriticalSectionAndSpinCount(mutex, Spi nCount#); */
27 » return TRUE; /* failure is a segfault for this function */
28 }
29
30 VOID
31 DeleteNtMutex(PNTMUTEX mutex)
32 {
33 » /* ideally would set the pointer to zero here, might be a good reason to
34 » encapsulate CRITICAL_SECTION */
35 » DeleteCriticalSection(mutex);
36 }
37
38
39 DWORD
40 EnterNtMutex(PNTMUTEX mutex, BOOL wait)
41 {
42 » const DWORD ThisThread = GetCurrentThreadId();
43
44 » /*
45 » We can only effectively disallow recursion when the
46 » caller doesn't want to wait. There are two other options
47 » in the presence of recursion:
48 » (1) allow recursion no matter what, or
49 » (2) force a deadlock (i.e. acquire an unused semaphore).
50 »
51 » Option 1 breaks code that does sanity checks assuming that
52 » we can't lock it if we own it already without blocking.
53 » Option 2 preserves semantics, but is not desirable.
54
55 » The solution here disallows recursion when wait == 0, and
56 » silently allows it otherwise.
57 » */
58
59 » if ( !wait )
60 » {
61 » » /* warning: using NT internals. this value is always the thread id,
62 » » but we are bypassing the opaqueness of CRITICAL_SECTION */
63 » » if ( ((DWORD)(mutex->OwningThread) == ThisThread) ||
64 » » (TryEnterCriticalSection(mutex) == FALSE) ) /* try to acqui re if not owner */
65 » » » return WAIT_TIMEOUT; /* recursion or unavailable */
66 » }
67 » else /* wait always passed as INFINITE anyway, so ignore it */
68 » » EnterCriticalSection(mutex);
69
70 » return WAIT_OBJECT_0;
71 }
72
73 BOOL
74 LeaveNtMutex(PNTMUTEX mutex)
75 {
76 » /* It might be important here to fail if a thread not owning this object
77 » tries to release it. It will work with events AFAIK, but not critical
78 » sections.
79 » */
80 » LeaveCriticalSection(mutex);
81 » return TRUE;
82 }
83
84 #elif defined(WITH_SEMAPHORE_LOCKING)
85 /* Implement locking as a semaphore */
86
87 typedef HANDLE NTMUTEX;
88 typedef LPHANDLE PNTMUTEX;
89
90 BOOL
91 InitializeNtMutex(PNTMUTEX mutex)
92 {
93 » *mutex = CreateSemaphore(NULL, 1, LONG_MAX, NULL);
94 » return *mutex != NULL;
95 }
96
97 VOID
98 DeleteNtMutex(PNTMUTEX mutex)
99 {
100 » CloseHandle(*mutex);
101 }
102
103
104 DWORD
105 EnterNtMutex(PNTMUTEX mutex, DWORD wait) /* second parameter type changed to DWO RD */
106 {
107 » return WaitForSingleObject(*mutex, wait);
108 }
109
110 BOOL
111 LeaveNtMutex(PNTMUTEX mutex)
112 {
113 » return ReleaseSemaphore(*mutex, 1, NULL);
114 }
115
116 #else /* Use an event-based non-recursive mutex */
117
118 typedef struct NTMUTEX {
13 LONG owned ; 119 LONG owned ;
14 DWORD thread_id ; 120 DWORD thread_id ;
15 HANDLE hevent ; 121 HANDLE hevent ;
16 } NRMUTEX, *PNRMUTEX ; 122 } NTMUTEX, *PNTMUTEX ;
17 123
18 124
19 BOOL 125 BOOL
20 InitializeNonRecursiveMutex(PNRMUTEX mutex) 126 InitializeNtMutex(PNTMUTEX mutex)
21 { 127 {
22 mutex->owned = -1 ; /* No threads have entered NonRecursiveMutex */ 128 mutex->owned = -1 ; /* No threads have entered NonRecursiveMutex */
23 mutex->thread_id = 0 ; 129 mutex->thread_id = 0 ;
24 mutex->hevent = CreateEvent(NULL, FALSE, FALSE, NULL) ; 130 mutex->hevent = CreateEvent(NULL, FALSE, FALSE, NULL) ;
25 return mutex->hevent != NULL ; /* TRUE if the mutex is created */ 131 return mutex->hevent != NULL ; /* TRUE if the mutex is created */
26 } 132 }
27 133
28 VOID 134 VOID
29 DeleteNonRecursiveMutex(PNRMUTEX mutex) 135 DeleteNtMutex(PNTMUTEX mutex)
30 { 136 {
31 /* No in-use check */ 137 /* No in-use check */
32 CloseHandle(mutex->hevent) ; 138 CloseHandle(mutex->hevent) ;
33 mutex->hevent = NULL ; /* Just in case */ 139 mutex->hevent = NULL ; /* Just in case */
34 } 140 }
35 141
36 DWORD 142 DWORD
37 EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait) 143 EnterNtMutex(PNTMUTEX mutex, BOOL wait)
38 { 144 {
39 /* Assume that the thread waits successfully */ 145 /* Assume that the thread waits successfully */
40 DWORD ret ; 146 DWORD ret ;
41 147
42 /* InterlockedIncrement(&mutex->owned) == 0 means that no thread current ly owns the mutex */ 148 /* InterlockedIncrement(&mutex->owned) == 0 means that no thread current ly owns the mutex */
43 if (!wait) 149 if (!wait)
44 { 150 {
45 if (InterlockedCompareExchange(&mutex->owned, 0, -1) != -1) 151 if (InterlockedCompareExchange(&mutex->owned, 0, -1) != -1)
46 return WAIT_TIMEOUT ; 152 return WAIT_TIMEOUT ;
47 ret = WAIT_OBJECT_0 ; 153 ret = WAIT_OBJECT_0 ;
48 } 154 }
49 else 155 else
50 ret = InterlockedIncrement(&mutex->owned) ? 156 ret = InterlockedIncrement(&mutex->owned) ?
51 /* Some thread owns the mutex, let's wait... */ 157 /* Some thread owns the mutex, let's wait... */
52 WaitForSingleObject(mutex->hevent, INFINITE) : WAIT_OBJE CT_0 ; 158 WaitForSingleObject(mutex->hevent, INFINITE) : WAIT_OBJE CT_0 ;
53 159
54 mutex->thread_id = GetCurrentThreadId() ; /* We own it */ 160 mutex->thread_id = GetCurrentThreadId() ; /* We own it */
55 return ret ; 161 return ret ;
56 } 162 }
57 163
58 BOOL 164 BOOL
59 LeaveNonRecursiveMutex(PNRMUTEX mutex) 165 LeaveNtMutex(PNTMUTEX mutex)
60 { 166 {
61 /* We don't own the mutex */ 167 /* We don't own the mutex */
62 mutex->thread_id = 0 ; 168 mutex->thread_id = 0 ;
63 return 169 return
64 InterlockedDecrement(&mutex->owned) < 0 || 170 InterlockedDecrement(&mutex->owned) < 0 ||
65 SetEvent(mutex->hevent) ; /* Other threads are waiting, wake one on them up */ 171 SetEvent(mutex->hevent) ; /* Other threads are waiting, wake one on them up */
66 } 172 }
67 173
68 PNRMUTEX 174 #endif /* WITH_CRITICAL_SECTION_GIL */
69 AllocNonRecursiveMutex(void) 175
176
177 PNTMUTEX
178 AllocNtMutex(void)
70 { 179 {
71 » PNRMUTEX mutex = (PNRMUTEX)malloc(sizeof(NRMUTEX)) ; 180 » PNTMUTEX mutex = (PNTMUTEX)malloc(sizeof(NTMUTEX)) ;
72 » if (mutex && !InitializeNonRecursiveMutex(mutex)) 181 » if (mutex && !InitializeNtMutex(mutex))
73 { 182 {
74 free(mutex) ; 183 free(mutex) ;
75 mutex = NULL ; 184 mutex = NULL ;
76 } 185 }
77 return mutex ; 186 return mutex ;
78 } 187 }
79 188
80 void 189 void
81 FreeNonRecursiveMutex(PNRMUTEX mutex) 190 FreeNtMutex(PNTMUTEX mutex)
82 { 191 {
83 if (mutex) 192 if (mutex)
84 { 193 {
85 » » DeleteNonRecursiveMutex(mutex) ; 194 » » DeleteNtMutex(mutex) ;
86 free(mutex) ; 195 free(mutex) ;
87 } 196 }
88 } 197 }
89 198
90 long PyThread_get_thread_ident(void); 199 long PyThread_get_thread_ident(void);
91 200
92 /* 201 /*
93 * Initialization of the C package, should not be needed. 202 * Initialization of the C package, should not be needed.
94 */ 203 */
95 static void 204 static void
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 #ifndef NO_EXIT_PROG 315 #ifndef NO_EXIT_PROG
207 void 316 void
208 PyThread_exit_prog(int status) 317 PyThread_exit_prog(int status)
209 { 318 {
210 dprintf(("PyThread_exit_prog(%d) called\n", status)); 319 dprintf(("PyThread_exit_prog(%d) called\n", status));
211 if (!initialized) 320 if (!initialized)
212 exit(status); 321 exit(status);
213 } 322 }
214 #endif /* NO_EXIT_PROG */ 323 #endif /* NO_EXIT_PROG */
215 324
216 /*
217 * Lock support. It has too be implemented as semaphores.
218 * I [Dag] tried to implement it with mutex but I could find a way to
219 * tell whether a thread already own the lock or not.
220 */
221 PyThread_type_lock 325 PyThread_type_lock
222 PyThread_allocate_lock(void) 326 PyThread_allocate_lock(void)
223 { 327 {
224 » PNRMUTEX aLock; 328 » PNTMUTEX aLock;
225 329
226 dprintf(("PyThread_allocate_lock called\n")); 330 dprintf(("PyThread_allocate_lock called\n"));
227 if (!initialized) 331 if (!initialized)
228 PyThread_init_thread(); 332 PyThread_init_thread();
229 333
230 » aLock = AllocNonRecursiveMutex() ; 334 » aLock = AllocNtMutex() ;
231 335
232 dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_id ent(), aLock)); 336 dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_id ent(), aLock));
233 337
234 return (PyThread_type_lock) aLock; 338 return (PyThread_type_lock) aLock;
235 } 339 }
236 340
237 void 341 void
238 PyThread_free_lock(PyThread_type_lock aLock) 342 PyThread_free_lock(PyThread_type_lock aLock)
239 { 343 {
240 dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ide nt(),aLock)); 344 dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ide nt(),aLock));
241 345
242 » FreeNonRecursiveMutex(aLock) ; 346 » FreeNtMutex(aLock) ;
243 } 347 }
244 348
245 /* 349 /*
246 * Return 1 on success if the lock was acquired 350 * Return 1 on success if the lock was acquired
247 * 351 *
248 * and 0 if the lock was not acquired. This means a 0 is returned 352 * and 0 if the lock was not acquired. This means a 0 is returned
249 * if the lock has already been acquired by this thread! 353 * if the lock has already been acquired by this thread!
250 */ 354 */
251 int 355 int
252 PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag) 356 PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag)
253 { 357 {
254 int success ; 358 int success ;
255 359
256 dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thr ead_ident(),aLock, waitflag)); 360 dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thr ead_ident(),aLock, waitflag));
257 361
258 » success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag ? INFINITE : 0)) == WAIT_OBJECT_0 ; 362 » success = aLock && EnterNtMutex((PNTMUTEX) aLock, (waitflag ? INFINITE : 0)) == WAIT_OBJECT_0 ;
259 363
260 dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thre ad_ident(),aLock, waitflag, success)); 364 dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thre ad_ident(),aLock, waitflag, success));
261 365
262 return success; 366 return success;
263 } 367 }
264 368
265 void 369 void
266 PyThread_release_lock(PyThread_type_lock aLock) 370 PyThread_release_lock(PyThread_type_lock aLock)
267 { 371 {
268 dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ ident(),aLock)); 372 dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ ident(),aLock));
269 373
270 » if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock))) 374 » if (!(aLock && LeaveNtMutex((PNTMUTEX) aLock)))
271 dprintf(("%ld: Could not PyThread_release_lock(%p) error: %ld\n" , PyThread_get_thread_ident(), aLock, GetLastError())); 375 dprintf(("%ld: Could not PyThread_release_lock(%p) error: %ld\n" , PyThread_get_thread_ident(), aLock, GetLastError()));
272 } 376 }
273 377
274 /* minimum/maximum thread stack sizes supported */ 378 /* minimum/maximum thread stack sizes supported */
275 #define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */ 379 #define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */
276 #define THREAD_MAX_STACKSIZE 0x10000000 /* 256MB */ 380 #define THREAD_MAX_STACKSIZE 0x10000000 /* 256MB */
277 381
278 /* set the thread stack size. 382 /* set the thread stack size.
279 * Return 0 if size is valid, -1 otherwise. 383 * Return 0 if size is valid, -1 otherwise.
280 */ 384 */
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
360 } 464 }
361 465
362 /* reinitialization of TLS is not necessary after fork when using 466 /* reinitialization of TLS is not necessary after fork when using
363 * the native TLS functions. And forking isn't supported on Windows either. 467 * the native TLS functions. And forking isn't supported on Windows either.
364 */ 468 */
365 void 469 void
366 PyThread_ReInitTLS(void) 470 PyThread_ReInitTLS(void)
367 {} 471 {}
368 472
369 #endif 473 #endif
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld cbc36f91f3f7