Release 980215
[wine] / scheduler / semaphore.c
1 /*
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"
14
15 typedef struct
16 {
17     K32OBJ        header;
18     THREAD_QUEUE  wait_queue;
19     LONG          count;
20     LONG          max;
21 } SEMAPHORE;
22
23 static BOOL32 SEMAPHORE_Signaled( K32OBJ *obj, DWORD thread_id );
24 static BOOL32 SEMAPHORE_Satisfied( K32OBJ *obj, DWORD thread_id );
25 static void SEMAPHORE_AddWait( K32OBJ *obj, DWORD thread_id );
26 static void SEMAPHORE_RemoveWait( K32OBJ *obj, DWORD thread_id );
27 static void SEMAPHORE_Destroy( K32OBJ *obj );
28
29 const K32OBJ_OPS SEMAPHORE_Ops =
30 {
31     SEMAPHORE_Signaled,    /* signaled */
32     SEMAPHORE_Satisfied,   /* satisfied */
33     SEMAPHORE_AddWait,     /* add_wait */
34     SEMAPHORE_RemoveWait,  /* remove_wait */
35     SEMAPHORE_Destroy      /* destroy */
36 };
37
38
39 /***********************************************************************
40  *           CreateSemaphore32A   (KERNEL32.174)
41  */
42 HANDLE32 WINAPI CreateSemaphore32A( SECURITY_ATTRIBUTES *sa, LONG initial,
43                                     LONG max, LPCSTR name )
44 {
45     HANDLE32 handle;
46     SEMAPHORE *sem;
47
48     /* Check parameters */
49
50     if ((max <= 0) || (initial < 0) || (initial > max))
51     {
52         SetLastError( ERROR_INVALID_PARAMETER );
53         return INVALID_HANDLE_VALUE32;
54     }
55
56     SYSTEM_LOCK();
57     sem = (SEMAPHORE *)K32OBJ_Create( K32OBJ_SEMAPHORE, sizeof(*sem),
58                                       name, SEMAPHORE_ALL_ACCESS, &handle );
59     if (sem)
60     {
61         /* Finish initializing it */
62         sem->wait_queue = NULL;
63         sem->count      = initial;
64         sem->max        = max;
65         K32OBJ_DecCount( &sem->header );
66     }
67     SYSTEM_UNLOCK();
68     return handle;
69 }
70
71
72 /***********************************************************************
73  *           CreateSemaphore32W   (KERNEL32.175)
74  */
75 HANDLE32 WINAPI CreateSemaphore32W( SECURITY_ATTRIBUTES *sa, LONG initial,
76                                     LONG max, LPCWSTR name )
77 {
78     LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
79     HANDLE32 ret = CreateSemaphore32A( sa, initial, max, nameA );
80     if (nameA) HeapFree( GetProcessHeap(), 0, nameA );
81     return ret;
82 }
83
84
85 /***********************************************************************
86  *           OpenSemaphore32A   (KERNEL32.545)
87  */
88 HANDLE32 WINAPI OpenSemaphore32A( DWORD access, BOOL32 inherit, LPCSTR name )
89 {
90     HANDLE32 handle = 0;
91     K32OBJ *obj;
92     SYSTEM_LOCK();
93     if ((obj = K32OBJ_FindNameType( name, K32OBJ_SEMAPHORE )) != NULL)
94     {
95         handle = HANDLE_Alloc( obj, access, inherit );
96         K32OBJ_DecCount( obj );
97     }
98     SYSTEM_UNLOCK();
99     return handle;
100 }
101
102
103 /***********************************************************************
104  *           OpenSemaphore32W   (KERNEL32.546)
105  */
106 HANDLE32 WINAPI OpenSemaphore32W( DWORD access, BOOL32 inherit, LPCWSTR name )
107 {
108     LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
109     HANDLE32 ret = OpenSemaphore32A( access, inherit, nameA );
110     if (nameA) HeapFree( GetProcessHeap(), 0, nameA );
111     return ret;
112 }
113
114
115 /***********************************************************************
116  *           ReleaseSemaphore   (KERNEL32.583)
117  */
118 BOOL32 WINAPI ReleaseSemaphore( HANDLE32 handle, LONG count, LONG *previous )
119 {
120     SEMAPHORE *sem;
121
122     SYSTEM_LOCK();
123     if (!(sem = (SEMAPHORE *)HANDLE_GetObjPtr( handle, K32OBJ_SEMAPHORE,
124                                                SEMAPHORE_MODIFY_STATE )))
125     {
126         SYSTEM_UNLOCK();
127         return FALSE;
128     }
129     if (previous) *previous = sem->count;
130     if (sem->count + count > sem->max)
131     {
132         SYSTEM_UNLOCK();
133         SetLastError( ERROR_TOO_MANY_POSTS );
134         return FALSE;
135     }
136     if (sem->count > 0)
137     {
138         /* There cannot be any thread waiting if the count is > 0 */
139         assert( sem->wait_queue == NULL );
140         sem->count += count;
141     }
142     else
143     {
144         sem->count = count;
145         SYNC_WakeUp( &sem->wait_queue, count );
146     }
147     K32OBJ_DecCount( &sem->header );
148     SYSTEM_UNLOCK();
149     return TRUE;
150 }
151
152
153 /***********************************************************************
154  *           SEMAPHORE_Signaled
155  */
156 static BOOL32 SEMAPHORE_Signaled( K32OBJ *obj, DWORD thread_id )
157 {
158     SEMAPHORE *sem = (SEMAPHORE *)obj;
159     assert( obj->type == K32OBJ_SEMAPHORE );
160     return (sem->count > 0);
161 }
162
163
164 /***********************************************************************
165  *           SEMAPHORE_Satisfied
166  *
167  * Wait on this object has been satisfied.
168  */
169 static BOOL32 SEMAPHORE_Satisfied( K32OBJ *obj, DWORD thread_id )
170 {
171     SEMAPHORE *sem = (SEMAPHORE *)obj;
172     assert( obj->type == K32OBJ_SEMAPHORE );
173     assert( sem->count > 0 );
174     sem->count--;
175     return FALSE;  /* Not abandoned */
176 }
177
178
179 /***********************************************************************
180  *           SEMAPHORE_AddWait
181  *
182  * Add current thread to object wait queue.
183  */
184 static void SEMAPHORE_AddWait( K32OBJ *obj, DWORD thread_id )
185 {
186     SEMAPHORE *sem = (SEMAPHORE *)obj;
187     assert( obj->type == K32OBJ_SEMAPHORE );
188     THREAD_AddQueue( &sem->wait_queue, THREAD_ID_TO_THDB(thread_id) );
189 }
190
191
192 /***********************************************************************
193  *           SEMAPHORE_RemoveWait
194  *
195  * Remove thread from object wait queue.
196  */
197 static void SEMAPHORE_RemoveWait( K32OBJ *obj, DWORD thread_id )
198 {
199     SEMAPHORE *sem = (SEMAPHORE *)obj;
200     assert( obj->type == K32OBJ_SEMAPHORE );
201     THREAD_RemoveQueue( &sem->wait_queue, THREAD_ID_TO_THDB(thread_id) );
202 }
203
204
205 /***********************************************************************
206  *           SEMAPHORE_Destroy
207  */
208 static void SEMAPHORE_Destroy( K32OBJ *obj )
209 {
210     SEMAPHORE *sem = (SEMAPHORE *)obj;
211     assert( obj->type == K32OBJ_SEMAPHORE );
212     /* There cannot be any thread on the list since the ref count is 0 */
213     assert( sem->wait_queue == NULL );
214     obj->type = K32OBJ_UNKNOWN;
215     HeapFree( SystemHeap, 0, sem );
216 }