Handle non-hardware X events correctly with native USER
[wine/multimedia.git] / scheduler / critsection.c
blob4cd478a24e3eab72e46b3aa0c2bf6f47ee730d52
1 /*
2 * Win32 critical sections
4 * Copyright 1998 Alexandre Julliard
5 */
7 /* Note: critical sections are not implemented exactly the same way
8 * than under NT (LockSemaphore should be a real semaphore handle).
9 * But since they are even more different under Win95, it probably
10 * doesn't matter...
13 #include <assert.h>
14 #include <errno.h>
15 #include <stdio.h>
16 #include <sys/types.h>
17 #include <sys/sem.h>
18 #include "debug.h"
19 #include "windows.h"
20 #include "winerror.h"
21 #include "winbase.h"
22 #include "heap.h"
23 #include "k32obj.h"
24 #include "debug.h"
25 #include "thread.h"
27 typedef struct
29 K32OBJ header;
30 THREAD_QUEUE wait_queue;
31 BOOL32 signaled;
32 } CRIT_SECTION;
34 /* On some systems this is supposed to be defined in the program */
35 #ifndef HAVE_UNION_SEMUN
36 union semun {
37 int val;
38 struct semid_ds *buf;
39 ushort *array;
41 #endif
43 static BOOL32 CRIT_SECTION_Signaled( K32OBJ *obj, DWORD thread_id );
44 static BOOL32 CRIT_SECTION_Satisfied( K32OBJ *obj, DWORD thread_id );
45 static void CRIT_SECTION_AddWait( K32OBJ *obj, DWORD thread_id );
46 static void CRIT_SECTION_RemoveWait( K32OBJ *obj, DWORD thread_id );
47 static void CRIT_SECTION_Destroy( K32OBJ *obj );
49 const K32OBJ_OPS CRITICAL_SECTION_Ops =
51 CRIT_SECTION_Signaled, /* signaled */
52 CRIT_SECTION_Satisfied, /* satisfied */
53 CRIT_SECTION_AddWait, /* add_wait */
54 CRIT_SECTION_RemoveWait, /* remove_wait */
55 NULL, /* read */
56 NULL, /* write */
57 CRIT_SECTION_Destroy /* destroy */
60 /***********************************************************************
61 * InitializeCriticalSection (KERNEL32.472) (NTDLL.406)
63 void WINAPI InitializeCriticalSection( CRITICAL_SECTION *crit )
65 CRIT_SECTION *obj;
67 crit->LockCount = -1;
68 crit->RecursionCount = 0;
69 crit->OwningThread = 0;
70 crit->LockSemaphore = 0;
71 if (SystemHeap)
73 if (!(obj = (CRIT_SECTION *)HeapAlloc( SystemHeap, 0, sizeof(*obj) )))
74 return; /* No way to return an error... */
75 obj->header.type = K32OBJ_CRITICAL_SECTION;
76 obj->header.refcount = 1;
77 obj->wait_queue = NULL;
78 obj->signaled = FALSE;
79 crit->LockSemaphore = (HANDLE32)obj;
80 crit->Reserved = (DWORD)-1;
82 else
84 union semun val;
85 crit->Reserved = (DWORD)semget( IPC_PRIVATE, 1, IPC_CREAT | 0777 );
86 if (crit->Reserved == (DWORD)-1)
88 perror( "semget" );
89 return;
91 val.val = 0;
92 semctl( (int)crit->Reserved, 0, SETVAL, val );
97 /***********************************************************************
98 * DeleteCriticalSection (KERNEL32.185) (NTDLL.327)
100 void WINAPI DeleteCriticalSection( CRITICAL_SECTION *crit )
102 CRIT_SECTION *obj = (CRIT_SECTION *)crit->LockSemaphore;
104 if (obj)
106 if (crit->RecursionCount) /* Should not happen */
107 MSG("Deleting owned critical section (%p)\n", crit );
108 crit->LockCount = -1;
109 crit->RecursionCount = 0;
110 crit->OwningThread = 0;
111 crit->LockSemaphore = 0;
112 K32OBJ_DecCount( &obj->header );
114 else if (crit->Reserved != (DWORD)-1)
116 semctl( (int)crit->Reserved, 0, IPC_RMID, (union semun)0 );
121 /***********************************************************************
122 * EnterCriticalSection (KERNEL32.195) (NTDLL.344)
124 void WINAPI EnterCriticalSection( CRITICAL_SECTION *crit )
126 if ( (crit->Reserved==-1) && !(crit->LockSemaphore) &&
127 (crit!=HEAP_SystemLock)
129 FIXME(win32,"entering uninitialized section(%p)?\n",crit);
130 InitializeCriticalSection(crit);
132 if (InterlockedIncrement( &crit->LockCount ))
134 if (crit->OwningThread == GetCurrentThreadId())
136 crit->RecursionCount++;
137 return;
139 /* Now wait for it */
140 if (crit->LockSemaphore)
142 WAIT_STRUCT *wait = &THREAD_Current()->wait_struct;
143 SYSTEM_LOCK();
144 wait->count = 1;
145 wait->signaled = WAIT_FAILED;
146 wait->wait_all = FALSE;
147 wait->objs[0] = (K32OBJ *)crit->LockSemaphore;
148 K32OBJ_IncCount( wait->objs[0] );
149 SYNC_WaitForCondition( wait, INFINITE32 );
150 K32OBJ_DecCount( wait->objs[0] );
151 SYSTEM_UNLOCK();
153 else if (crit->Reserved != (DWORD)-1)
155 int ret;
156 struct sembuf sop;
157 sop.sem_num = 0;
158 sop.sem_op = -1;
159 sop.sem_flg = 0/*SEM_UNDO*/;
162 ret = semop( (int)crit->Reserved, &sop, 1 );
163 } while ((ret == -1) && (errno == EINTR));
165 else
167 MSG( "Uninitialized critical section (%p)\n", crit );
168 return;
171 crit->OwningThread = GetCurrentThreadId();
172 crit->RecursionCount = 1;
176 /***********************************************************************
177 * TryEnterCriticalSection (KERNEL32.898) (NTDLL.969)
179 BOOL32 WINAPI TryEnterCriticalSection( CRITICAL_SECTION *crit )
181 if (InterlockedIncrement( &crit->LockCount ))
183 if (crit->OwningThread == GetCurrentThreadId())
185 crit->RecursionCount++;
186 return TRUE;
188 /* FIXME: this doesn't work */
189 InterlockedDecrement( &crit->LockCount );
190 return FALSE;
192 crit->OwningThread = GetCurrentThreadId();
193 crit->RecursionCount = 1;
194 return TRUE;
198 /***********************************************************************
199 * LeaveCriticalSection (KERNEL32.494) (NTDLL.426)
201 void WINAPI LeaveCriticalSection( CRITICAL_SECTION *crit )
203 if (crit->OwningThread != GetCurrentThreadId()) return;
205 if (--crit->RecursionCount)
207 InterlockedDecrement( &crit->LockCount );
208 return;
210 crit->OwningThread = 0;
211 if (InterlockedDecrement( &crit->LockCount ) >= 0)
213 /* Someone is waiting */
214 if (crit->LockSemaphore)
216 CRIT_SECTION *obj = (CRIT_SECTION *)crit->LockSemaphore;
217 SYSTEM_LOCK();
218 obj->signaled = TRUE;
219 SYNC_WakeUp( &obj->wait_queue, 1 );
220 SYSTEM_UNLOCK();
222 else if (crit->Reserved != (DWORD)-1)
224 struct sembuf sop;
225 sop.sem_num = 0;
226 sop.sem_op = 1;
227 sop.sem_flg = 0/*SEM_UNDO*/;
228 semop( (int)crit->Reserved, &sop, 1 );
234 /***********************************************************************
235 * MakeCriticalSectionGlobal (KERNEL32.515)
237 void WINAPI MakeCriticalSectionGlobal( CRITICAL_SECTION *crit )
239 /* Nothing to do: a critical section is always global */
243 /***********************************************************************
244 * ReinitializeCriticalSection (KERNEL32.581)
246 void WINAPI ReinitializeCriticalSection( CRITICAL_SECTION *crit )
248 DeleteCriticalSection( crit );
249 InitializeCriticalSection( crit );
253 /***********************************************************************
254 * CRIT_SECTION_Signaled
256 static BOOL32 CRIT_SECTION_Signaled( K32OBJ *obj, DWORD thread_id )
258 CRIT_SECTION *crit = (CRIT_SECTION *)obj;
259 assert( obj->type == K32OBJ_CRITICAL_SECTION );
260 return crit->signaled;
264 /***********************************************************************
265 * CRIT_SECTION_Satisfied
267 * Wait on this object has been satisfied.
269 static BOOL32 CRIT_SECTION_Satisfied( K32OBJ *obj, DWORD thread_id )
271 CRIT_SECTION *crit = (CRIT_SECTION *)obj;
272 assert( obj->type == K32OBJ_CRITICAL_SECTION );
273 /* Only one thread is allowed to wake up */
274 crit->signaled = FALSE;
275 return FALSE; /* Not abandoned */
279 /***********************************************************************
280 * CRIT_SECTION_AddWait
282 * Add thread to object wait queue.
284 static void CRIT_SECTION_AddWait( K32OBJ *obj, DWORD thread_id )
286 CRIT_SECTION *crit = (CRIT_SECTION *)obj;
287 assert( obj->type == K32OBJ_CRITICAL_SECTION );
288 THREAD_AddQueue( &crit->wait_queue, THREAD_ID_TO_THDB(thread_id) );
292 /***********************************************************************
293 * CRIT_SECTION_RemoveWait
295 * Remove current thread from object wait queue.
297 static void CRIT_SECTION_RemoveWait( K32OBJ *obj, DWORD thread_id )
299 CRIT_SECTION *crit = (CRIT_SECTION *)obj;
300 assert( obj->type == K32OBJ_CRITICAL_SECTION );
301 THREAD_RemoveQueue( &crit->wait_queue, THREAD_ID_TO_THDB(thread_id) );
305 /***********************************************************************
306 * CRIT_SECTION_Destroy
308 static void CRIT_SECTION_Destroy( K32OBJ *obj )
310 CRIT_SECTION *crit = (CRIT_SECTION *)obj;
311 assert( obj->type == K32OBJ_CRITICAL_SECTION );
312 /* There cannot be any thread on the list since the ref count is 0 */
313 assert( crit->wait_queue == NULL );
314 obj->type = K32OBJ_UNKNOWN;
315 HeapFree( SystemHeap, 0, crit );