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"
12 #include "mono-mutex.h"
16 struct _WapiHandle_mutex
24 static void mutex_close(WapiHandle *handle);
25 static gboolean mutex_wait(WapiHandle *handle, WapiHandle *signal, guint32 ms);
26 static guint32 mutex_wait_multiple(gpointer data);
27 static void mutex_signal(WapiHandle *handle);
29 static struct _WapiHandleOps mutex_ops = {
30 mutex_close, /* close */
31 NULL, /* getfiletype */
36 NULL, /* setendoffile */
37 NULL, /* getfilesize */
38 NULL, /* getfiletime */
39 NULL, /* setfiletime */
40 mutex_wait, /* wait */
41 mutex_wait_multiple, /* wait_multiple */
42 mutex_signal, /* signal */
45 static void mutex_close(WapiHandle *handle)
47 struct _WapiHandle_mutex *mutex_handle=(struct _WapiHandle_mutex *)handle;
50 g_message(G_GNUC_PRETTY_FUNCTION ": closing mutex handle %p",
54 mono_mutex_destroy(&mutex_handle->mutex);
57 static gboolean mutex_wait(WapiHandle *handle, WapiHandle *signal, guint32 ms)
59 struct _WapiHandle_mutex *mutex_handle=(struct _WapiHandle_mutex *)handle;
60 pthread_t tid=pthread_self();
64 g_message(G_GNUC_PRETTY_FUNCTION ": waiting for mutex handle %p",
68 /* Signal this handle now. It really doesn't matter if some
69 * other thread grabs the mutex before we can
72 signal->ops->signal(signal);
75 if(mutex_handle->tid==tid) {
76 /* We already own this mutex, so just increase the count and
80 mutex_handle->recursion++;
83 g_message(G_GNUC_PRETTY_FUNCTION
84 ": Already own mutex handle %p (recursion %d)",
85 mutex_handle, mutex_handle->recursion);
92 ret=mono_mutex_lock(&mutex_handle->mutex);
94 struct timespec timeout;
96 _wapi_calc_timeout(&timeout, ms);
98 ret=mono_mutex_timedlock(&mutex_handle->mutex, &timeout);
105 g_message(G_GNUC_PRETTY_FUNCTION ": Locking mutex handle %p",
109 mutex_handle->tid=tid;
110 mutex_handle->recursion=1;
114 /* ret might be ETIMEDOUT for timeout, or other for error */
117 g_message(G_GNUC_PRETTY_FUNCTION
118 ": Failed to lock mutex handle %p: %s", mutex_handle,
125 static guint32 mutex_wait_multiple(gpointer data G_GNUC_UNUSED)
127 WaitQueueItem *item=(WaitQueueItem *)data;
131 struct timespec timeout;
132 pthread_t tid=pthread_self();
133 guint32 i, iterations;
135 numhandles=item->handles[WAPI_HANDLE_MUTEX]->len;
138 g_message(G_GNUC_PRETTY_FUNCTION
139 ": waiting on %d mutex handles for %d ms", numhandles,
144 * See which ones we need to lock
146 needed=g_ptr_array_new();
147 for(i=0; i<numhandles; i++) {
148 struct _WapiHandle_mutex *mutex_handle;
150 mutex_handle=g_ptr_array_index(
151 item->handles[WAPI_HANDLE_MUTEX], i);
153 if(mutex_handle->tid!=tid) {
154 /* We don't have this one, so add it to the list */
155 g_ptr_array_add(needed, mutex_handle);
160 g_message(G_GNUC_PRETTY_FUNCTION ": need to lock %d mutex handles",
168 /* If the timeout isnt INFINITE but greater than 1s,
169 * split the timeout into 1s chunks
171 if((item->timeout!=INFINITE) &&
172 (item->timeout < (iterations*1000))) {
174 &timeout, item->timeout-((iterations-1)*1000));
176 _wapi_calc_timeout(&timeout, 1000);
179 /* Try and lock as many mutexes as we can until we run
180 * out of time, but to avoid deadlocks back off if we
183 for(i=0; i<needed->len; i++) {
184 struct _WapiHandle_mutex *mutex_handle;
186 mutex_handle=g_ptr_array_index(needed, i);
189 g_message(G_GNUC_PRETTY_FUNCTION
190 ": Locking %d mutex %p (owner %ld, me %ld)",
191 i, mutex_handle, mutex_handle->tid, tid);
194 ret=mono_mutex_timedlock(&mutex_handle->mutex,
198 g_message(G_GNUC_PRETTY_FUNCTION ": timedlock ret %s",
203 /* ETIMEDOUT is the most likely, but
204 * fail on other error too
208 g_message(G_GNUC_PRETTY_FUNCTION
209 ": Lock %d mutex failed: %s", i,
215 g_message(G_GNUC_PRETTY_FUNCTION
216 ": Releasing %d mutex", i);
218 mutex_handle=g_ptr_array_index(needed,
220 mono_mutex_unlock(&mutex_handle->mutex);
226 /* OK, got that one. Don't record it as ours
227 * though until we get them all
232 /* We've locked all the mutexes. Update the
233 * ones we already had, and record that the
234 * new ones belong to us
236 for(i=0; i<numhandles; i++) {
237 struct _WapiHandle_mutex *mutex_handle;
240 mutex_handle=g_ptr_array_index(
241 item->handles[WAPI_HANDLE_MUTEX], i);
244 item->waitindex[WAPI_HANDLE_MUTEX],
246 _wapi_handle_set_lowest(item, idx);
249 g_message(G_GNUC_PRETTY_FUNCTION
250 ": Updating mutex %p", mutex_handle);
253 if(mutex_handle->tid==tid) {
254 /* We already own this mutex,
255 * so just increase the count
257 mutex_handle->recursion++;
259 mutex_handle->tid=tid;
260 mutex_handle->recursion=1;
264 g_ptr_array_free(needed, FALSE);
266 item->waited[WAPI_HANDLE_MUTEX]=TRUE;
267 item->waitcount[WAPI_HANDLE_MUTEX]=numhandles;
271 } while((item->timeout==INFINITE) ||
272 (item->timeout > (iterations * 1000)));
274 /* Didn't get all the locks, and timeout isn't INFINITE */
276 g_ptr_array_free(needed, FALSE);
278 item->waited[WAPI_HANDLE_MUTEX]=TRUE;
279 item->waitcount[WAPI_HANDLE_MUTEX]=0;
284 static void mutex_signal(WapiHandle *handle)
286 ReleaseMutex(handle);
291 * @security: Ignored for now.
292 * @owned: If %TRUE, the mutex is created with the calling thread
293 * already owning the mutex.
294 * @name:Pointer to a string specifying the name of this mutex, or
295 * %NULL. Currently ignored.
297 * Creates a new mutex handle. A mutex is signalled when no thread
298 * owns it. A thread acquires ownership of the mutex by waiting for
299 * it with WaitForSingleObject() or WaitForMultipleObjects(). A
300 * thread relinquishes ownership with ReleaseMutex().
302 * A thread that owns a mutex can specify the same mutex in repeated
303 * wait function calls without blocking. The thread must call
304 * ReleaseMutex() an equal number of times to release the mutex.
306 * Return value: A new handle, or %NULL on error.
308 WapiHandle *CreateMutex(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean owned G_GNUC_UNUSED,
309 const guchar *name G_GNUC_UNUSED)
311 struct _WapiHandle_mutex *mutex_handle;
314 mutex_handle=(struct _WapiHandle_mutex *)g_new0(struct _WapiHandle_mutex, 1);
315 handle=(WapiHandle *)mutex_handle;
316 _WAPI_HANDLE_INIT(handle, WAPI_HANDLE_MUTEX, mutex_ops);
318 mono_mutex_init(&mutex_handle->mutex, NULL);
320 pthread_t tid=pthread_self();
322 mono_mutex_lock(&mutex_handle->mutex);
324 mutex_handle->tid=tid;
325 mutex_handle->recursion=1;
333 * @handle: The mutex handle.
335 * Releases ownership if the mutex handle @handle.
337 * Return value: %TRUE on success, %FALSE otherwise. This function
338 * fails if the calling thread does not own the mutex @handle.
340 gboolean ReleaseMutex(WapiHandle *handle)
342 struct _WapiHandle_mutex *mutex_handle=(struct _WapiHandle_mutex *)handle;
343 pthread_t tid=pthread_self();
346 g_message(G_GNUC_PRETTY_FUNCTION ": Releasing mutex handle %p",
350 if(mutex_handle->tid!=tid) {
352 g_message(G_GNUC_PRETTY_FUNCTION ": We don't own mutex handle %p (owned by %ld, me %ld)", mutex_handle, mutex_handle->tid, tid);
358 /* OK, we own this mutex */
359 mutex_handle->recursion--;
361 if(mutex_handle->recursion==0) {
363 g_message(G_GNUC_PRETTY_FUNCTION ": Unlocking mutex handle %p",
368 mono_mutex_unlock(&mutex_handle->mutex);