Fixes crash when running without external shell32.dll.
[wine/multimedia.git] / scheduler / semaphore.c
blob7c71a100624baa81ba9a6732042f9e1d3b1777d8
1 /*
2 * Win32 semaphores
4 * Copyright 1998 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include "windows.h"
9 #include "winerror.h"
10 #include "k32obj.h"
11 #include "process.h"
12 #include "thread.h"
13 #include "heap.h"
14 #include "server/request.h"
15 #include "server.h"
17 typedef struct
19 K32OBJ header;
20 THREAD_QUEUE wait_queue;
21 LONG count;
22 LONG max;
23 } SEMAPHORE;
25 static BOOL32 SEMAPHORE_Signaled( K32OBJ *obj, DWORD thread_id );
26 static BOOL32 SEMAPHORE_Satisfied( K32OBJ *obj, DWORD thread_id );
27 static void SEMAPHORE_AddWait( K32OBJ *obj, DWORD thread_id );
28 static void SEMAPHORE_RemoveWait( K32OBJ *obj, DWORD thread_id );
29 static void SEMAPHORE_Destroy( K32OBJ *obj );
31 const K32OBJ_OPS SEMAPHORE_Ops =
33 SEMAPHORE_Signaled, /* signaled */
34 SEMAPHORE_Satisfied, /* satisfied */
35 SEMAPHORE_AddWait, /* add_wait */
36 SEMAPHORE_RemoveWait, /* remove_wait */
37 NULL, /* read */
38 NULL, /* write */
39 SEMAPHORE_Destroy /* destroy */
43 /***********************************************************************
44 * CreateSemaphore32A (KERNEL32.174)
46 HANDLE32 WINAPI CreateSemaphore32A( SECURITY_ATTRIBUTES *sa, LONG initial,
47 LONG max, LPCSTR name )
49 struct create_semaphore_request req;
50 struct create_semaphore_reply reply;
51 int len = name ? strlen(name) + 1 : 0;
52 HANDLE32 handle;
53 SEMAPHORE *sem;
55 /* Check parameters */
57 if ((max <= 0) || (initial < 0) || (initial > max))
59 SetLastError( ERROR_INVALID_PARAMETER );
60 return INVALID_HANDLE_VALUE32;
63 req.initial = (unsigned int)initial;
64 req.max = (unsigned int)max;
65 req.inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
67 CLIENT_SendRequest( REQ_CREATE_SEMAPHORE, -1, 2, &req, sizeof(req), name, len );
68 CLIENT_WaitReply( &len, NULL, 1, &reply, sizeof(reply) );
69 CHECK_LEN( len, sizeof(reply) );
70 if (reply.handle == -1) return NULL;
72 SYSTEM_LOCK();
73 sem = (SEMAPHORE *)K32OBJ_Create( K32OBJ_SEMAPHORE, sizeof(*sem),
74 name, reply.handle, SEMAPHORE_ALL_ACCESS,
75 sa, &handle);
76 if (sem)
78 /* Finish initializing it */
79 sem->wait_queue = NULL;
80 sem->count = initial;
81 sem->max = max;
82 K32OBJ_DecCount( &sem->header );
84 SYSTEM_UNLOCK();
85 return handle;
89 /***********************************************************************
90 * CreateSemaphore32W (KERNEL32.175)
92 HANDLE32 WINAPI CreateSemaphore32W( SECURITY_ATTRIBUTES *sa, LONG initial,
93 LONG max, LPCWSTR name )
95 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
96 HANDLE32 ret = CreateSemaphore32A( sa, initial, max, nameA );
97 if (nameA) HeapFree( GetProcessHeap(), 0, nameA );
98 return ret;
102 /***********************************************************************
103 * OpenSemaphore32A (KERNEL32.545)
105 HANDLE32 WINAPI OpenSemaphore32A( DWORD access, BOOL32 inherit, LPCSTR name )
107 HANDLE32 handle = 0;
108 K32OBJ *obj;
109 SYSTEM_LOCK();
110 if ((obj = K32OBJ_FindNameType( name, K32OBJ_SEMAPHORE )) != NULL)
112 handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit, -1 );
113 K32OBJ_DecCount( obj );
115 SYSTEM_UNLOCK();
116 return handle;
120 /***********************************************************************
121 * OpenSemaphore32W (KERNEL32.546)
123 HANDLE32 WINAPI OpenSemaphore32W( DWORD access, BOOL32 inherit, LPCWSTR name )
125 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
126 HANDLE32 ret = OpenSemaphore32A( access, inherit, nameA );
127 if (nameA) HeapFree( GetProcessHeap(), 0, nameA );
128 return ret;
132 /***********************************************************************
133 * ReleaseSemaphore (KERNEL32.583)
135 BOOL32 WINAPI ReleaseSemaphore( HANDLE32 handle, LONG count, LONG *previous )
137 struct release_semaphore_request req;
138 SEMAPHORE *sem;
140 if (count < 0)
142 SetLastError( ERROR_INVALID_PARAMETER );
143 return FALSE;
145 SYSTEM_LOCK();
146 if (!(sem = (SEMAPHORE *)HANDLE_GetObjPtr( PROCESS_Current(), handle,
147 K32OBJ_SEMAPHORE,
148 SEMAPHORE_MODIFY_STATE, &req.handle )))
150 SYSTEM_UNLOCK();
151 return FALSE;
153 if (req.handle != -1)
155 struct release_semaphore_reply reply;
156 int len;
158 SYSTEM_UNLOCK();
159 req.count = (unsigned int)count;
160 CLIENT_SendRequest( REQ_RELEASE_SEMAPHORE, -1, 1, &req, sizeof(req) );
161 if (CLIENT_WaitReply( &len, NULL, 1, &reply, sizeof(reply) )) return FALSE;
162 CHECK_LEN( len, sizeof(reply) );
163 if (previous) *previous = reply.prev_count;
164 return TRUE;
166 if (previous) *previous = sem->count;
167 if (sem->count + count > sem->max)
169 SYSTEM_UNLOCK();
170 SetLastError( ERROR_TOO_MANY_POSTS );
171 return FALSE;
173 if (sem->count > 0)
175 /* There cannot be any thread waiting if the count is > 0 */
176 assert( sem->wait_queue == NULL );
177 sem->count += count;
179 else
181 sem->count = count;
182 SYNC_WakeUp( &sem->wait_queue, count );
184 K32OBJ_DecCount( &sem->header );
185 SYSTEM_UNLOCK();
186 return TRUE;
190 /***********************************************************************
191 * SEMAPHORE_Signaled
193 static BOOL32 SEMAPHORE_Signaled( K32OBJ *obj, DWORD thread_id )
195 SEMAPHORE *sem = (SEMAPHORE *)obj;
196 assert( obj->type == K32OBJ_SEMAPHORE );
197 return (sem->count > 0);
201 /***********************************************************************
202 * SEMAPHORE_Satisfied
204 * Wait on this object has been satisfied.
206 static BOOL32 SEMAPHORE_Satisfied( K32OBJ *obj, DWORD thread_id )
208 SEMAPHORE *sem = (SEMAPHORE *)obj;
209 assert( obj->type == K32OBJ_SEMAPHORE );
210 assert( sem->count > 0 );
211 sem->count--;
212 return FALSE; /* Not abandoned */
216 /***********************************************************************
217 * SEMAPHORE_AddWait
219 * Add current thread to object wait queue.
221 static void SEMAPHORE_AddWait( K32OBJ *obj, DWORD thread_id )
223 SEMAPHORE *sem = (SEMAPHORE *)obj;
224 assert( obj->type == K32OBJ_SEMAPHORE );
225 THREAD_AddQueue( &sem->wait_queue, THREAD_ID_TO_THDB(thread_id) );
229 /***********************************************************************
230 * SEMAPHORE_RemoveWait
232 * Remove thread from object wait queue.
234 static void SEMAPHORE_RemoveWait( K32OBJ *obj, DWORD thread_id )
236 SEMAPHORE *sem = (SEMAPHORE *)obj;
237 assert( obj->type == K32OBJ_SEMAPHORE );
238 THREAD_RemoveQueue( &sem->wait_queue, THREAD_ID_TO_THDB(thread_id) );
242 /***********************************************************************
243 * SEMAPHORE_Destroy
245 static void SEMAPHORE_Destroy( K32OBJ *obj )
247 SEMAPHORE *sem = (SEMAPHORE *)obj;
248 assert( obj->type == K32OBJ_SEMAPHORE );
249 /* There cannot be any thread on the list since the ref count is 0 */
250 assert( sem->wait_queue == NULL );
251 obj->type = K32OBJ_UNKNOWN;
252 HeapFree( SystemHeap, 0, sem );