Release 980201
[wine/multimedia.git] / scheduler / critsection.c
blobc97c295a3b975a387b19046e2475df25e5a002ff
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 CRIT_SECTION_Destroy /* destroy */
56 /***********************************************************************
57 * InitializeCriticalSection (KERNEL32.472) (NTDLL.406)
59 void WINAPI InitializeCriticalSection( CRITICAL_SECTION *crit )
61 CRIT_SECTION *obj;
63 crit->LockCount = -1;
64 crit->RecursionCount = 0;
65 crit->OwningThread = 0;
66 crit->LockSemaphore = 0;
67 if (SystemHeap)
69 if (!(obj = (CRIT_SECTION *)HeapAlloc( SystemHeap, 0, sizeof(*obj) )))
70 return; /* No way to return an error... */
71 obj->header.type = K32OBJ_CRITICAL_SECTION;
72 obj->header.refcount = 1;
73 obj->wait_queue = NULL;
74 obj->signaled = FALSE;
75 crit->LockSemaphore = (HANDLE32)obj;
76 crit->Reserved = (DWORD)-1;
78 else
80 union semun val;
81 crit->Reserved = (DWORD)semget( IPC_PRIVATE, 1, IPC_CREAT | 0777 );
82 if (crit->Reserved == (DWORD)-1)
84 perror( "semget" );
85 return;
87 val.val = 0;
88 semctl( (int)crit->Reserved, 0, SETVAL, val );
93 /***********************************************************************
94 * DeleteCriticalSection (KERNEL32.185) (NTDLL.327)
96 void WINAPI DeleteCriticalSection( CRITICAL_SECTION *crit )
98 CRIT_SECTION *obj = (CRIT_SECTION *)crit->LockSemaphore;
100 if (obj)
102 if (crit->RecursionCount) /* Should not happen */
103 fprintf( stderr, "Deleting owned critical section (%p)\n", crit );
104 crit->LockCount = -1;
105 crit->RecursionCount = 0;
106 crit->OwningThread = 0;
107 crit->LockSemaphore = 0;
108 K32OBJ_DecCount( &obj->header );
110 else if (crit->Reserved != (DWORD)-1)
112 semctl( (int)crit->Reserved, 0, IPC_RMID, (union semun)0 );
117 /***********************************************************************
118 * EnterCriticalSection (KERNEL32.195) (NTDLL.344)
120 void WINAPI EnterCriticalSection( CRITICAL_SECTION *crit )
122 if (InterlockedIncrement( &crit->LockCount ))
124 if (crit->OwningThread == GetCurrentThreadId())
126 crit->RecursionCount++;
127 return;
129 /* Now wait for it */
130 if (crit->LockSemaphore)
132 WAIT_STRUCT *wait = &THREAD_Current()->wait_struct;
133 SYSTEM_LOCK();
134 wait->count = 1;
135 wait->signaled = WAIT_FAILED;
136 wait->wait_all = FALSE;
137 wait->objs[0] = (K32OBJ *)crit->LockSemaphore;
138 K32OBJ_IncCount( wait->objs[0] );
139 SYNC_WaitForCondition( wait, INFINITE32 );
140 K32OBJ_DecCount( wait->objs[0] );
141 SYSTEM_UNLOCK();
143 else if (crit->Reserved != (DWORD)-1)
145 int ret;
146 struct sembuf sop;
147 sop.sem_num = 0;
148 sop.sem_op = -1;
149 sop.sem_flg = SEM_UNDO;
152 ret = semop( (int)crit->Reserved, &sop, 1 );
153 } while ((ret == -1) && (errno == EINTR));
155 else
157 fprintf( stderr, "Uninitialized critical section (%p)\n", crit );
158 return;
161 crit->OwningThread = GetCurrentThreadId();
162 crit->RecursionCount = 1;
166 /***********************************************************************
167 * TryEnterCriticalSection (KERNEL32.898) (NTDLL.969)
169 BOOL32 WINAPI TryEnterCriticalSection( CRITICAL_SECTION *crit )
171 if (InterlockedIncrement( &crit->LockCount ))
173 if (crit->OwningThread == GetCurrentThreadId())
175 crit->RecursionCount++;
176 return TRUE;
178 /* FIXME: this doesn't work */
179 InterlockedDecrement( &crit->LockCount );
180 return FALSE;
182 crit->OwningThread = GetCurrentThreadId();
183 crit->RecursionCount = 1;
184 return TRUE;
188 /***********************************************************************
189 * LeaveCriticalSection (KERNEL32.494) (NTDLL.426)
191 void WINAPI LeaveCriticalSection( CRITICAL_SECTION *crit )
193 if (crit->OwningThread != GetCurrentThreadId()) return;
195 if (--crit->RecursionCount)
197 InterlockedDecrement( &crit->LockCount );
198 return;
200 crit->OwningThread = 0;
201 if (InterlockedDecrement( &crit->LockCount ) >= 0)
203 /* Someone is waiting */
204 if (crit->LockSemaphore)
206 CRIT_SECTION *obj = (CRIT_SECTION *)crit->LockSemaphore;
207 SYSTEM_LOCK();
208 obj->signaled = TRUE;
209 SYNC_WakeUp( &obj->wait_queue, 1 );
210 SYSTEM_UNLOCK();
212 else if (crit->Reserved != (DWORD)-1)
214 struct sembuf sop;
215 sop.sem_num = 0;
216 sop.sem_op = 1;
217 sop.sem_flg = SEM_UNDO;
218 semop( (int)crit->Reserved, &sop, 1 );
224 /***********************************************************************
225 * MakeCriticalSectionGlobal (KERNEL32.515)
227 void WINAPI MakeCriticalSectionGlobal( CRITICAL_SECTION *crit )
229 /* Nothing to do: a critical section is always global */
233 /***********************************************************************
234 * ReinitializeCriticalSection (KERNEL32.581)
236 void WINAPI ReinitializeCriticalSection( CRITICAL_SECTION *crit )
238 DeleteCriticalSection( crit );
239 InitializeCriticalSection( crit );
243 /***********************************************************************
244 * CRIT_SECTION_Signaled
246 static BOOL32 CRIT_SECTION_Signaled( K32OBJ *obj, DWORD thread_id )
248 CRIT_SECTION *crit = (CRIT_SECTION *)obj;
249 assert( obj->type == K32OBJ_CRITICAL_SECTION );
250 return crit->signaled;
254 /***********************************************************************
255 * CRIT_SECTION_Satisfied
257 * Wait on this object has been satisfied.
259 static BOOL32 CRIT_SECTION_Satisfied( K32OBJ *obj, DWORD thread_id )
261 CRIT_SECTION *crit = (CRIT_SECTION *)obj;
262 assert( obj->type == K32OBJ_CRITICAL_SECTION );
263 /* Only one thread is allowed to wake up */
264 crit->signaled = FALSE;
265 return FALSE; /* Not abandoned */
269 /***********************************************************************
270 * CRIT_SECTION_AddWait
272 * Add thread to object wait queue.
274 static void CRIT_SECTION_AddWait( K32OBJ *obj, DWORD thread_id )
276 CRIT_SECTION *crit = (CRIT_SECTION *)obj;
277 assert( obj->type == K32OBJ_CRITICAL_SECTION );
278 THREAD_AddQueue( &crit->wait_queue, THREAD_ID_TO_THDB(thread_id) );
282 /***********************************************************************
283 * CRIT_SECTION_RemoveWait
285 * Remove current thread from object wait queue.
287 static void CRIT_SECTION_RemoveWait( K32OBJ *obj, DWORD thread_id )
289 CRIT_SECTION *crit = (CRIT_SECTION *)obj;
290 assert( obj->type == K32OBJ_CRITICAL_SECTION );
291 THREAD_RemoveQueue( &crit->wait_queue, THREAD_ID_TO_THDB(thread_id) );
295 /***********************************************************************
296 * CRIT_SECTION_Destroy
298 static void CRIT_SECTION_Destroy( K32OBJ *obj )
300 CRIT_SECTION *crit = (CRIT_SECTION *)obj;
301 assert( obj->type == K32OBJ_CRITICAL_SECTION );
302 /* There cannot be any thread on the list since the ref count is 0 */
303 assert( crit->wait_queue == NULL );
304 obj->type = K32OBJ_UNKNOWN;
305 HeapFree( SystemHeap, 0, crit );