Release 980301
[wine/hacks.git] / scheduler / mutex.c
blobae69498cdaacfa75c7fd6d80ee323c84cf7096f7
1 /*
2 * Win32 mutexes
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"
15 typedef struct _MUTEX
17 K32OBJ header;
18 THREAD_QUEUE wait_queue;
19 DWORD owner;
20 DWORD count;
21 BOOL32 abandoned;
22 struct _MUTEX *next;
23 struct _MUTEX *prev;
24 } MUTEX;
26 static BOOL32 MUTEX_Signaled( K32OBJ *obj, DWORD thread_id );
27 static BOOL32 MUTEX_Satisfied( K32OBJ *obj, DWORD thread_id );
28 static void MUTEX_AddWait( K32OBJ *obj, DWORD thread_id );
29 static void MUTEX_RemoveWait( K32OBJ *obj, DWORD thread_id );
30 static void MUTEX_Destroy( K32OBJ *obj );
32 const K32OBJ_OPS MUTEX_Ops =
34 MUTEX_Signaled, /* signaled */
35 MUTEX_Satisfied, /* satisfied */
36 MUTEX_AddWait, /* add_wait */
37 MUTEX_RemoveWait, /* remove_wait */
38 NULL, /* read */
39 NULL, /* write */
40 MUTEX_Destroy /* destroy */
44 /***********************************************************************
45 * MUTEX_Release
47 * Release a mutex once the count is 0.
48 * Helper function for MUTEX_Abandon and ReleaseMutex.
50 static void MUTEX_Release( MUTEX *mutex )
52 /* Remove the mutex from the thread list of owned mutexes */
53 if (mutex->next) mutex->next->prev = mutex->prev;
54 if (mutex->prev) mutex->prev->next = mutex->next;
55 else THREAD_Current()->mutex_list = &mutex->next->header;
56 mutex->next = mutex->prev = NULL;
57 mutex->owner = 0;
58 SYNC_WakeUp( &mutex->wait_queue, INFINITE32 );
62 /***********************************************************************
63 * MUTEX_Abandon
65 * Abandon a mutex.
67 void MUTEX_Abandon( K32OBJ *obj )
69 MUTEX *mutex = (MUTEX *)obj;
70 assert( obj->type == K32OBJ_MUTEX );
71 assert( mutex->count && (mutex->owner == GetCurrentThreadId()) );
72 mutex->count = 0;
73 mutex->abandoned = TRUE;
74 MUTEX_Release( mutex );
78 /***********************************************************************
79 * CreateMutex32A (KERNEL32.166)
81 HANDLE32 WINAPI CreateMutex32A( SECURITY_ATTRIBUTES *sa, BOOL32 owner,
82 LPCSTR name )
84 HANDLE32 handle;
85 MUTEX *mutex;
87 SYSTEM_LOCK();
88 mutex = (MUTEX *)K32OBJ_Create( K32OBJ_MUTEX, sizeof(*mutex),
89 name, MUTEX_ALL_ACCESS, &handle );
90 if (mutex)
92 /* Finish initializing it */
93 mutex->wait_queue = NULL;
94 mutex->abandoned = FALSE;
95 mutex->prev = NULL;
96 if (owner)
98 K32OBJ **list;
99 mutex->owner = GetCurrentThreadId();
100 mutex->count = 1;
101 /* Add the mutex in the thread list of owned mutexes */
102 list = &THREAD_Current()->mutex_list;
103 if ((mutex->next = (MUTEX *)*list)) mutex->next->prev = mutex;
104 *list = &mutex->header;
106 else
108 mutex->owner = 0;
109 mutex->count = 0;
110 mutex->next = NULL;
112 K32OBJ_DecCount( &mutex->header );
114 SetLastError(0); /* FIXME */
115 SYSTEM_UNLOCK();
116 return handle;
120 /***********************************************************************
121 * CreateMutex32W (KERNEL32.167)
123 HANDLE32 WINAPI CreateMutex32W( SECURITY_ATTRIBUTES *sa, BOOL32 owner,
124 LPCWSTR name )
126 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
127 HANDLE32 ret = CreateMutex32A( sa, owner, nameA );
128 if (nameA) HeapFree( GetProcessHeap(), 0, nameA );
129 return ret;
133 /***********************************************************************
134 * OpenMutex32A (KERNEL32.541)
136 HANDLE32 WINAPI OpenMutex32A( DWORD access, BOOL32 inherit, LPCSTR name )
138 HANDLE32 handle = 0;
139 K32OBJ *obj;
140 SYSTEM_LOCK();
141 if ((obj = K32OBJ_FindNameType( name, K32OBJ_MUTEX )) != NULL)
143 handle = HANDLE_Alloc( obj, access, inherit );
144 K32OBJ_DecCount( obj );
146 SYSTEM_UNLOCK();
147 return handle;
151 /***********************************************************************
152 * OpenMutex32W (KERNEL32.542)
154 HANDLE32 WINAPI OpenMutex32W( DWORD access, BOOL32 inherit, LPCWSTR name )
156 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
157 HANDLE32 ret = OpenMutex32A( access, inherit, nameA );
158 if (nameA) HeapFree( GetProcessHeap(), 0, nameA );
159 return ret;
163 /***********************************************************************
164 * ReleaseMutex (KERNEL32.582)
166 BOOL32 WINAPI ReleaseMutex( HANDLE32 handle )
168 MUTEX *mutex;
169 SYSTEM_LOCK();
170 if (!(mutex = (MUTEX *)HANDLE_GetObjPtr( handle, K32OBJ_MUTEX,
171 MUTEX_MODIFY_STATE )))
173 SYSTEM_UNLOCK();
174 return FALSE;
176 if (!mutex->count || (mutex->owner != GetCurrentThreadId()))
178 SYSTEM_UNLOCK();
179 SetLastError( ERROR_NOT_OWNER );
180 return FALSE;
182 if (!--mutex->count) MUTEX_Release( mutex );
183 K32OBJ_DecCount( &mutex->header );
184 SYSTEM_UNLOCK();
185 return TRUE;
189 /***********************************************************************
190 * MUTEX_Signaled
192 static BOOL32 MUTEX_Signaled( K32OBJ *obj, DWORD thread_id )
194 MUTEX *mutex = (MUTEX *)obj;
195 assert( obj->type == K32OBJ_MUTEX );
196 return (!mutex->count || (mutex->owner == thread_id));
200 /***********************************************************************
201 * MUTEX_Satisfied
203 * Wait on this object has been satisfied.
205 static BOOL32 MUTEX_Satisfied( K32OBJ *obj, DWORD thread_id )
207 BOOL32 ret;
208 MUTEX *mutex = (MUTEX *)obj;
209 assert( obj->type == K32OBJ_MUTEX );
210 assert( !mutex->count || (mutex->owner == thread_id) );
211 mutex->owner = thread_id;
212 if (!mutex->count++)
214 /* Add the mutex in the thread list of owned mutexes */
215 K32OBJ **list = &THREAD_ID_TO_THDB( thread_id )->mutex_list;
216 assert( !mutex->next );
217 if ((mutex->next = (MUTEX *)*list)) mutex->next->prev = mutex;
218 *list = &mutex->header;
219 mutex->prev = NULL;
221 ret = mutex->abandoned;
222 mutex->abandoned = FALSE;
223 return ret;
227 /***********************************************************************
228 * MUTEX_AddWait
230 * Add a thread to the object wait queue.
232 static void MUTEX_AddWait( K32OBJ *obj, DWORD thread_id )
234 MUTEX *mutex = (MUTEX *)obj;
235 assert( obj->type == K32OBJ_MUTEX );
236 THREAD_AddQueue( &mutex->wait_queue, THREAD_ID_TO_THDB(thread_id) );
240 /***********************************************************************
241 * MUTEX_RemoveWait
243 * Remove a thread from the object wait queue.
245 static void MUTEX_RemoveWait( K32OBJ *obj, DWORD thread_id )
247 MUTEX *mutex = (MUTEX *)obj;
248 assert( obj->type == K32OBJ_MUTEX );
249 THREAD_RemoveQueue( &mutex->wait_queue, THREAD_ID_TO_THDB(thread_id) );
253 /***********************************************************************
254 * MUTEX_Destroy
256 static void MUTEX_Destroy( K32OBJ *obj )
258 MUTEX *mutex = (MUTEX *)obj;
259 assert( obj->type == K32OBJ_MUTEX );
260 /* There cannot be any thread on the list since the ref count is 0 */
261 assert( mutex->wait_queue == NULL );
262 obj->type = K32OBJ_UNKNOWN;
263 HeapFree( SystemHeap, 0, mutex );