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 */
35 NULL, /* setendoffile */
36 NULL, /* getfilesize */
37 NULL, /* getfiletime */
38 NULL, /* setfiletime */
39 mutex_wait, /* wait */
40 mutex_wait_multiple, /* wait_multiple */
41 mutex_signal, /* signal */
44 static void mutex_close(WapiHandle *handle)
46 struct _WapiHandle_mutex *mutex_handle=(struct _WapiHandle_mutex *)handle;
49 g_message(G_GNUC_PRETTY_FUNCTION ": closing mutex handle %p",
53 mono_mutex_destroy(&mutex_handle->mutex);
56 static gboolean mutex_wait(WapiHandle *handle, WapiHandle *signal, guint32 ms)
58 struct _WapiHandle_mutex *mutex_handle=(struct _WapiHandle_mutex *)handle;
59 pthread_t tid=pthread_self();
63 g_message(G_GNUC_PRETTY_FUNCTION ": waiting for mutex handle %p",
67 /* Signal this handle now. It really doesn't matter if some
68 * other thread grabs the mutex before we can
71 signal->ops->signal(signal);
74 if(mutex_handle->tid==tid) {
75 /* We already own this mutex, so just increase the count and
79 mutex_handle->recursion++;
82 g_message(G_GNUC_PRETTY_FUNCTION
83 ": Already own mutex handle %p (recursion %d)",
84 mutex_handle, mutex_handle->recursion);
91 ret=mono_mutex_lock(&mutex_handle->mutex);
93 struct timespec timeout;
95 _wapi_calc_timeout(&timeout, ms);
97 ret=mono_mutex_timedlock(&mutex_handle->mutex, &timeout);
104 g_message(G_GNUC_PRETTY_FUNCTION ": Locking mutex handle %p",
108 mutex_handle->tid=tid;
109 mutex_handle->recursion=1;
113 /* ret might be ETIMEDOUT for timeout, or other for error */
116 g_message(G_GNUC_PRETTY_FUNCTION
117 ": Failed to lock mutex handle %p: %s", mutex_handle,
124 static guint32 mutex_wait_multiple(gpointer data G_GNUC_UNUSED)
126 WaitQueueItem *item=(WaitQueueItem *)data;
130 struct timespec timeout;
131 pthread_t tid=pthread_self();
132 guint32 i, iterations;
134 numhandles=item->handles[WAPI_HANDLE_MUTEX]->len;
137 g_message(G_GNUC_PRETTY_FUNCTION
138 ": waiting on %d mutex handles for %d ms", numhandles,
143 * See which ones we need to lock
145 needed=g_ptr_array_new();
146 for(i=0; i<numhandles; i++) {
147 struct _WapiHandle_mutex *mutex_handle;
149 mutex_handle=g_ptr_array_index(
150 item->handles[WAPI_HANDLE_MUTEX], i);
152 if(mutex_handle->tid!=tid) {
153 /* We don't have this one, so add it to the list */
154 g_ptr_array_add(needed, mutex_handle);
159 g_message(G_GNUC_PRETTY_FUNCTION ": need to lock %d mutex handles",
167 /* If the timeout isnt INFINITE but greater than 1s,
168 * split the timeout into 1s chunks
170 if((item->timeout!=INFINITE) &&
171 (item->timeout < (iterations*1000))) {
173 &timeout, item->timeout-((iterations-1)*1000));
175 _wapi_calc_timeout(&timeout, 1000);
178 /* Try and lock as many mutexes as we can until we run
179 * out of time, but to avoid deadlocks back off if we
182 for(i=0; i<needed->len; i++) {
183 struct _WapiHandle_mutex *mutex_handle;
185 mutex_handle=g_ptr_array_index(needed, i);
188 g_message(G_GNUC_PRETTY_FUNCTION
189 ": Locking %d mutex %p (owner %ld, me %ld)",
190 i, mutex_handle, mutex_handle->tid, tid);
193 ret=mono_mutex_timedlock(&mutex_handle->mutex,
197 g_message(G_GNUC_PRETTY_FUNCTION ": timedlock ret %s",
202 /* ETIMEDOUT is the most likely, but
203 * fail on other error too
207 g_message(G_GNUC_PRETTY_FUNCTION
208 ": Lock %d mutex failed: %s", i,
214 g_message(G_GNUC_PRETTY_FUNCTION
215 ": Releasing %d mutex", i);
217 mutex_handle=g_ptr_array_index(needed,
219 mono_mutex_unlock(&mutex_handle->mutex);
225 /* OK, got that one. Don't record it as ours
226 * though until we get them all
231 /* We've locked all the mutexes. Update the
232 * ones we already had, and record that the
233 * new ones belong to us
235 for(i=0; i<numhandles; i++) {
236 struct _WapiHandle_mutex *mutex_handle;
239 mutex_handle=g_ptr_array_index(
240 item->handles[WAPI_HANDLE_MUTEX], i);
243 item->waitindex[WAPI_HANDLE_MUTEX],
245 _wapi_handle_set_lowest(item, idx);
248 g_message(G_GNUC_PRETTY_FUNCTION
249 ": Updating mutex %p", mutex_handle);
252 if(mutex_handle->tid==tid) {
253 /* We already own this mutex,
254 * so just increase the count
256 mutex_handle->recursion++;
258 mutex_handle->tid=tid;
259 mutex_handle->recursion=1;
263 g_ptr_array_free(needed, FALSE);
265 item->waited[WAPI_HANDLE_MUTEX]=TRUE;
266 item->waitcount[WAPI_HANDLE_MUTEX]=numhandles;
270 } while((item->timeout==INFINITE) ||
271 (item->timeout > (iterations * 1000)));
273 /* Didn't get all the locks, and timeout isn't INFINITE */
275 g_ptr_array_free(needed, FALSE);
277 item->waited[WAPI_HANDLE_MUTEX]=TRUE;
278 item->waitcount[WAPI_HANDLE_MUTEX]=0;
283 static void mutex_signal(WapiHandle *handle)
285 ReleaseMutex(handle);
290 * @security: Ignored for now.
291 * @owned: If %TRUE, the mutex is created with the calling thread
292 * already owning the mutex.
293 * @name:Pointer to a string specifying the name of this mutex, or
294 * %NULL. Currently ignored.
296 * Creates a new mutex handle. A mutex is signalled when no thread
297 * owns it. A thread acquires ownership of the mutex by waiting for
298 * it with WaitForSingleObject() or WaitForMultipleObjects(). A
299 * thread relinquishes ownership with ReleaseMutex().
301 * A thread that owns a mutex can specify the same mutex in repeated
302 * wait function calls without blocking. The thread must call
303 * ReleaseMutex() an equal number of times to release the mutex.
305 * Return value: A new handle, or %NULL on error.
307 WapiHandle *CreateMutex(WapiSecurityAttributes *security G_GNUC_UNUSED, gboolean owned G_GNUC_UNUSED,
308 const guchar *name G_GNUC_UNUSED)
310 struct _WapiHandle_mutex *mutex_handle;
313 mutex_handle=(struct _WapiHandle_mutex *)g_new0(struct _WapiHandle_mutex, 1);
314 handle=(WapiHandle *)mutex_handle;
315 _WAPI_HANDLE_INIT(handle, WAPI_HANDLE_MUTEX, mutex_ops);
317 mono_mutex_init(&mutex_handle->mutex, NULL);
319 pthread_t tid=pthread_self();
321 mono_mutex_lock(&mutex_handle->mutex);
323 mutex_handle->tid=tid;
324 mutex_handle->recursion=1;
332 * @handle: The mutex handle.
334 * Releases ownership if the mutex handle @handle.
336 * Return value: %TRUE on success, %FALSE otherwise. This function
337 * fails if the calling thread does not own the mutex @handle.
339 gboolean ReleaseMutex(WapiHandle *handle)
341 struct _WapiHandle_mutex *mutex_handle=(struct _WapiHandle_mutex *)handle;
342 pthread_t tid=pthread_self();
345 g_message(G_GNUC_PRETTY_FUNCTION ": Releasing mutex handle %p",
349 if(mutex_handle->tid!=tid) {
351 g_message(G_GNUC_PRETTY_FUNCTION ": We don't own mutex handle %p (owned by %ld, me %ld)", mutex_handle, mutex_handle->tid, tid);
357 /* OK, we own this mutex */
358 mutex_handle->recursion--;
360 if(mutex_handle->recursion==0) {
362 g_message(G_GNUC_PRETTY_FUNCTION ": Unlocking mutex handle %p",
367 mono_mutex_unlock(&mutex_handle->mutex);