Release 980503
[wine/multimedia.git] / scheduler / critsection.c
blob9c92351accaeab73e63f788ad721f34b49235703
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 "windows.h"
19 #include "winerror.h"
20 #include "winbase.h"
21 #include "heap.h"
22 #include "k32obj.h"
23 #include "thread.h"
25 typedef struct
27 K32OBJ header;
28 THREAD_QUEUE wait_queue;
29 BOOL32 signaled;
30 } CRIT_SECTION;
32 /* On some systems this is supposed to be defined in the program */
33 #ifndef HAVE_UNION_SEMUN
34 union semun {
35 int val;
36 struct semid_ds *buf;
37 ushort *array;
39 #endif
41 static BOOL32 CRIT_SECTION_Signaled( K32OBJ *obj, DWORD thread_id );
42 static BOOL32 CRIT_SECTION_Satisfied( K32OBJ *obj, DWORD thread_id );
43 static void CRIT_SECTION_AddWait( K32OBJ *obj, DWORD thread_id );
44 static void CRIT_SECTION_RemoveWait( K32OBJ *obj, DWORD thread_id );
45 static void CRIT_SECTION_Destroy( K32OBJ *obj );
47 const K32OBJ_OPS CRITICAL_SECTION_Ops =
49 CRIT_SECTION_Signaled, /* signaled */
50 CRIT_SECTION_Satisfied, /* satisfied */
51 CRIT_SECTION_AddWait, /* add_wait */
52 CRIT_SECTION_RemoveWait, /* remove_wait */
53 NULL, /* read */
54 NULL, /* write */
55 CRIT_SECTION_Destroy /* destroy */
58 /***********************************************************************
59 * InitializeCriticalSection (KERNEL32.472) (NTDLL.406)
61 void WINAPI InitializeCriticalSection( CRITICAL_SECTION *crit )
63 CRIT_SECTION *obj;
65 crit->LockCount = -1;
66 crit->RecursionCount = 0;
67 crit->OwningThread = 0;
68 crit->LockSemaphore = 0;
69 if (SystemHeap)
71 if (!(obj = (CRIT_SECTION *)HeapAlloc( SystemHeap, 0, sizeof(*obj) )))
72 return; /* No way to return an error... */
73 obj->header.type = K32OBJ_CRITICAL_SECTION;
74 obj->header.refcount = 1;
75 obj->wait_queue = NULL;
76 obj->signaled = FALSE;
77 crit->LockSemaphore = (HANDLE32)obj;
78 crit->Reserved = (DWORD)-1;
80 else
82 union semun val;
83 crit->Reserved = (DWORD)semget( IPC_PRIVATE, 1, IPC_CREAT | 0777 );
84 if (crit->Reserved == (DWORD)-1)
86 perror( "semget" );
87 return;
89 val.val = 0;
90 semctl( (int)crit->Reserved, 0, SETVAL, val );
95 /***********************************************************************
96 * DeleteCriticalSection (KERNEL32.185) (NTDLL.327)
98 void WINAPI DeleteCriticalSection( CRITICAL_SECTION *crit )
100 CRIT_SECTION *obj = (CRIT_SECTION *)crit->LockSemaphore;
102 if (obj)
104 if (crit->RecursionCount) /* Should not happen */
105 fprintf( stderr, "Deleting owned critical section (%p)\n", crit );
106 crit->LockCount = -1;
107 crit->RecursionCount = 0;
108 crit->OwningThread = 0;
109 crit->LockSemaphore = 0;
110 K32OBJ_DecCount( &obj->header );
112 else if (crit->Reserved != (DWORD)-1)
114 semctl( (int)crit->Reserved, 0, IPC_RMID, (union semun)0 );
119 /***********************************************************************
120 * EnterCriticalSection (KERNEL32.195) (NTDLL.344)
122 void WINAPI EnterCriticalSection( CRITICAL_SECTION *crit )
124 if (InterlockedIncrement( &crit->LockCount ))
126 if (crit->OwningThread == GetCurrentThreadId())
128 crit->RecursionCount++;
129 return;
131 /* Now wait for it */
132 if (crit->LockSemaphore)
134 WAIT_STRUCT *wait = &THREAD_Current()->wait_struct;
135 SYSTEM_LOCK();
136 wait->count = 1;
137 wait->signaled = WAIT_FAILED;
138 wait->wait_all = FALSE;
139 wait->objs[0] = (K32OBJ *)crit->LockSemaphore;
140 K32OBJ_IncCount( wait->objs[0] );
141 SYNC_WaitForCondition( wait, INFINITE32 );
142 K32OBJ_DecCount( wait->objs[0] );
143 SYSTEM_UNLOCK();
145 else if (crit->Reserved != (DWORD)-1)
147 int ret;
148 struct sembuf sop;
149 sop.sem_num = 0;
150 sop.sem_op = -1;
151 sop.sem_flg = SEM_UNDO;
154 ret = semop( (int)crit->Reserved, &sop, 1 );
155 } while ((ret == -1) && (errno == EINTR));
157 else
159 fprintf( stderr, "Uninitialized critical section (%p)\n", crit );
160 return;
163 crit->OwningThread = GetCurrentThreadId();
164 crit->RecursionCount = 1;
168 /***********************************************************************
169 * TryEnterCriticalSection (KERNEL32.898) (NTDLL.969)
171 BOOL32 WINAPI TryEnterCriticalSection( CRITICAL_SECTION *crit )
173 if (InterlockedIncrement( &crit->LockCount ))
175 if (crit->OwningThread == GetCurrentThreadId())
177 crit->RecursionCount++;
178 return TRUE;
180 /* FIXME: this doesn't work */
181 InterlockedDecrement( &crit->LockCount );
182 return FALSE;
184 crit->OwningThread = GetCurrentThreadId();
185 crit->RecursionCount = 1;
186 return TRUE;
190 /***********************************************************************
191 * LeaveCriticalSection (KERNEL32.494) (NTDLL.426)
193 void WINAPI LeaveCriticalSection( CRITICAL_SECTION *crit )
195 if (crit->OwningThread != GetCurrentThreadId()) return;
197 if (--crit->RecursionCount)
199 InterlockedDecrement( &crit->LockCount );
200 return;
202 crit->OwningThread = 0;
203 if (InterlockedDecrement( &crit->LockCount ) >= 0)
205 /* Someone is waiting */
206 if (crit->LockSemaphore)
208 CRIT_SECTION *obj = (CRIT_SECTION *)crit->LockSemaphore;
209 SYSTEM_LOCK();
210 obj->signaled = TRUE;
211 SYNC_WakeUp( &obj->wait_queue, 1 );
212 SYSTEM_UNLOCK();
214 else if (crit->Reserved != (DWORD)-1)
216 struct sembuf sop;
217 sop.sem_num = 0;
218 sop.sem_op = 1;
219 sop.sem_flg = SEM_UNDO;
220 semop( (int)crit->Reserved, &sop, 1 );
226 /***********************************************************************
227 * MakeCriticalSectionGlobal (KERNEL32.515)
229 void WINAPI MakeCriticalSectionGlobal( CRITICAL_SECTION *crit )
231 /* Nothing to do: a critical section is always global */
235 /***********************************************************************
236 * ReinitializeCriticalSection (KERNEL32.581)
238 void WINAPI ReinitializeCriticalSection( CRITICAL_SECTION *crit )
240 DeleteCriticalSection( crit );
241 InitializeCriticalSection( crit );
245 /***********************************************************************
246 * CRIT_SECTION_Signaled
248 static BOOL32 CRIT_SECTION_Signaled( K32OBJ *obj, DWORD thread_id )
250 CRIT_SECTION *crit = (CRIT_SECTION *)obj;
251 assert( obj->type == K32OBJ_CRITICAL_SECTION );
252 return crit->signaled;
256 /***********************************************************************
257 * CRIT_SECTION_Satisfied
259 * Wait on this object has been satisfied.
261 static BOOL32 CRIT_SECTION_Satisfied( K32OBJ *obj, DWORD thread_id )
263 CRIT_SECTION *crit = (CRIT_SECTION *)obj;
264 assert( obj->type == K32OBJ_CRITICAL_SECTION );
265 /* Only one thread is allowed to wake up */
266 crit->signaled = FALSE;
267 return FALSE; /* Not abandoned */
271 /***********************************************************************
272 * CRIT_SECTION_AddWait
274 * Add thread to object wait queue.
276 static void CRIT_SECTION_AddWait( K32OBJ *obj, DWORD thread_id )
278 CRIT_SECTION *crit = (CRIT_SECTION *)obj;
279 assert( obj->type == K32OBJ_CRITICAL_SECTION );
280 THREAD_AddQueue( &crit->wait_queue, THREAD_ID_TO_THDB(thread_id) );
284 /***********************************************************************
285 * CRIT_SECTION_RemoveWait
287 * Remove current thread from object wait queue.
289 static void CRIT_SECTION_RemoveWait( K32OBJ *obj, DWORD thread_id )
291 CRIT_SECTION *crit = (CRIT_SECTION *)obj;
292 assert( obj->type == K32OBJ_CRITICAL_SECTION );
293 THREAD_RemoveQueue( &crit->wait_queue, THREAD_ID_TO_THDB(thread_id) );
297 /***********************************************************************
298 * CRIT_SECTION_Destroy
300 static void CRIT_SECTION_Destroy( K32OBJ *obj )
302 CRIT_SECTION *crit = (CRIT_SECTION *)obj;
303 assert( obj->type == K32OBJ_CRITICAL_SECTION );
304 /* There cannot be any thread on the list since the ref count is 0 */
305 assert( crit->wait_queue == NULL );
306 obj->type = K32OBJ_UNKNOWN;
307 HeapFree( SystemHeap, 0, crit );