2 * handles.c: Generic and internal operations on handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002-2006 Novell, Inc.
16 #include <sys/types.h>
17 #ifdef HAVE_SYS_SOCKET_H
18 # include <sys/socket.h>
23 #ifdef HAVE_SYS_MMAN_H
24 # include <sys/mman.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>
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
]={
61 &_wapi_namedmutex_ops
,
63 &_wapi_namedevent_ops
,
66 static void _wapi_shared_details (gpointer handle_info
);
68 static void (*handle_details
[WAPI_HANDLE_COUNT
])(gpointer
) = {
71 _wapi_console_details
,
72 _wapi_shared_details
, /* thread */
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 */
80 _wapi_shared_details
, /* namedmutex */
81 _wapi_shared_details
, /* namedsem */
82 _wapi_shared_details
, /* namedevent */
85 const char *_wapi_handle_typename
[] = {
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
;
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
);
155 static mono_mutex_t scan_mutex
= MONO_MUTEX_INITIALIZER
;
157 static void handle_cleanup (void)
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
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
193 _wapi_thread_set_termination_details (handle
, 0);
196 for(k
= handle_data
->ref
; k
> 0; k
--) {
198 g_message ("%s: unreffing %s handle %p", __func__
, _wapi_handle_typename
[type
], handle
);
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);
234 * The entries in _wapi_private_handles reserved for fds are allocated lazily to
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
267 g_atexit (handle_cleanup
);
270 static void _wapi_handle_init_shared (struct _WapiHandleShared
*handle
,
272 gpointer handle_specific
)
274 g_assert (_wapi_has_shut_down
== FALSE
);
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
)
291 g_assert (_wapi_has_shut_down
== FALSE
);
294 handle
->signalled
= FALSE
;
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
,
311 static guint32
_wapi_handle_new_shared (WapiHandleType type
,
312 gpointer handle_specific
)
315 static guint32 last
= 1;
318 g_assert (_wapi_has_shut_down
== FALSE
);
320 /* Leave the first slot empty as a guard */
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
) {
333 _wapi_handle_init_shared (handle
, type
,
336 _wapi_handle_unlock_shared_handles ();
340 /* Someone else beat us to it, just
345 _wapi_handle_unlock_shared_handles ();
350 /* Try again from the beginning */
355 /* Will need to expand the array. The caller will sort it out */
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
)
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
383 if (last
< _wapi_fd_reserve
) {
384 last
= _wapi_fd_reserve
;
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
) {
399 _wapi_handle_init (handle
, type
, handle_specific
);
407 if(retry
&& last
> _wapi_fd_reserve
) {
408 /* Try again from the beginning */
409 last
= _wapi_fd_reserve
;
413 /* Will need to expand the array. The caller will sort it out */
418 static gpointer
_wapi_handle_real_new (WapiHandleType type
, gpointer handle_specific
)
420 guint32 handle_idx
= 0;
425 g_message ("%s: Creating new handle of type %s", __func__
,
426 _wapi_handle_typename
[type
]);
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
) {
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
;
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
);
466 g_message ("%s: Allocated new handle %p", __func__
, handle
);
469 if (_WAPI_SHARED_HANDLE(type
)) {
470 /* Add the shared section too */
473 ref
= _wapi_handle_new_shared (type
, handle_specific
);
475 _wapi_handle_collect ();
476 ref
= _wapi_handle_new_shared (type
, handle_specific
);
478 /* FIXME: grow the arrays */
479 handle
= _WAPI_HANDLE_INVALID
;
484 _WAPI_PRIVATE_HANDLES(handle_idx
).u
.shared
.offset
= ref
;
486 g_message ("%s: New shared handle at offset 0x%x", __func__
,
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
,
507 guint32 handle_idx
= 0;
508 gpointer handle
= INVALID_HANDLE_VALUE
;
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
);
518 g_message ("%s: Creating new handle of type %s to offset %d", __func__
,
519 _wapi_handle_typename
[type
], offset
);
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
];
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
;
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
);
560 g_message ("%s: Returning old handle %p referencing 0x%x",
561 __func__
, handle
, offset
);
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 */
573 g_message ("%s: Handle at 0x%x unused", __func__
, offset
);
578 if (shared
->type
!= type
) {
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
]);
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
);
616 g_message ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__
, handle
, offset
, shared
->handle_refs
);
620 _wapi_handle_unlock_shared_handles ();
626 init_handles_slot (int idx
)
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
;
652 g_assert (_wapi_has_shut_down
== FALSE
);
654 mono_once (&shared_init_once
, shared_init
);
657 g_message ("%s: Creating new handle of type %s", __func__
,
658 _wapi_handle_typename
[type
]);
661 g_assert(_WAPI_FD_HANDLE(type
));
662 g_assert(!_WAPI_SHARED_HANDLE(type
));
664 if (fd
>= _wapi_fd_reserve
) {
666 g_message ("%s: fd %d is too big", __func__
, fd
);
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
) {
680 g_message ("%s: fd %d is already in use!", __func__
, fd
);
682 /* FIXME: clean up this handle? We can't do anything
683 * with the fd, cos thats the new one
688 g_message ("%s: Assigning new fd handle %d", __func__
, fd
);
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
)) {
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
) {
724 if (handle_specific
== NULL
) {
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
741 *handle_specific
= &shared_handle_data
->u
;
743 *handle_specific
= &handle_data
->u
;
750 _wapi_handle_foreach (WapiHandleType type
,
751 gboolean (*on_each
)(gpointer test
, gpointer user
),
754 struct _WapiHandleUnshared
*handle_data
= NULL
;
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
)
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
790 gpointer
_wapi_search_handle (WapiHandleType type
,
791 gboolean (*check
)(gpointer test
, gpointer user
),
793 gpointer
*handle_specific
,
794 gboolean search_shared
)
796 struct _WapiHandleUnshared
*handle_data
= NULL
;
797 struct _WapiHandleShared
*shared
= NULL
;
800 gboolean found
= FALSE
;
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
);
819 if (_WAPI_SHARED_HANDLE (type
)) {
820 shared
= &_wapi_shared_layout
->handles
[i
];
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 */
837 g_message ("%s: Looking at other shared handles...", __func__
);
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
850 ret
= _wapi_handle_new_from_offset (type
, i
,
852 if (ret
== INVALID_HANDLE_VALUE
) {
853 /* This handle was deleted
854 * while we were looking at it
860 g_message ("%s: Opened tmp handle %p (type %s) from offset %d", __func__
, ret
, _wapi_handle_typename
[type
], i
);
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
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
);
884 handle_data
= &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret
));
886 _wapi_handle_unlock_shared_handles ();
889 /* It's been deleted,
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
);
911 if(handle_specific
!= NULL
) {
912 if (_WAPI_SHARED_HANDLE(type
)) {
913 g_assert(shared
->type
== type
);
915 *handle_specific
= &shared
->u
;
917 *handle_specific
= &handle_data
->u
;
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
,
931 struct _WapiHandleShared
*shared_handle_data
;
936 g_assert(_WAPI_SHARED_HANDLE(type
));
939 g_message ("%s: Lookup for handle named [%s] type %s", __func__
,
940 utf8_name
, _wapi_handle_typename
[type
]);
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
)) {
965 g_message ("%s: found a shared namespace handle at 0x%x (type %s)", __func__
, i
, _wapi_handle_typename
[shared_handle_data
->type
]);
968 sharedns
=(WapiSharedNamespace
*)&shared_handle_data
->u
;
971 g_message ("%s: name is [%s]", __func__
, sharedns
->name
);
974 if (strcmp (sharedns
->name
, utf8_name
) == 0) {
975 if (shared_handle_data
->type
!= type
) {
976 /* Its the wrong type, so fail now */
978 g_message ("%s: handle 0x%x matches name but is wrong type: %s", __func__
, i
, _wapi_handle_typename
[shared_handle_data
->type
]);
984 g_message ("%s: handle 0x%x matches name and type", __func__
, i
);
993 _wapi_handle_unlock_shared_handles ();
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
)) {
1008 if (_wapi_handle_type (handle
) == WAPI_HANDLE_UNUSED
) {
1009 g_warning ("%s: Attempting to ref unused handle %p", __func__
,
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
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
);
1030 g_message ("%s: %s handle %p ref now %d", __func__
,
1031 _wapi_handle_typename
[_WAPI_PRIVATE_HANDLES (idx
).type
],
1033 _WAPI_PRIVATE_HANDLES(idx
).ref
);
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
;
1044 if (!_WAPI_PRIVATE_VALID_SLOT (idx
)) {
1048 if (_wapi_handle_type (handle
) == WAPI_HANDLE_UNUSED
) {
1049 g_warning ("%s: Attempting to unref unused handle %p",
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);
1062 g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__
,
1063 _wapi_handle_typename
[_WAPI_PRIVATE_HANDLES (idx
).type
],
1065 _WAPI_PRIVATE_HANDLES(idx
).ref
, destroy
?"TRUE":"FALSE");
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
);
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
);
1094 g_message ("%s: Destroying handle %p", __func__
, handle
);
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
;
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);
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
1126 g_message ("%s: %s handle %p shared refs before dec %d", __func__
, _wapi_handle_typename
[type
], handle
, shared
->handle_refs
);
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);
1142 _wapi_handle_unlock_shared_handles ();
1145 if (close_func
!= NULL
) {
1147 close_func (handle
, &shared_handle_data
.u
);
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
)) {
1171 type
= _WAPI_PRIVATE_HANDLES(idx
).type
;
1174 g_message ("%s: testing 0x%x against 0x%x (%d)", __func__
,
1175 handle_caps
[type
], caps
, handle_caps
[type
] & caps
);
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
);
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
)) {
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
)) {
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
)) {
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
));
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
)) {
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
));
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
));
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
)) {
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
);
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
1317 if (_WAPI_PRIVATE_HANDLES (0).type
!= WAPI_HANDLE_CONSOLE
) {
1318 SetLastError (ERROR_INVALID_PARAMETER
);
1322 if (handle
== _WAPI_HANDLE_INVALID
){
1323 SetLastError (ERROR_INVALID_PARAMETER
);
1327 _wapi_handle_unref (handle
);
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
);
1344 if (src
== _WAPI_PROCESS_CURRENT
) {
1345 *target
= _wapi_process_duplicate ();
1346 } else if (src
== _WAPI_THREAD_CURRENT
) {
1347 *target
= _wapi_thread_duplicate ();
1349 _wapi_handle_ref (src
);
1356 gboolean
_wapi_handle_count_signalled_handles (guint32 numhandles
,
1362 guint32 count
, i
, iter
=0;
1365 WapiHandleType type
;
1367 /* Lock all the handles, with backoff */
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
);
1377 g_message ("%s: attempting to lock %p", __func__
, handle
);
1380 type
= _WAPI_PRIVATE_HANDLES(idx
).type
;
1382 thr_ret
= _wapi_handle_trylock_handle (handle
);
1388 g_message ("%s: attempt failed for %p: %s", __func__
,
1389 handle
, strerror (thr_ret
));
1392 thr_ret
= _wapi_handle_unlock_shared_handles ();
1393 g_assert (thr_ret
== 0);
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.
1409 g_warning ("%s: iteration overflow!",
1415 g_message ("%s: Backing off for %d ms", __func__
,
1418 _wapi_handle_spin (10 * iter
);
1425 g_message ("%s: Locked all handles", __func__
);
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
;
1438 g_message ("%s: Checking handle %p", __func__
, handle
);
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
)) {
1450 g_message ("%s: Handle %p signalled", __func__
,
1460 g_message ("%s: %d event handles signalled", __func__
, count
);
1463 if ((waitall
== TRUE
&& count
== numhandles
) ||
1464 (waitall
== FALSE
&& count
> 0)) {
1471 g_message ("%s: Returning %d", __func__
, ret
);
1479 void _wapi_handle_unlock_handles (guint32 numhandles
, gpointer
*handles
)
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
];
1491 g_message ("%s: unlocking handle %p", __func__
, handle
);
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
;
1506 ret
=mono_cond_timedwait (cond
, mutex
, timeout
);
1508 ret
=mono_cond_wait (cond
, mutex
);
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
);
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
) {
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
)
1545 g_message ("%s: waiting for %p", __func__
, handle
);
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
)
1555 g_message ("%s: waiting for %p (type %s)", __func__
, handle
,
1556 _wapi_handle_typename
[_wapi_handle_type (handle
)]);
1559 if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle
))) {
1560 if (WAPI_SHARED_HANDLE_DATA(handle
).signalled
== TRUE
) {
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
) {
1583 _wapi_handle_spin (100);
1587 guint32 idx
= GPOINTER_TO_UINT(handle
);
1589 pthread_cond_t
*cond
;
1590 mono_mutex_t
*mutex
;
1592 if (alertable
&& !wapi_thread_set_wait_handle (handle
))
1595 cond
= &_WAPI_PRIVATE_HANDLES (idx
).signal_cond
;
1596 mutex
= &_WAPI_PRIVATE_HANDLES (idx
).signal_mutex
;
1599 /* This is needed when waiting for process handles */
1600 res
= timedwait_signal_poll_cond (cond
, mutex
, timeout
, alertable
);
1603 res
= mono_cond_timedwait (cond
, mutex
, timeout
);
1605 res
= mono_cond_wait (cond
, mutex
);
1609 wapi_thread_clear_wait_handle (handle
);
1615 gboolean
_wapi_handle_get_or_set_share (dev_t device
, ino_t inode
,
1616 guint32 new_sharemode
,
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
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
1646 if (first_unused
== -1 && file_share
->handle_refs
== 0) {
1651 if (file_share
->handle_refs
== 0) {
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
1666 InterlockedIncrement ((gint32
*)&file_share
->handle_refs
);
1674 if (i
== _WAPI_FILESHARE_SIZE
&& first_unused
== -1) {
1677 if (first_unused
== -1) {
1678 file_share
= &_wapi_fileshare_layout
->share_info
[++i
];
1679 _wapi_fileshare_layout
->hwm
= i
;
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 ();
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,
1709 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare
*share_info
)
1711 if (kill (share_info
->opened_by_pid
, 0) == -1 &&
1714 /* It's gone completely (or there's a new process
1715 * owned by someone else) so mark this share info as
1719 g_message ("%s: Didn't find it, destroying entry", __func__
);
1722 memset (share_info
, '\0', sizeof(struct _WapiFileShare
));
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 ();
1741 /* Prevents entries from expiring under us if we remove this
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
);
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
);
1766 handle
->type
== WAPI_HANDLE_FILE
) {
1767 struct _WapiHandle_file
*file_handle
= &handle
->u
.file
;
1769 if (file_handle
->share_info
== share_info
) {
1771 g_message ("%s: handle 0x%x has this file open!",
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
) {
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
1799 g_snprintf (subdir
, _POSIX_PATH_MAX
, "/proc/%d/fd",
1802 fd_dir
= opendir (subdir
);
1803 if (fd_dir
== NULL
) {
1808 g_message ("%s: Looking in %s", __func__
, subdir
);
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
, "..") ||
1820 fd
== atoi (fd_entry
->d_name
))) {
1824 g_snprintf (path
, _POSIX_PATH_MAX
,
1825 "/proc/%d/fd/%s", pid
,
1828 stat (path
, &link_stat
);
1829 if (link_stat
.st_dev
== share_info
->device
&&
1830 link_stat
.st_ino
== share_info
->inode
) {
1832 g_message ("%s: Found it at %s",
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 */
1849 g_message ("%s: Didn't find it, destroying entry", __func__
);
1852 memset (share_info
, '\0', sizeof(struct _WapiFileShare
));
1856 thr_ret
= _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE
);
1858 _wapi_handle_unlock_shared_handles ();
1862 // Other implementations (non-Linux)
1864 void _wapi_handle_check_share (struct _WapiFileShare
*share_info
, int fd
)
1868 /* Prevents entries from expiring under us if we remove this
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 ();
1884 void _wapi_handle_dump (void)
1886 struct _WapiHandleUnshared
*handle_data
;
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
) {
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",
1909 handle_details
[handle_data
->type
](&handle_data
->u
);
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)
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
;
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
]);
1956 shared_data
= &_wapi_shared_layout
->handles
[handle
->u
.shared
.offset
];
1959 g_message ("%s: (%d) Updating timestamp of handle 0x%x", __func__
, _wapi_getpid (), handle
->u
.shared
.offset
);
1962 InterlockedExchange ((gint32
*)&shared_data
->timestamp
, now
);
1963 } else if (handle
->type
== WAPI_HANDLE_FILE
) {
1964 struct _WapiHandle_file
*file_handle
= &handle
->u
.file
;
1967 g_message ("%s: (%d) handle 0x%x is FILE", __func__
, _wapi_getpid (), i
* _WAPI_HANDLE_INITIAL_COUNT
+ k
);
1970 g_assert (file_handle
->share_info
!= NULL
);
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
));
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 ();