2009-02-25 Zoltan Varga <vargaz@gmail.com>
[mono-debugger.git] / mono / io-layer / handles.c
blob077ad8458780cad61e7c447972f1a4076aeb62e7
1 /*
2 * handles.c: Generic and internal operations on handles
4 * Author:
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002-2006 Novell, Inc.
8 */
10 #include <config.h>
11 #include <glib.h>
12 #include <pthread.h>
13 #include <errno.h>
14 #include <unistd.h>
15 #include <string.h>
16 #include <sys/types.h>
17 #ifdef HAVE_SYS_SOCKET_H
18 # include <sys/socket.h>
19 #endif
20 #ifdef HAVE_SYS_UN_H
21 # include <sys/un.h>
22 #endif
23 #ifdef HAVE_SYS_MMAN_H
24 # include <sys/mman.h>
25 #endif
26 #ifdef HAVE_DIRENT_H
27 # include <dirent.h>
28 #endif
29 #include <sys/stat.h>
31 #include <mono/os/gc_wrapper.h>
33 #include <mono/io-layer/wapi.h>
34 #include <mono/io-layer/wapi-private.h>
35 #include <mono/io-layer/handles-private.h>
36 #include <mono/io-layer/mono-mutex.h>
37 #include <mono/io-layer/misc-private.h>
38 #include <mono/io-layer/shared.h>
39 #include <mono/io-layer/collection.h>
40 #include <mono/io-layer/process-private.h>
41 #include <mono/io-layer/critical-section-private.h>
43 #undef DEBUG
44 #undef DEBUG_REFS
46 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
48 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
49 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
50 NULL,
51 &_wapi_file_ops,
52 &_wapi_console_ops,
53 &_wapi_thread_ops,
54 &_wapi_sem_ops,
55 &_wapi_mutex_ops,
56 &_wapi_event_ops,
57 &_wapi_socket_ops,
58 &_wapi_find_ops,
59 &_wapi_process_ops,
60 &_wapi_pipe_ops,
61 &_wapi_namedmutex_ops,
62 &_wapi_namedsem_ops,
63 &_wapi_namedevent_ops,
66 static void _wapi_shared_details (gpointer handle_info);
68 static void (*handle_details[WAPI_HANDLE_COUNT])(gpointer) = {
69 NULL,
70 _wapi_file_details,
71 _wapi_console_details,
72 _wapi_shared_details, /* thread */
73 _wapi_sem_details,
74 _wapi_mutex_details,
75 _wapi_event_details,
76 NULL, /* Nothing useful to see in a socket handle */
77 NULL, /* Nothing useful to see in a find handle */
78 _wapi_shared_details, /* process */
79 _wapi_pipe_details,
80 _wapi_shared_details, /* namedmutex */
81 _wapi_shared_details, /* namedsem */
82 _wapi_shared_details, /* namedevent */
85 const char *_wapi_handle_typename[] = {
86 "Unused",
87 "File",
88 "Console",
89 "Thread",
90 "Sem",
91 "Mutex",
92 "Event",
93 "Socket",
94 "Find",
95 "Process",
96 "Pipe",
97 "N.Mutex",
98 "N.Sem",
99 "N.Event",
100 "Error!!"
104 * We can hold _WAPI_PRIVATE_MAX_SLOTS * _WAPI_HANDLE_INITIAL_COUNT handles.
105 * If 4M handles are not enough... Oh, well... we will crash.
107 #define SLOT_INDEX(x) (x / _WAPI_HANDLE_INITIAL_COUNT)
108 #define SLOT_OFFSET(x) (x % _WAPI_HANDLE_INITIAL_COUNT)
110 struct _WapiHandleUnshared *_wapi_private_handles [_WAPI_PRIVATE_MAX_SLOTS];
111 static guint32 _wapi_private_handle_count = 0;
112 static guint32 _wapi_private_handle_slot_count = 0;
114 struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
115 struct _WapiFileShareLayout *_wapi_fileshare_layout = NULL;
117 guint32 _wapi_fd_reserve;
120 * This is an internal handle which is used for handling waiting for multiple handles.
121 * Threads which wait for multiple handles wait on this one handle, and when a handle
122 * is signalled, this handle is signalled too.
124 static gpointer _wapi_global_signal_handle;
126 /* Point to the mutex/cond inside _wapi_global_signal_handle */
127 mono_mutex_t *_wapi_global_signal_mutex;
128 pthread_cond_t *_wapi_global_signal_cond;
130 int _wapi_sem_id;
131 gboolean _wapi_has_shut_down = FALSE;
133 /* Use this instead of getpid(), to cope with linuxthreads. It's a
134 * function rather than a variable lookup because we need to get at
135 * this before share_init() might have been called.
137 static pid_t _wapi_pid;
138 static mono_once_t pid_init_once = MONO_ONCE_INIT;
140 static gpointer _wapi_handle_real_new (WapiHandleType type, gpointer handle_specific);
142 static void pid_init (void)
144 _wapi_pid = getpid ();
147 pid_t _wapi_getpid (void)
149 mono_once (&pid_init_once, pid_init);
151 return(_wapi_pid);
155 static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
157 static void handle_cleanup (void)
159 int i, j, k;
161 _wapi_process_signal_self ();
163 /* Every shared handle we were using ought really to be closed
164 * by now, but to make sure just blow them all away. The
165 * exiting finalizer thread in particular races us to the
166 * program exit and doesn't always win, so it can be left
167 * cluttering up the shared file. Anything else left over is
168 * really a bug.
170 for(i = SLOT_INDEX (0); _wapi_private_handles[i] != NULL; i++) {
171 for(j = SLOT_OFFSET (0); j < _WAPI_HANDLE_INITIAL_COUNT; j++) {
172 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles[i][j];
173 int type = handle_data->type;
176 if (_WAPI_SHARED_HANDLE (type)) {
177 gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
179 if (type == WAPI_HANDLE_THREAD) {
180 /* Special-case thread handles
181 * because they need extra
182 * cleanup. This also avoids
183 * a race condition between
184 * the application exit and
185 * the finalizer thread - if
186 * it finishes up between now
187 * and actual app termination
188 * it will find all its handle
189 * details have been blown
190 * away, so this sets those
191 * anyway.
193 _wapi_thread_set_termination_details (handle, 0);
196 for(k = handle_data->ref; k > 0; k--) {
197 #ifdef DEBUG
198 g_message ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
199 #endif
201 _wapi_handle_unref (handle);
207 _wapi_shm_semaphores_remove ();
210 void _wapi_cleanup ()
212 g_assert (_wapi_has_shut_down == FALSE);
214 _wapi_has_shut_down = TRUE;
216 _wapi_critical_section_cleanup ();
217 _wapi_error_cleanup ();
218 _wapi_thread_cleanup ();
221 static mono_once_t shared_init_once = MONO_ONCE_INIT;
222 static void shared_init (void)
224 g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
225 == WAPI_HANDLE_COUNT);
227 _wapi_fd_reserve = getdtablesize();
229 /* This is needed by the code in _wapi_handle_new_internal */
230 _wapi_fd_reserve = (_wapi_fd_reserve + (_WAPI_HANDLE_INITIAL_COUNT - 1)) & ~(_WAPI_HANDLE_INITIAL_COUNT - 1);
232 do {
234 * The entries in _wapi_private_handles reserved for fds are allocated lazily to
235 * save memory.
238 _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
239 _WAPI_HANDLE_INITIAL_COUNT);
242 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
243 _wapi_private_handle_slot_count ++;
244 } while(_wapi_fd_reserve > _wapi_private_handle_count);
246 _wapi_shm_semaphores_init ();
248 _wapi_shared_layout = _wapi_shm_attach (WAPI_SHM_DATA);
249 g_assert (_wapi_shared_layout != NULL);
251 _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
252 g_assert (_wapi_fileshare_layout != NULL);
254 _wapi_collection_init ();
256 /* Can't call wapi_handle_new as it calls us recursively */
257 _wapi_global_signal_handle = _wapi_handle_real_new (WAPI_HANDLE_EVENT, NULL);
259 _wapi_global_signal_cond = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_cond;
260 _wapi_global_signal_mutex = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_mutex;
262 /* Using g_atexit here instead of an explicit function call in
263 * a cleanup routine lets us cope when a third-party library
264 * calls exit (eg if an X client loses the connection to its
265 * server.)
267 g_atexit (handle_cleanup);
270 static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
271 WapiHandleType type,
272 gpointer handle_specific)
274 g_assert (_wapi_has_shut_down == FALSE);
276 handle->type = type;
277 handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
278 handle->signalled = FALSE;
279 handle->handle_refs = 1;
281 if (handle_specific != NULL) {
282 memcpy (&handle->u, handle_specific, sizeof (handle->u));
286 static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
287 WapiHandleType type, gpointer handle_specific)
289 int thr_ret;
291 g_assert (_wapi_has_shut_down == FALSE);
293 handle->type = type;
294 handle->signalled = FALSE;
295 handle->ref = 1;
297 if (!_WAPI_SHARED_HANDLE(type)) {
298 thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
299 g_assert (thr_ret == 0);
301 thr_ret = mono_mutex_init (&handle->signal_mutex, NULL);
302 g_assert (thr_ret == 0);
304 if (handle_specific != NULL) {
305 memcpy (&handle->u, handle_specific,
306 sizeof (handle->u));
311 static guint32 _wapi_handle_new_shared (WapiHandleType type,
312 gpointer handle_specific)
314 guint32 offset;
315 static guint32 last = 1;
316 int thr_ret;
318 g_assert (_wapi_has_shut_down == FALSE);
320 /* Leave the first slot empty as a guard */
321 again:
322 /* FIXME: expandable array */
323 for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT; offset++) {
324 struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
326 if(handle->type == WAPI_HANDLE_UNUSED) {
327 thr_ret = _wapi_handle_lock_shared_handles ();
328 g_assert (thr_ret == 0);
330 if (InterlockedCompareExchange ((gint32 *)&handle->type, type, WAPI_HANDLE_UNUSED) == WAPI_HANDLE_UNUSED) {
331 last = offset + 1;
333 _wapi_handle_init_shared (handle, type,
334 handle_specific);
336 _wapi_handle_unlock_shared_handles ();
338 return(offset);
339 } else {
340 /* Someone else beat us to it, just
341 * continue looking
345 _wapi_handle_unlock_shared_handles ();
349 if(last > 1) {
350 /* Try again from the beginning */
351 last = 1;
352 goto again;
355 /* Will need to expand the array. The caller will sort it out */
357 return(0);
361 * _wapi_handle_new_internal:
362 * @type: Init handle to this type
364 * Search for a free handle and initialize it. Return the handle on
365 * success and 0 on failure. This is only called from
366 * _wapi_handle_new, and scan_mutex must be held.
368 static guint32 _wapi_handle_new_internal (WapiHandleType type,
369 gpointer handle_specific)
371 guint32 i, k, count;
372 static guint32 last = 0;
373 gboolean retry = FALSE;
375 g_assert (_wapi_has_shut_down == FALSE);
377 /* A linear scan should be fast enough. Start from the last
378 * allocation, assuming that handles are allocated more often
379 * than they're freed. Leave the space reserved for file
380 * descriptors
383 if (last < _wapi_fd_reserve) {
384 last = _wapi_fd_reserve;
385 } else {
386 retry = TRUE;
389 again:
390 count = last;
391 for(i = SLOT_INDEX (count); i < _wapi_private_handle_slot_count; i++) {
392 if (_wapi_private_handles [i]) {
393 for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
394 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
396 if(handle->type == WAPI_HANDLE_UNUSED) {
397 last = count + 1;
399 _wapi_handle_init (handle, type, handle_specific);
400 return (count);
402 count++;
407 if(retry && last > _wapi_fd_reserve) {
408 /* Try again from the beginning */
409 last = _wapi_fd_reserve;
410 goto again;
413 /* Will need to expand the array. The caller will sort it out */
415 return(0);
418 static gpointer _wapi_handle_real_new (WapiHandleType type, gpointer handle_specific)
420 guint32 handle_idx = 0;
421 gpointer handle;
422 int thr_ret;
424 #ifdef DEBUG
425 g_message ("%s: Creating new handle of type %s", __func__,
426 _wapi_handle_typename[type]);
427 #endif
429 g_assert(!_WAPI_FD_HANDLE(type));
431 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
432 (void *)&scan_mutex);
433 thr_ret = mono_mutex_lock (&scan_mutex);
434 g_assert (thr_ret == 0);
436 while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
437 /* Try and expand the array, and have another go */
438 int idx = SLOT_INDEX (_wapi_private_handle_count);
439 if (idx >= _WAPI_PRIVATE_MAX_SLOTS) {
440 break;
443 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
444 _WAPI_HANDLE_INITIAL_COUNT);
446 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
447 _wapi_private_handle_slot_count ++;
450 thr_ret = mono_mutex_unlock (&scan_mutex);
451 g_assert (thr_ret == 0);
452 pthread_cleanup_pop (0);
454 if (handle_idx == 0) {
455 /* We ran out of slots */
456 handle = _WAPI_HANDLE_INVALID;
457 goto done;
460 /* Make sure we left the space for fd mappings */
461 g_assert (handle_idx >= _wapi_fd_reserve);
463 handle = GUINT_TO_POINTER (handle_idx);
465 #ifdef DEBUG
466 g_message ("%s: Allocated new handle %p", __func__, handle);
467 #endif
469 if (_WAPI_SHARED_HANDLE(type)) {
470 /* Add the shared section too */
471 guint32 ref;
473 ref = _wapi_handle_new_shared (type, handle_specific);
474 if (ref == 0) {
475 _wapi_handle_collect ();
476 ref = _wapi_handle_new_shared (type, handle_specific);
477 if (ref == 0) {
478 /* FIXME: grow the arrays */
479 handle = _WAPI_HANDLE_INVALID;
480 goto done;
484 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
485 #ifdef DEBUG
486 g_message ("%s: New shared handle at offset 0x%x", __func__,
487 ref);
488 #endif
491 done:
492 return(handle);
495 gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
497 g_assert (_wapi_has_shut_down == FALSE);
499 mono_once (&shared_init_once, shared_init);
501 return _wapi_handle_real_new (type, handle_specific);
504 gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
505 gboolean timestamp)
507 guint32 handle_idx = 0;
508 gpointer handle = INVALID_HANDLE_VALUE;
509 int thr_ret, i, k;
510 struct _WapiHandleShared *shared;
511 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
513 g_assert (_wapi_has_shut_down == FALSE);
515 mono_once (&shared_init_once, shared_init);
517 #ifdef DEBUG
518 g_message ("%s: Creating new handle of type %s to offset %d", __func__,
519 _wapi_handle_typename[type], offset);
520 #endif
522 g_assert(!_WAPI_FD_HANDLE(type));
523 g_assert(_WAPI_SHARED_HANDLE(type));
524 g_assert(offset != 0);
526 shared = &_wapi_shared_layout->handles[offset];
527 if (timestamp) {
528 /* Bump up the timestamp for this offset */
529 InterlockedExchange ((gint32 *)&shared->timestamp, now);
532 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
533 (void *)&scan_mutex);
534 thr_ret = mono_mutex_lock (&scan_mutex);
535 g_assert (thr_ret == 0);
537 for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
538 if (_wapi_private_handles [i]) {
539 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
540 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
542 if (handle_data->type == type &&
543 handle_data->u.shared.offset == offset) {
544 handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
545 goto first_pass_done;
551 first_pass_done:
552 thr_ret = mono_mutex_unlock (&scan_mutex);
553 g_assert (thr_ret == 0);
554 pthread_cleanup_pop (0);
556 if (handle != INVALID_HANDLE_VALUE) {
557 _wapi_handle_ref (handle);
559 #ifdef DEBUG
560 g_message ("%s: Returning old handle %p referencing 0x%x",
561 __func__, handle, offset);
562 #endif
563 return (handle);
566 /* Prevent entries expiring under us as we search */
567 thr_ret = _wapi_handle_lock_shared_handles ();
568 g_assert (thr_ret == 0);
570 if (shared->type == WAPI_HANDLE_UNUSED) {
571 /* Someone deleted this handle while we were working */
572 #ifdef DEBUG
573 g_message ("%s: Handle at 0x%x unused", __func__, offset);
574 #endif
575 goto done;
578 if (shared->type != type) {
579 #ifdef DEBUG
580 g_message ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
581 __func__, offset, offset,
582 _wapi_handle_typename[shared->type],
583 _wapi_handle_typename[type]);
584 #endif
585 goto done;
588 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
589 (void *)&scan_mutex);
590 thr_ret = mono_mutex_lock (&scan_mutex);
591 g_assert (thr_ret == 0);
593 while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
594 /* Try and expand the array, and have another go */
595 int idx = SLOT_INDEX (_wapi_private_handle_count);
596 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
597 _WAPI_HANDLE_INITIAL_COUNT);
599 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
600 _wapi_private_handle_slot_count ++;
603 thr_ret = mono_mutex_unlock (&scan_mutex);
604 g_assert (thr_ret == 0);
605 pthread_cleanup_pop (0);
607 /* Make sure we left the space for fd mappings */
608 g_assert (handle_idx >= _wapi_fd_reserve);
610 handle = GUINT_TO_POINTER (handle_idx);
612 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
613 InterlockedIncrement ((gint32 *)&shared->handle_refs);
615 #ifdef DEBUG
616 g_message ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
617 #endif
619 done:
620 _wapi_handle_unlock_shared_handles ();
622 return(handle);
625 static void
626 init_handles_slot (int idx)
628 int thr_ret;
630 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
631 (void *)&scan_mutex);
632 thr_ret = mono_mutex_lock (&scan_mutex);
633 g_assert (thr_ret == 0);
635 if (_wapi_private_handles [idx] == NULL) {
636 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
637 _WAPI_HANDLE_INITIAL_COUNT);
638 g_assert (_wapi_private_handles [idx]);
641 thr_ret = mono_mutex_unlock (&scan_mutex);
642 g_assert (thr_ret == 0);
643 pthread_cleanup_pop (0);
646 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
647 gpointer handle_specific)
649 struct _WapiHandleUnshared *handle;
650 int thr_ret;
652 g_assert (_wapi_has_shut_down == FALSE);
654 mono_once (&shared_init_once, shared_init);
656 #ifdef DEBUG
657 g_message ("%s: Creating new handle of type %s", __func__,
658 _wapi_handle_typename[type]);
659 #endif
661 g_assert(_WAPI_FD_HANDLE(type));
662 g_assert(!_WAPI_SHARED_HANDLE(type));
664 if (fd >= _wapi_fd_reserve) {
665 #ifdef DEBUG
666 g_message ("%s: fd %d is too big", __func__, fd);
667 #endif
669 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
672 /* Initialize the array entries on demand */
673 if (_wapi_private_handles [SLOT_INDEX (fd)] == NULL)
674 init_handles_slot (SLOT_INDEX (fd));
676 handle = &_WAPI_PRIVATE_HANDLES(fd);
678 if (handle->type != WAPI_HANDLE_UNUSED) {
679 #ifdef DEBUG
680 g_message ("%s: fd %d is already in use!", __func__, fd);
681 #endif
682 /* FIXME: clean up this handle? We can't do anything
683 * with the fd, cos thats the new one
687 #ifdef DEBUG
688 g_message ("%s: Assigning new fd handle %d", __func__, fd);
689 #endif
691 /* Prevent file share entries racing with us, when the file
692 * handle is only half initialised
694 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
695 g_assert(thr_ret == 0);
697 _wapi_handle_init (handle, type, handle_specific);
699 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
701 return(GUINT_TO_POINTER(fd));
704 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
705 gpointer *handle_specific)
707 struct _WapiHandleUnshared *handle_data;
708 guint32 handle_idx = GPOINTER_TO_UINT(handle);
710 if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
711 return(FALSE);
714 /* Initialize the array entries on demand */
715 if (_wapi_private_handles [SLOT_INDEX (handle_idx)] == NULL)
716 init_handles_slot (SLOT_INDEX (handle_idx));
718 handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
720 if (handle_data->type != type) {
721 return(FALSE);
724 if (handle_specific == NULL) {
725 return(FALSE);
728 if (_WAPI_SHARED_HANDLE(type)) {
729 struct _WapiHandle_shared_ref *ref;
730 struct _WapiHandleShared *shared_handle_data;
732 ref = &handle_data->u.shared;
733 shared_handle_data = &_wapi_shared_layout->handles[ref->offset];
735 if (shared_handle_data->type != type) {
736 /* The handle must have been deleted on us
738 return (FALSE);
741 *handle_specific = &shared_handle_data->u;
742 } else {
743 *handle_specific = &handle_data->u;
746 return(TRUE);
749 void
750 _wapi_handle_foreach (WapiHandleType type,
751 gboolean (*on_each)(gpointer test, gpointer user),
752 gpointer user_data)
754 struct _WapiHandleUnshared *handle_data = NULL;
755 gpointer ret = NULL;
756 guint32 i, k;
757 int thr_ret;
759 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
760 (void *)&scan_mutex);
761 thr_ret = mono_mutex_lock (&scan_mutex);
762 g_assert (thr_ret == 0);
764 for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
765 if (_wapi_private_handles [i]) {
766 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
767 handle_data = &_wapi_private_handles [i][k];
769 if (handle_data->type == type) {
770 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
771 if (on_each (ret, user_data) == TRUE)
772 break;
778 thr_ret = mono_mutex_unlock (&scan_mutex);
779 g_assert (thr_ret == 0);
780 pthread_cleanup_pop (0);
783 /* This might list some shared handles twice if they are already
784 * opened by this process, and the check function returns FALSE the
785 * first time. Shared handles that are created during the search are
786 * unreffed if the check function returns FALSE, so callers must not
787 * rely on the handle persisting (unless the check function returns
788 * TRUE)
790 gpointer _wapi_search_handle (WapiHandleType type,
791 gboolean (*check)(gpointer test, gpointer user),
792 gpointer user_data,
793 gpointer *handle_specific,
794 gboolean search_shared)
796 struct _WapiHandleUnshared *handle_data = NULL;
797 struct _WapiHandleShared *shared = NULL;
798 gpointer ret = NULL;
799 guint32 i, k;
800 gboolean found = FALSE;
801 int thr_ret;
803 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
804 (void *)&scan_mutex);
805 thr_ret = mono_mutex_lock (&scan_mutex);
806 g_assert (thr_ret == 0);
808 for (i = SLOT_INDEX (0); !found && i < _wapi_private_handle_slot_count; i++) {
809 if (_wapi_private_handles [i]) {
810 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
811 handle_data = &_wapi_private_handles [i][k];
813 if (handle_data->type == type) {
814 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
815 if (check (ret, user_data) == TRUE) {
816 _wapi_handle_ref (ret);
817 found = TRUE;
819 if (_WAPI_SHARED_HANDLE (type)) {
820 shared = &_wapi_shared_layout->handles[i];
823 break;
830 thr_ret = mono_mutex_unlock (&scan_mutex);
831 g_assert (thr_ret == 0);
832 pthread_cleanup_pop (0);
834 if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) {
835 /* Not found yet, so search the shared memory too */
836 #ifdef DEBUG
837 g_message ("%s: Looking at other shared handles...", __func__);
838 #endif
840 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
841 shared = &_wapi_shared_layout->handles[i];
843 if (shared->type == type) {
844 /* Tell new_from_offset to not
845 * timestamp this handle, because
846 * otherwise it will ping every handle
847 * in the list and they will never
848 * expire
850 ret = _wapi_handle_new_from_offset (type, i,
851 FALSE);
852 if (ret == INVALID_HANDLE_VALUE) {
853 /* This handle was deleted
854 * while we were looking at it
856 continue;
859 #ifdef DEBUG
860 g_message ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
861 #endif
863 /* It's possible that the shared part
864 * of this handle has now been blown
865 * away (after new_from_offset
866 * successfully opened it,) if its
867 * timestamp is too old. The check
868 * function needs to be aware of this,
869 * and cope if the handle has
870 * vanished.
872 if (check (ret, user_data) == TRUE) {
873 /* Timestamp this handle, but make
874 * sure it still exists first
876 thr_ret = _wapi_handle_lock_shared_handles ();
877 g_assert (thr_ret == 0);
879 if (shared->type == type) {
880 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
881 InterlockedExchange ((gint32 *)&shared->timestamp, now);
883 found = TRUE;
884 handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
886 _wapi_handle_unlock_shared_handles ();
887 break;
888 } else {
889 /* It's been deleted,
890 * so just keep
891 * looking
893 _wapi_handle_unlock_shared_handles ();
897 /* This isn't the handle we're looking
898 * for, so drop the reference we took
899 * in _wapi_handle_new_from_offset ()
901 _wapi_handle_unref (ret);
906 if (!found) {
907 ret = NULL;
908 goto done;
911 if(handle_specific != NULL) {
912 if (_WAPI_SHARED_HANDLE(type)) {
913 g_assert(shared->type == type);
915 *handle_specific = &shared->u;
916 } else {
917 *handle_specific = &handle_data->u;
921 done:
922 return(ret);
925 /* Returns the offset of the metadata array, or -1 on error, or 0 for
926 * not found (0 is not a valid offset)
928 gint32 _wapi_search_handle_namespace (WapiHandleType type,
929 gchar *utf8_name)
931 struct _WapiHandleShared *shared_handle_data;
932 guint32 i;
933 gint32 ret = 0;
934 int thr_ret;
936 g_assert(_WAPI_SHARED_HANDLE(type));
938 #ifdef DEBUG
939 g_message ("%s: Lookup for handle named [%s] type %s", __func__,
940 utf8_name, _wapi_handle_typename[type]);
941 #endif
943 /* Do a handle collection before starting to look, so that any
944 * stale cruft gets removed
946 _wapi_handle_collect ();
948 thr_ret = _wapi_handle_lock_shared_handles ();
949 g_assert (thr_ret == 0);
951 for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
952 WapiSharedNamespace *sharedns;
954 shared_handle_data = &_wapi_shared_layout->handles[i];
956 /* Check mutex, event, semaphore, timer, job and
957 * file-mapping object names. So far only mutex,
958 * semaphore and event are implemented.
960 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
961 continue;
964 #ifdef DEBUG
965 g_message ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
966 #endif
968 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
970 #ifdef DEBUG
971 g_message ("%s: name is [%s]", __func__, sharedns->name);
972 #endif
974 if (strcmp (sharedns->name, utf8_name) == 0) {
975 if (shared_handle_data->type != type) {
976 /* Its the wrong type, so fail now */
977 #ifdef DEBUG
978 g_message ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
979 #endif
980 ret = -1;
981 goto done;
982 } else {
983 #ifdef DEBUG
984 g_message ("%s: handle 0x%x matches name and type", __func__, i);
985 #endif
986 ret = i;
987 goto done;
992 done:
993 _wapi_handle_unlock_shared_handles ();
995 return(ret);
998 void _wapi_handle_ref (gpointer handle)
1000 guint32 idx = GPOINTER_TO_UINT(handle);
1001 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1002 struct _WapiHandleUnshared *handle_data;
1004 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1005 return;
1008 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1009 g_warning ("%s: Attempting to ref unused handle %p", __func__,
1010 handle);
1011 return;
1014 handle_data = &_WAPI_PRIVATE_HANDLES(idx);
1016 InterlockedIncrement ((gint32 *)&handle_data->ref);
1018 /* It's possible for processes to exit before getting around
1019 * to updating timestamps in the collection thread, so if a
1020 * shared handle is reffed do the timestamp here as well just
1021 * to make sure.
1023 if (_WAPI_SHARED_HANDLE(handle_data->type)) {
1024 struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
1026 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1029 #ifdef DEBUG_REFS
1030 g_message ("%s: %s handle %p ref now %d", __func__,
1031 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1032 handle,
1033 _WAPI_PRIVATE_HANDLES(idx).ref);
1034 #endif
1037 /* The handle must not be locked on entry to this function */
1038 void _wapi_handle_unref (gpointer handle)
1040 guint32 idx = GPOINTER_TO_UINT(handle);
1041 gboolean destroy = FALSE;
1042 int thr_ret;
1044 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1045 return;
1048 if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1049 g_warning ("%s: Attempting to unref unused handle %p",
1050 __func__, handle);
1051 return;
1054 /* Possible race condition here if another thread refs the
1055 * handle between here and setting the type to UNUSED. I
1056 * could lock a mutex, but I'm not sure that allowing a handle
1057 * reference to reach 0 isn't an application bug anyway.
1059 destroy = (InterlockedDecrement ((gint32 *)&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
1061 #ifdef DEBUG_REFS
1062 g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
1063 _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1064 handle,
1065 _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
1066 #endif
1068 if(destroy==TRUE) {
1069 /* Need to copy the handle info, reset the slot in the
1070 * array, and _only then_ call the close function to
1071 * avoid race conditions (eg file descriptors being
1072 * closed, and another file being opened getting the
1073 * same fd racing the memset())
1075 struct _WapiHandleUnshared handle_data;
1076 struct _WapiHandleShared shared_handle_data;
1077 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
1078 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
1079 gboolean is_shared = _WAPI_SHARED_HANDLE(type);
1081 if (is_shared) {
1082 /* If this is a shared handle we need to take
1083 * the shared lock outside of the scan_mutex
1084 * lock to avoid deadlocks
1086 thr_ret = _wapi_handle_lock_shared_handles ();
1087 g_assert (thr_ret == 0);
1090 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup, (void *)&scan_mutex);
1091 thr_ret = mono_mutex_lock (&scan_mutex);
1093 #ifdef DEBUG
1094 g_message ("%s: Destroying handle %p", __func__, handle);
1095 #endif
1097 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
1098 sizeof (struct _WapiHandleUnshared));
1100 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
1101 sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
1103 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
1105 if (!is_shared) {
1106 /* Destroy the mutex and cond var. We hope nobody
1107 * tried to grab them between the handle unlock and
1108 * now, but pthreads doesn't have a
1109 * "unlock_and_destroy" atomic function.
1111 thr_ret = mono_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
1112 g_assert (thr_ret == 0);
1114 thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
1115 g_assert (thr_ret == 0);
1116 } else {
1117 struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
1119 memcpy (&shared_handle_data, shared,
1120 sizeof (struct _WapiHandleShared));
1122 /* It's possible that this handle is already
1123 * pointing at a deleted shared section
1125 #ifdef DEBUG_REFS
1126 g_message ("%s: %s handle %p shared refs before dec %d", __func__, _wapi_handle_typename[type], handle, shared->handle_refs);
1127 #endif
1129 if (shared->handle_refs > 0) {
1130 shared->handle_refs--;
1131 if (shared->handle_refs == 0) {
1132 memset (shared, '\0', sizeof (struct _WapiHandleShared));
1137 thr_ret = mono_mutex_unlock (&scan_mutex);
1138 g_assert (thr_ret == 0);
1139 pthread_cleanup_pop (0);
1141 if (is_shared) {
1142 _wapi_handle_unlock_shared_handles ();
1145 if (close_func != NULL) {
1146 if (is_shared) {
1147 close_func (handle, &shared_handle_data.u);
1148 } else {
1149 close_func (handle, &handle_data.u);
1155 void _wapi_handle_register_capabilities (WapiHandleType type,
1156 WapiHandleCapability caps)
1158 handle_caps[type] = caps;
1161 gboolean _wapi_handle_test_capabilities (gpointer handle,
1162 WapiHandleCapability caps)
1164 guint32 idx = GPOINTER_TO_UINT(handle);
1165 WapiHandleType type;
1167 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1168 return(FALSE);
1171 type = _WAPI_PRIVATE_HANDLES(idx).type;
1173 #ifdef DEBUG
1174 g_message ("%s: testing 0x%x against 0x%x (%d)", __func__,
1175 handle_caps[type], caps, handle_caps[type] & caps);
1176 #endif
1178 return((handle_caps[type] & caps) != 0);
1181 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
1183 if (handle_ops[type] != NULL &&
1184 handle_ops[type]->close != NULL) {
1185 return (handle_ops[type]->close);
1188 return (NULL);
1191 void _wapi_handle_ops_close (gpointer handle, gpointer data)
1193 guint32 idx = GPOINTER_TO_UINT(handle);
1194 WapiHandleType type;
1196 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1197 return;
1200 type = _WAPI_PRIVATE_HANDLES(idx).type;
1202 if (handle_ops[type] != NULL &&
1203 handle_ops[type]->close != NULL) {
1204 handle_ops[type]->close (handle, data);
1208 void _wapi_handle_ops_signal (gpointer handle)
1210 guint32 idx = GPOINTER_TO_UINT(handle);
1211 WapiHandleType type;
1213 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1214 return;
1217 type = _WAPI_PRIVATE_HANDLES(idx).type;
1219 if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
1220 handle_ops[type]->signal (handle);
1224 gboolean _wapi_handle_ops_own (gpointer handle)
1226 guint32 idx = GPOINTER_TO_UINT(handle);
1227 WapiHandleType type;
1229 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1230 return(FALSE);
1233 type = _WAPI_PRIVATE_HANDLES(idx).type;
1235 if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
1236 return(handle_ops[type]->own_handle (handle));
1237 } else {
1238 return(FALSE);
1242 gboolean _wapi_handle_ops_isowned (gpointer handle)
1244 guint32 idx = GPOINTER_TO_UINT(handle);
1245 WapiHandleType type;
1247 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1248 return(FALSE);
1251 type = _WAPI_PRIVATE_HANDLES(idx).type;
1253 if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
1254 return(handle_ops[type]->is_owned (handle));
1255 } else {
1256 return(FALSE);
1260 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout)
1262 guint32 idx = GPOINTER_TO_UINT(handle);
1263 WapiHandleType type;
1265 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1266 return(WAIT_FAILED);
1269 type = _WAPI_PRIVATE_HANDLES(idx).type;
1271 if (handle_ops[type] != NULL &&
1272 handle_ops[type]->special_wait != NULL) {
1273 return(handle_ops[type]->special_wait (handle, timeout));
1274 } else {
1275 return(WAIT_FAILED);
1279 void _wapi_handle_ops_prewait (gpointer handle)
1281 guint32 idx = GPOINTER_TO_UINT (handle);
1282 WapiHandleType type;
1284 if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1285 return;
1288 type = _WAPI_PRIVATE_HANDLES (idx).type;
1290 if (handle_ops[type] != NULL &&
1291 handle_ops[type]->prewait != NULL) {
1292 handle_ops[type]->prewait (handle);
1298 * CloseHandle:
1299 * @handle: The handle to release
1301 * Closes and invalidates @handle, releasing any resources it
1302 * consumes. When the last handle to a temporary or non-persistent
1303 * object is closed, that object can be deleted. Closing the same
1304 * handle twice is an error.
1306 * Return value: %TRUE on success, %FALSE otherwise.
1308 gboolean CloseHandle(gpointer handle)
1310 if (handle == NULL) {
1311 /* Problem: because we map file descriptors to the
1312 * same-numbered handle we can't tell the difference
1313 * between a bogus handle and the handle to stdin.
1314 * Assume that it's the console handle if that handle
1315 * exists...
1317 if (_WAPI_PRIVATE_HANDLES (0).type != WAPI_HANDLE_CONSOLE) {
1318 SetLastError (ERROR_INVALID_PARAMETER);
1319 return(FALSE);
1322 if (handle == _WAPI_HANDLE_INVALID){
1323 SetLastError (ERROR_INVALID_PARAMETER);
1324 return(FALSE);
1327 _wapi_handle_unref (handle);
1329 return(TRUE);
1332 /* Lots more to implement here, but this is all we need at the moment */
1333 gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
1334 gpointer targetprocess, gpointer *target,
1335 guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED)
1337 if (srcprocess != _WAPI_PROCESS_CURRENT ||
1338 targetprocess != _WAPI_PROCESS_CURRENT) {
1339 /* Duplicating other process's handles is not supported */
1340 SetLastError (ERROR_INVALID_HANDLE);
1341 return(FALSE);
1344 if (src == _WAPI_PROCESS_CURRENT) {
1345 *target = _wapi_process_duplicate ();
1346 } else if (src == _WAPI_THREAD_CURRENT) {
1347 *target = _wapi_thread_duplicate ();
1348 } else {
1349 _wapi_handle_ref (src);
1350 *target = src;
1353 return(TRUE);
1356 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1357 gpointer *handles,
1358 gboolean waitall,
1359 guint32 *retcount,
1360 guint32 *lowest)
1362 guint32 count, i, iter=0;
1363 gboolean ret;
1364 int thr_ret;
1365 WapiHandleType type;
1367 /* Lock all the handles, with backoff */
1368 again:
1369 thr_ret = _wapi_handle_lock_shared_handles ();
1370 g_assert (thr_ret == 0);
1372 for(i=0; i<numhandles; i++) {
1373 gpointer handle = handles[i];
1374 guint32 idx = GPOINTER_TO_UINT(handle);
1376 #ifdef DEBUG
1377 g_message ("%s: attempting to lock %p", __func__, handle);
1378 #endif
1380 type = _WAPI_PRIVATE_HANDLES(idx).type;
1382 thr_ret = _wapi_handle_trylock_handle (handle);
1384 if (thr_ret != 0) {
1385 /* Bummer */
1387 #ifdef DEBUG
1388 g_message ("%s: attempt failed for %p: %s", __func__,
1389 handle, strerror (thr_ret));
1390 #endif
1392 thr_ret = _wapi_handle_unlock_shared_handles ();
1393 g_assert (thr_ret == 0);
1395 while (i--) {
1396 handle = handles[i];
1397 idx = GPOINTER_TO_UINT(handle);
1399 thr_ret = _wapi_handle_unlock_handle (handle);
1400 g_assert (thr_ret == 0);
1403 /* If iter ever reaches 100 the nanosleep will
1404 * return EINVAL immediately, but we have a
1405 * design flaw if that happens.
1407 iter++;
1408 if(iter==100) {
1409 g_warning ("%s: iteration overflow!",
1410 __func__);
1411 iter=1;
1414 #ifdef DEBUG
1415 g_message ("%s: Backing off for %d ms", __func__,
1416 iter*10);
1417 #endif
1418 _wapi_handle_spin (10 * iter);
1420 goto again;
1424 #ifdef DEBUG
1425 g_message ("%s: Locked all handles", __func__);
1426 #endif
1428 count=0;
1429 *lowest=numhandles;
1431 for(i=0; i<numhandles; i++) {
1432 gpointer handle = handles[i];
1433 guint32 idx = GPOINTER_TO_UINT(handle);
1435 type = _WAPI_PRIVATE_HANDLES(idx).type;
1437 #ifdef DEBUG
1438 g_message ("%s: Checking handle %p", __func__, handle);
1439 #endif
1441 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1442 (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1443 (_WAPI_SHARED_HANDLE(type) &&
1444 WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) ||
1445 (!_WAPI_SHARED_HANDLE(type) &&
1446 _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
1447 count++;
1449 #ifdef DEBUG
1450 g_message ("%s: Handle %p signalled", __func__,
1451 handle);
1452 #endif
1453 if(*lowest>i) {
1454 *lowest=i;
1459 #ifdef DEBUG
1460 g_message ("%s: %d event handles signalled", __func__, count);
1461 #endif
1463 if ((waitall == TRUE && count == numhandles) ||
1464 (waitall == FALSE && count > 0)) {
1465 ret=TRUE;
1466 } else {
1467 ret=FALSE;
1470 #ifdef DEBUG
1471 g_message ("%s: Returning %d", __func__, ret);
1472 #endif
1474 *retcount=count;
1476 return(ret);
1479 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1481 guint32 i;
1482 int thr_ret;
1484 thr_ret = _wapi_handle_unlock_shared_handles ();
1485 g_assert (thr_ret == 0);
1487 for(i=0; i<numhandles; i++) {
1488 gpointer handle = handles[i];
1490 #ifdef DEBUG
1491 g_message ("%s: unlocking handle %p", __func__, handle);
1492 #endif
1494 thr_ret = _wapi_handle_unlock_handle (handle);
1495 g_assert (thr_ret == 0);
1499 static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout, gboolean alertable)
1501 struct timespec fake_timeout;
1502 int ret;
1504 if (!alertable) {
1505 if (timeout)
1506 ret=mono_cond_timedwait (cond, mutex, timeout);
1507 else
1508 ret=mono_cond_wait (cond, mutex);
1509 } else {
1510 _wapi_calc_timeout (&fake_timeout, 100);
1512 if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
1513 (fake_timeout.tv_sec == timeout->tv_sec &&
1514 fake_timeout.tv_nsec > timeout->tv_nsec))) {
1515 /* Real timeout is less than 100ms time */
1516 ret=mono_cond_timedwait (cond, mutex, timeout);
1517 } else {
1518 ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
1520 /* Mask the fake timeout, this will cause
1521 * another poll if the cond was not really signaled
1523 if (ret==ETIMEDOUT) {
1524 ret=0;
1529 return(ret);
1532 int _wapi_handle_wait_signal (gboolean poll)
1534 return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, NULL, TRUE, poll);
1537 int _wapi_handle_timedwait_signal (struct timespec *timeout, gboolean poll)
1539 return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, TRUE, poll);
1542 int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable)
1544 #ifdef DEBUG
1545 g_message ("%s: waiting for %p", __func__, handle);
1546 #endif
1548 return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable, FALSE);
1551 int _wapi_handle_timedwait_signal_handle (gpointer handle,
1552 struct timespec *timeout, gboolean alertable, gboolean poll)
1554 #ifdef DEBUG
1555 g_message ("%s: waiting for %p (type %s)", __func__, handle,
1556 _wapi_handle_typename[_wapi_handle_type (handle)]);
1557 #endif
1559 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1560 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1561 return (0);
1563 if (timeout != NULL) {
1564 struct timespec fake_timeout;
1565 _wapi_calc_timeout (&fake_timeout, 100);
1567 if ((fake_timeout.tv_sec > timeout->tv_sec) ||
1568 (fake_timeout.tv_sec == timeout->tv_sec &&
1569 fake_timeout.tv_nsec > timeout->tv_nsec)) {
1570 /* FIXME: Real timeout is less than
1571 * 100ms time, but is it really worth
1572 * calculating to the exact ms?
1574 _wapi_handle_spin (100);
1576 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1577 return (0);
1578 } else {
1579 return (ETIMEDOUT);
1583 _wapi_handle_spin (100);
1584 return (0);
1586 } else {
1587 guint32 idx = GPOINTER_TO_UINT(handle);
1588 int res;
1589 pthread_cond_t *cond;
1590 mono_mutex_t *mutex;
1592 if (alertable && !wapi_thread_set_wait_handle (handle))
1593 return 0;
1595 cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1596 mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1598 if (poll) {
1599 /* This is needed when waiting for process handles */
1600 res = timedwait_signal_poll_cond (cond, mutex, timeout, alertable);
1601 } else {
1602 if (timeout)
1603 res = mono_cond_timedwait (cond, mutex, timeout);
1604 else
1605 res = mono_cond_wait (cond, mutex);
1608 if (alertable)
1609 wapi_thread_clear_wait_handle (handle);
1611 return res;
1615 gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
1616 guint32 new_sharemode,
1617 guint32 new_access,
1618 guint32 *old_sharemode,
1619 guint32 *old_access,
1620 struct _WapiFileShare **share_info)
1622 struct _WapiFileShare *file_share;
1623 guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1624 int thr_ret, i, first_unused = -1;
1625 gboolean exists = FALSE;
1627 /* Prevents entries from expiring under us as we search
1629 thr_ret = _wapi_handle_lock_shared_handles ();
1630 g_assert (thr_ret == 0);
1632 /* Prevent new entries racing with us */
1633 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1634 g_assert (thr_ret == 0);
1636 /* If a linear scan gets too slow we'll have to fit a hash
1637 * table onto the shared mem backing store
1639 *share_info = NULL;
1640 for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
1641 file_share = &_wapi_fileshare_layout->share_info[i];
1643 /* Make a note of an unused slot, in case we need to
1644 * store share info
1646 if (first_unused == -1 && file_share->handle_refs == 0) {
1647 first_unused = i;
1648 continue;
1651 if (file_share->handle_refs == 0) {
1652 continue;
1655 if (file_share->device == device &&
1656 file_share->inode == inode) {
1657 *old_sharemode = file_share->sharemode;
1658 *old_access = file_share->access;
1659 *share_info = file_share;
1661 /* Increment the reference count while we
1662 * still have sole access to the shared area.
1663 * This makes the increment atomic wrt
1664 * collections
1666 InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1668 exists = TRUE;
1669 break;
1673 if (!exists) {
1674 if (i == _WAPI_FILESHARE_SIZE && first_unused == -1) {
1675 /* No more space */
1676 } else {
1677 if (first_unused == -1) {
1678 file_share = &_wapi_fileshare_layout->share_info[++i];
1679 _wapi_fileshare_layout->hwm = i;
1680 } else {
1681 file_share = &_wapi_fileshare_layout->share_info[first_unused];
1684 file_share->device = device;
1685 file_share->inode = inode;
1686 file_share->opened_by_pid = _wapi_getpid ();
1687 file_share->sharemode = new_sharemode;
1688 file_share->access = new_access;
1689 file_share->handle_refs = 1;
1690 *share_info = file_share;
1694 if (*share_info != NULL) {
1695 InterlockedExchange ((gint32 *)&(*share_info)->timestamp, now);
1698 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1700 _wapi_handle_unlock_shared_handles ();
1702 return(exists);
1705 /* If we don't have the info in /proc, check if the process that
1706 * opened this share info is still there (it's not a perfect method,
1707 * due to pid reuse)
1709 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
1711 if (kill (share_info->opened_by_pid, 0) == -1 &&
1712 (errno == ESRCH ||
1713 errno == EPERM)) {
1714 /* It's gone completely (or there's a new process
1715 * owned by someone else) so mark this share info as
1716 * dead
1718 #ifdef DEBUG
1719 g_message ("%s: Didn't find it, destroying entry", __func__);
1720 #endif
1722 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1726 #ifdef __linux__
1727 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1728 * question. If there are none, reset the share info.
1730 * This implementation is Linux-specific; legacy systems will have to
1731 * implement their own ways of finding out if a particular file is
1732 * open by a process.
1734 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1736 gboolean found = FALSE, proc_fds = FALSE;
1737 pid_t self = _wapi_getpid ();
1738 int pid;
1739 int thr_ret, i;
1741 /* Prevents entries from expiring under us if we remove this
1742 * one
1744 thr_ret = _wapi_handle_lock_shared_handles ();
1745 g_assert (thr_ret == 0);
1747 /* Prevent new entries racing with us */
1748 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1749 g_assert (thr_ret == 0);
1751 /* If there is no /proc, there's nothing more we can do here */
1752 if (access ("/proc", F_OK) == -1) {
1753 _wapi_handle_check_share_by_pid (share_info);
1754 goto done;
1757 /* If there's another handle that thinks it owns this fd, then even
1758 * if the fd has been closed behind our back consider it still owned.
1759 * See bugs 75764 and 75891
1761 for (i = 0; i < _wapi_fd_reserve; i++) {
1762 if (_wapi_private_handles [SLOT_INDEX (i)]) {
1763 struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
1765 if (i != fd &&
1766 handle->type == WAPI_HANDLE_FILE) {
1767 struct _WapiHandle_file *file_handle = &handle->u.file;
1769 if (file_handle->share_info == share_info) {
1770 #ifdef DEBUG
1771 g_message ("%s: handle 0x%x has this file open!",
1772 __func__, i);
1773 #endif
1775 goto done;
1781 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
1782 struct _WapiHandleShared *shared;
1783 struct _WapiHandle_process *process_handle;
1785 shared = &_wapi_shared_layout->handles[i];
1787 if (shared->type == WAPI_HANDLE_PROCESS) {
1788 DIR *fd_dir;
1789 struct dirent *fd_entry;
1790 char subdir[_POSIX_PATH_MAX];
1792 process_handle = &shared->u.process;
1793 pid = process_handle->id;
1795 /* Look in /proc/<pid>/fd/ but ignore
1796 * /proc/<our pid>/fd/<fd>, as we have the
1797 * file open too
1799 g_snprintf (subdir, _POSIX_PATH_MAX, "/proc/%d/fd",
1800 pid);
1802 fd_dir = opendir (subdir);
1803 if (fd_dir == NULL) {
1804 continue;
1807 #ifdef DEBUG
1808 g_message ("%s: Looking in %s", __func__, subdir);
1809 #endif
1811 proc_fds = TRUE;
1813 while ((fd_entry = readdir (fd_dir)) != NULL) {
1814 char path[_POSIX_PATH_MAX];
1815 struct stat link_stat;
1817 if (!strcmp (fd_entry->d_name, ".") ||
1818 !strcmp (fd_entry->d_name, "..") ||
1819 (pid == self &&
1820 fd == atoi (fd_entry->d_name))) {
1821 continue;
1824 g_snprintf (path, _POSIX_PATH_MAX,
1825 "/proc/%d/fd/%s", pid,
1826 fd_entry->d_name);
1828 stat (path, &link_stat);
1829 if (link_stat.st_dev == share_info->device &&
1830 link_stat.st_ino == share_info->inode) {
1831 #ifdef DEBUG
1832 g_message ("%s: Found it at %s",
1833 __func__, path);
1834 #endif
1836 found = TRUE;
1840 closedir (fd_dir);
1844 if (proc_fds == FALSE) {
1845 _wapi_handle_check_share_by_pid (share_info);
1846 } else if (found == FALSE) {
1847 /* Blank out this entry, as it is stale */
1848 #ifdef DEBUG
1849 g_message ("%s: Didn't find it, destroying entry", __func__);
1850 #endif
1852 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1855 done:
1856 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1858 _wapi_handle_unlock_shared_handles ();
1860 #else
1862 // Other implementations (non-Linux)
1864 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1866 int thr_ret;
1868 /* Prevents entries from expiring under us if we remove this
1869 * one */
1870 thr_ret = _wapi_handle_lock_shared_handles ();
1871 g_assert (thr_ret == 0);
1873 /* Prevent new entries racing with us */
1874 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1875 g_assert (thr_ret == 0);
1877 _wapi_handle_check_share_by_pid (share_info);
1879 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1880 _wapi_handle_unlock_shared_handles ();
1882 #endif
1884 void _wapi_handle_dump (void)
1886 struct _WapiHandleUnshared *handle_data;
1887 guint32 i, k;
1888 int thr_ret;
1890 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
1891 (void *)&scan_mutex);
1892 thr_ret = mono_mutex_lock (&scan_mutex);
1893 g_assert (thr_ret == 0);
1895 for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1896 if (_wapi_private_handles [i]) {
1897 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1898 handle_data = &_wapi_private_handles [i][k];
1900 if (handle_data->type == WAPI_HANDLE_UNUSED) {
1901 continue;
1904 g_print ("%3x [%7s] %s %d ",
1905 i * _WAPI_HANDLE_INITIAL_COUNT + k,
1906 _wapi_handle_typename[handle_data->type],
1907 handle_data->signalled?"Sg":"Un",
1908 handle_data->ref);
1909 handle_details[handle_data->type](&handle_data->u);
1910 g_print ("\n");
1915 thr_ret = mono_mutex_unlock (&scan_mutex);
1916 g_assert (thr_ret == 0);
1917 pthread_cleanup_pop (0);
1920 static void _wapi_shared_details (gpointer handle_info)
1922 struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1924 g_print ("offset: 0x%x", shared->offset);
1927 void _wapi_handle_update_refs (void)
1929 guint32 i, k;
1930 int thr_ret;
1931 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1933 thr_ret = _wapi_handle_lock_shared_handles ();
1934 g_assert (thr_ret == 0);
1936 /* Prevent file share entries racing with us */
1937 thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1938 g_assert(thr_ret == 0);
1940 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
1941 (void *)&scan_mutex);
1942 thr_ret = mono_mutex_lock (&scan_mutex);
1944 for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1945 if (_wapi_private_handles [i]) {
1946 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1947 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
1949 if (_WAPI_SHARED_HANDLE(handle->type)) {
1950 struct _WapiHandleShared *shared_data;
1952 #ifdef DEBUG
1953 g_message ("%s: (%d) handle 0x%x is SHARED (%s)", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
1954 #endif
1956 shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
1958 #ifdef DEBUG
1959 g_message ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
1960 #endif
1962 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1963 } else if (handle->type == WAPI_HANDLE_FILE) {
1964 struct _WapiHandle_file *file_handle = &handle->u.file;
1966 #ifdef DEBUG
1967 g_message ("%s: (%d) handle 0x%x is FILE", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
1968 #endif
1970 g_assert (file_handle->share_info != NULL);
1972 #ifdef DEBUG
1973 g_message ("%s: (%d) Inc refs on fileshare 0x%x", __func__, _wapi_getpid (), (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
1974 #endif
1976 InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
1982 thr_ret = mono_mutex_unlock (&scan_mutex);
1983 g_assert (thr_ret == 0);
1984 pthread_cleanup_pop (0);
1986 thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1988 _wapi_handle_unlock_shared_handles ();