blob: 7c71a100624baa81ba9a6732042f9e1d3b1777d8 [file] [log] [blame]
Alexandre Julliard02e90081998-01-04 17:49:09 +00001/*
2 * Win32 semaphores
3 *
4 * Copyright 1998 Alexandre Julliard
5 */
6
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"
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000014#include "server/request.h"
15#include "server.h"
Alexandre Julliard02e90081998-01-04 17:49:09 +000016
17typedef struct
18{
19 K32OBJ header;
20 THREAD_QUEUE wait_queue;
21 LONG count;
22 LONG max;
23} SEMAPHORE;
24
25static BOOL32 SEMAPHORE_Signaled( K32OBJ *obj, DWORD thread_id );
Alexandre Julliard0623a6f1998-01-18 18:01:49 +000026static BOOL32 SEMAPHORE_Satisfied( K32OBJ *obj, DWORD thread_id );
Alexandre Julliard02e90081998-01-04 17:49:09 +000027static void SEMAPHORE_AddWait( K32OBJ *obj, DWORD thread_id );
28static void SEMAPHORE_RemoveWait( K32OBJ *obj, DWORD thread_id );
29static void SEMAPHORE_Destroy( K32OBJ *obj );
30
31const K32OBJ_OPS SEMAPHORE_Ops =
32{
33 SEMAPHORE_Signaled, /* signaled */
34 SEMAPHORE_Satisfied, /* satisfied */
35 SEMAPHORE_AddWait, /* add_wait */
36 SEMAPHORE_RemoveWait, /* remove_wait */
Alexandre Julliarda11d7b11998-03-01 20:05:02 +000037 NULL, /* read */
38 NULL, /* write */
Alexandre Julliard02e90081998-01-04 17:49:09 +000039 SEMAPHORE_Destroy /* destroy */
40};
41
42
43/***********************************************************************
44 * CreateSemaphore32A (KERNEL32.174)
45 */
46HANDLE32 WINAPI CreateSemaphore32A( SECURITY_ATTRIBUTES *sa, LONG initial,
47 LONG max, LPCSTR name )
48{
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000049 struct create_semaphore_request req;
50 struct create_semaphore_reply reply;
51 int len = name ? strlen(name) + 1 : 0;
Alexandre Julliard02e90081998-01-04 17:49:09 +000052 HANDLE32 handle;
53 SEMAPHORE *sem;
54
55 /* Check parameters */
56
57 if ((max <= 0) || (initial < 0) || (initial > max))
58 {
59 SetLastError( ERROR_INVALID_PARAMETER );
60 return INVALID_HANDLE_VALUE32;
61 }
62
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000063 req.initial = (unsigned int)initial;
64 req.max = (unsigned int)max;
65 req.inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
66
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;
71
Alexandre Julliard02e90081998-01-04 17:49:09 +000072 SYSTEM_LOCK();
73 sem = (SEMAPHORE *)K32OBJ_Create( K32OBJ_SEMAPHORE, sizeof(*sem),
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000074 name, reply.handle, SEMAPHORE_ALL_ACCESS,
75 sa, &handle);
Alexandre Julliard02e90081998-01-04 17:49:09 +000076 if (sem)
77 {
78 /* Finish initializing it */
79 sem->wait_queue = NULL;
80 sem->count = initial;
81 sem->max = max;
82 K32OBJ_DecCount( &sem->header );
83 }
84 SYSTEM_UNLOCK();
85 return handle;
86}
87
88
89/***********************************************************************
90 * CreateSemaphore32W (KERNEL32.175)
91 */
92HANDLE32 WINAPI CreateSemaphore32W( SECURITY_ATTRIBUTES *sa, LONG initial,
93 LONG max, LPCWSTR name )
94{
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;
99}
100
101
102/***********************************************************************
103 * OpenSemaphore32A (KERNEL32.545)
104 */
105HANDLE32 WINAPI OpenSemaphore32A( DWORD access, BOOL32 inherit, LPCSTR name )
106{
107 HANDLE32 handle = 0;
108 K32OBJ *obj;
109 SYSTEM_LOCK();
110 if ((obj = K32OBJ_FindNameType( name, K32OBJ_SEMAPHORE )) != NULL)
111 {
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000112 handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit, -1 );
Alexandre Julliard02e90081998-01-04 17:49:09 +0000113 K32OBJ_DecCount( obj );
114 }
115 SYSTEM_UNLOCK();
116 return handle;
117}
118
119
120/***********************************************************************
121 * OpenSemaphore32W (KERNEL32.546)
122 */
123HANDLE32 WINAPI OpenSemaphore32W( DWORD access, BOOL32 inherit, LPCWSTR name )
124{
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;
129}
130
131
132/***********************************************************************
133 * ReleaseSemaphore (KERNEL32.583)
134 */
135BOOL32 WINAPI ReleaseSemaphore( HANDLE32 handle, LONG count, LONG *previous )
136{
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000137 struct release_semaphore_request req;
Alexandre Julliard02e90081998-01-04 17:49:09 +0000138 SEMAPHORE *sem;
139
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000140 if (count < 0)
141 {
142 SetLastError( ERROR_INVALID_PARAMETER );
143 return FALSE;
144 }
Alexandre Julliard02e90081998-01-04 17:49:09 +0000145 SYSTEM_LOCK();
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000146 if (!(sem = (SEMAPHORE *)HANDLE_GetObjPtr( PROCESS_Current(), handle,
147 K32OBJ_SEMAPHORE,
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000148 SEMAPHORE_MODIFY_STATE, &req.handle )))
Alexandre Julliard02e90081998-01-04 17:49:09 +0000149 {
150 SYSTEM_UNLOCK();
151 return FALSE;
152 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000153 if (req.handle != -1)
154 {
155 struct release_semaphore_reply reply;
156 int len;
157
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;
165 }
Alexandre Julliard02e90081998-01-04 17:49:09 +0000166 if (previous) *previous = sem->count;
167 if (sem->count + count > sem->max)
168 {
169 SYSTEM_UNLOCK();
170 SetLastError( ERROR_TOO_MANY_POSTS );
171 return FALSE;
172 }
173 if (sem->count > 0)
174 {
175 /* There cannot be any thread waiting if the count is > 0 */
176 assert( sem->wait_queue == NULL );
177 sem->count += count;
178 }
179 else
180 {
181 sem->count = count;
182 SYNC_WakeUp( &sem->wait_queue, count );
183 }
184 K32OBJ_DecCount( &sem->header );
185 SYSTEM_UNLOCK();
186 return TRUE;
187}
188
189
190/***********************************************************************
191 * SEMAPHORE_Signaled
192 */
193static BOOL32 SEMAPHORE_Signaled( K32OBJ *obj, DWORD thread_id )
194{
195 SEMAPHORE *sem = (SEMAPHORE *)obj;
196 assert( obj->type == K32OBJ_SEMAPHORE );
197 return (sem->count > 0);
198}
199
200
201/***********************************************************************
202 * SEMAPHORE_Satisfied
203 *
204 * Wait on this object has been satisfied.
205 */
Alexandre Julliard0623a6f1998-01-18 18:01:49 +0000206static BOOL32 SEMAPHORE_Satisfied( K32OBJ *obj, DWORD thread_id )
Alexandre Julliard02e90081998-01-04 17:49:09 +0000207{
208 SEMAPHORE *sem = (SEMAPHORE *)obj;
209 assert( obj->type == K32OBJ_SEMAPHORE );
210 assert( sem->count > 0 );
211 sem->count--;
Alexandre Julliard0623a6f1998-01-18 18:01:49 +0000212 return FALSE; /* Not abandoned */
Alexandre Julliard02e90081998-01-04 17:49:09 +0000213}
214
215
216/***********************************************************************
217 * SEMAPHORE_AddWait
218 *
219 * Add current thread to object wait queue.
220 */
221static void SEMAPHORE_AddWait( K32OBJ *obj, DWORD thread_id )
222{
223 SEMAPHORE *sem = (SEMAPHORE *)obj;
224 assert( obj->type == K32OBJ_SEMAPHORE );
225 THREAD_AddQueue( &sem->wait_queue, THREAD_ID_TO_THDB(thread_id) );
226}
227
228
229/***********************************************************************
230 * SEMAPHORE_RemoveWait
231 *
232 * Remove thread from object wait queue.
233 */
234static void SEMAPHORE_RemoveWait( K32OBJ *obj, DWORD thread_id )
235{
236 SEMAPHORE *sem = (SEMAPHORE *)obj;
237 assert( obj->type == K32OBJ_SEMAPHORE );
238 THREAD_RemoveQueue( &sem->wait_queue, THREAD_ID_TO_THDB(thread_id) );
239}
240
241
242/***********************************************************************
243 * SEMAPHORE_Destroy
244 */
245static void SEMAPHORE_Destroy( K32OBJ *obj )
246{
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 );
253}