6 #include "mono/io-layer/wapi.h"
7 #include "wapi-private.h"
8 #include "wait-private.h"
9 #include "misc-private.h"
10 #include "handles-private.h"
14 struct _WapiHandle_mutex
17 pthread_mutex_t mutex;
22 static void mutex_close(WapiHandle *handle);
23 static gboolean mutex_wait(WapiHandle *handle, WapiHandle *signal, guint32 ms);
24 static guint32 mutex_wait_multiple(gpointer data);
25 static void mutex_signal(WapiHandle *handle);
27 static struct _WapiHandleOps mutex_ops = {
28 mutex_close, /* close */
29 NULL, /* getfiletype */
33 NULL, /* setendoffile */
34 NULL, /* getfilesize */
35 NULL, /* getfiletime */
36 NULL, /* setfiletime */
37 mutex_wait, /* wait */
38 mutex_wait_multiple, /* wait_multiple */
39 mutex_signal, /* signal */
42 static void mutex_close(WapiHandle *handle)
44 struct _WapiHandle_mutex *mutex_handle=(struct _WapiHandle_mutex *)handle;
47 g_message(G_GNUC_PRETTY_FUNCTION ": closing mutex handle %p",
51 pthread_mutex_destroy(&mutex_handle->mutex);
54 static gboolean mutex_wait(WapiHandle *handle, WapiHandle *signal, guint32 ms)
56 struct _WapiHandle_mutex *mutex_handle=(struct _WapiHandle_mutex *)handle;
57 pthread_t tid=pthread_self();
61 g_message(G_GNUC_PRETTY_FUNCTION ": waiting for mutex handle %p",
65 /* Signal this handle now. It really doesn't matter if some
66 * other thread grabs the mutex before we can
69 signal->ops->signal(signal);
72 if(mutex_handle->tid==tid) {
73 /* We already own this mutex, so just increase the count and
77 mutex_handle->recursion++;
80 g_message(G_GNUC_PRETTY_FUNCTION
81 ": Already own mutex handle %p (recursion %d)",
82 mutex_handle, mutex_handle->recursion);
89 ret=pthread_mutex_lock(&mutex_handle->mutex);
91 struct timespec timeout;
93 _wapi_calc_timeout(&timeout, ms);
95 ret=pthread_mutex_timedlock(&mutex_handle->mutex, &timeout);
102 g_message(G_GNUC_PRETTY_FUNCTION ": Locking mutex handle %p",
106 mutex_handle->tid=tid;
107 mutex_handle->recursion=1;
111 /* ret might be ETIMEDOUT for timeout, or other for error */
114 g_message(G_GNUC_PRETTY_FUNCTION
115 ": Failed to lock mutex handle %p: %s", mutex_handle,
122 static guint32 mutex_wait_multiple(gpointer data G_GNUC_UNUSED)
124 WaitQueueItem *item=(WaitQueueItem *)data;
128 struct timespec timeout;
129 pthread_t tid=pthread_self();
130 guint32 i, iterations;
132 numhandles=item->handles[WAPI_HANDLE_MUTEX]->len;
135 g_message(G_GNUC_PRETTY_FUNCTION
136 ": waiting on %d mutex handles for %d ms", numhandles,
141 * See which ones we need to lock
143 needed=g_ptr_array_new();
144 for(i=0; i<numhandles; i++) {
145 struct _WapiHandle_mutex *mutex_handle;
147 mutex_handle=g_ptr_array_index(
148 item->handles[WAPI_HANDLE_MUTEX], i);
150 if(mutex_handle->tid!=tid) {
151 /* We don't have this one, so add it to the list */
152 g_ptr_array_add(needed, mutex_handle);
157 g_message(G_GNUC_PRETTY_FUNCTION ": need to lock %d mutex handles",
165 /* If the timeout isnt INFINITE but greater than 1s,
166 * split the timeout into 1s chunks
168 if((item->timeout!=INFINITE) &&
169 (item->timeout < (iterations*1000))) {
171 &timeout, item->timeout-((iterations-1)*1000));
173 _wapi_calc_timeout(&timeout, 1000);
176 /* Try and lock as many mutexes as we can until we run
177 * out of time, but to avoid deadlocks back off if we
180 for(i=0; i<needed->len; i++) {
181 struct _WapiHandle_mutex *mutex_handle;
183 mutex_handle=g_ptr_array_index(needed, i);
186 g_message(G_GNUC_PRETTY_FUNCTION
187 ": Locking %d mutex %p (owner %ld, me %ld)",
188 i, mutex_handle, mutex_handle->tid, tid);
191 ret=pthread_mutex_timedlock(&mutex_handle->mutex,
195 g_message(G_GNUC_PRETTY_FUNCTION ": timedlock ret %s",
200 /* ETIMEDOUT is the most likely, but
201 * fail on other error too
205 g_message(G_GNUC_PRETTY_FUNCTION
206 ": Lock %d mutex failed: %s", i,
212 g_message(G_GNUC_PRETTY_FUNCTION
213 ": Releasing %d mutex", i);
215 mutex_handle=g_ptr_array_index(needed,
217 pthread_mutex_unlock(
218 &mutex_handle->mutex);
224 /* OK, got that one. Don't record it as ours
225 * though until we get them all
230 /* We've locked all the mutexes. Update the
231 * ones we already had, and record that the
232 * new ones belong to us
234 for(i=0; i<numhandles; i++) {
235 struct _WapiHandle_mutex *mutex_handle;
238 mutex_handle=g_ptr_array_index(
239 item->handles[WAPI_HANDLE_MUTEX], i);
242 item->waitindex[WAPI_HANDLE_MUTEX],
244 _wapi_handle_set_lowest(item, idx);
247 g_message(G_GNUC_PRETTY_FUNCTION
248 ": Updating mutex %p", mutex_handle);
251 if(mutex_handle->tid==tid) {
252 /* We already own this mutex,
253 * so just increase the count
255 mutex_handle->recursion++;
257 mutex_handle->tid=tid;
258 mutex_handle->recursion=1;
262 g_ptr_array_free(needed, FALSE);
264 item->waited[WAPI_HANDLE_MUTEX]=TRUE;
265 item->waitcount[WAPI_HANDLE_MUTEX]=numhandles;
269 } while((item->timeout==INFINITE) ||
270 (item->timeout > (iterations * 1000)));
272 /* Didn't get all the locks, and timeout isn't INFINITE */
274 g_ptr_array_free(needed, FALSE);
276 item->waited[WAPI_HANDLE_MUTEX]=TRUE;
277 item->waitcount[WAPI_HANDLE_MUTEX]=0;
282 static void mutex_signal(WapiHandle *handle)
284 ReleaseMutex(handle);
289 * @security: Ignored for now.
290 * @owned: If %TRUE, the mutex is created with the calling thread
291 * already owning the mutex.
292 * @name:Pointer to a string specifying the name of this mutex, or
293 * %NULL. Currently ignored.
295 * Creates a new mutex handle. A mutex is signalled when no thread
296 * owns it. A thread acquires ownership of the mutex by waiting for
297 * it with WaitForSingleObject() or WaitForMultipleObjects(). A
298 * thread relinquishes ownership with ReleaseMutex().
300 * A thread that owns a mutex can specify the same mutex in repeated
301 * wait function calls without blocking. The thread must call
302 * ReleaseMutex() an equal number of times to release the mutex.
304 * Return value: A new handle, or %NULL on error.
306 WapiHandle *CreateMutex(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean owned G_GNUC_UNUSED,
307 const guchar *name G_GNUC_UNUSED)
309 struct _WapiHandle_mutex *mutex_handle;
312 mutex_handle=(struct _WapiHandle_mutex *)g_new0(struct _WapiHandle_mutex, 1);
313 handle=(WapiHandle *)mutex_handle;
314 _WAPI_HANDLE_INIT(handle, WAPI_HANDLE_MUTEX, mutex_ops);
316 pthread_mutex_init(&mutex_handle->mutex, NULL);
318 pthread_t tid=pthread_self();
320 pthread_mutex_lock(&mutex_handle->mutex);
322 mutex_handle->tid=tid;
323 mutex_handle->recursion=1;
331 * @handle: The mutex handle.
333 * Releases ownership if the mutex handle @handle.
335 * Return value: %TRUE on success, %FALSE otherwise. This function
336 * fails if the calling thread does not own the mutex @handle.
338 gboolean ReleaseMutex(WapiHandle *handle)
340 struct _WapiHandle_mutex *mutex_handle=(struct _WapiHandle_mutex *)handle;
341 pthread_t tid=pthread_self();
344 g_message(G_GNUC_PRETTY_FUNCTION ": Releasing mutex handle %p",
348 if(mutex_handle->tid!=tid) {
350 g_message(G_GNUC_PRETTY_FUNCTION ": We don't own mutex handle %p (owned by %ld, me %ld)", mutex_handle, mutex_handle->tid, tid);
356 /* OK, we own this mutex */
357 mutex_handle->recursion--;
359 if(mutex_handle->recursion==0) {
361 g_message(G_GNUC_PRETTY_FUNCTION ": Unlocking mutex handle %p",
366 pthread_mutex_unlock(&mutex_handle->mutex);