[xbuild] Rename method to make it more consistent.
[mono.git] / mono / io-layer / handles.c
1 /*
2  * handles.c:  Generic and internal operations on handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002-2006 Novell, Inc.
8  */
9
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>
30
31 #include <mono/io-layer/wapi.h>
32 #include <mono/io-layer/wapi-private.h>
33 #include <mono/io-layer/handles-private.h>
34 #include <mono/io-layer/mono-mutex.h>
35 #include <mono/io-layer/misc-private.h>
36 #include <mono/io-layer/shared.h>
37 #include <mono/io-layer/collection.h>
38 #include <mono/io-layer/process-private.h>
39 #include <mono/io-layer/critical-section-private.h>
40
41 #undef DEBUG
42 #undef DEBUG_REFS
43
44 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
45
46 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
47 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
48         NULL,
49         &_wapi_file_ops,
50         &_wapi_console_ops,
51         &_wapi_thread_ops,
52         &_wapi_sem_ops,
53         &_wapi_mutex_ops,
54         &_wapi_event_ops,
55 #ifndef DISABLE_SOCKETS
56         &_wapi_socket_ops,
57 #endif
58         &_wapi_find_ops,
59         &_wapi_process_ops,
60         &_wapi_pipe_ops,
61         &_wapi_namedmutex_ops,
62         &_wapi_namedsem_ops,
63         &_wapi_namedevent_ops,
64 };
65
66 static void _wapi_shared_details (gpointer handle_info);
67
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 */
83 };
84
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!!"
101 };
102
103 /*
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.
106  */
107 #define SLOT_INDEX(x)   (x / _WAPI_HANDLE_INITIAL_COUNT)
108 #define SLOT_OFFSET(x)  (x % _WAPI_HANDLE_INITIAL_COUNT)
109
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;
113
114 struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
115
116 /*
117  * If SHM is enabled, this will point to shared memory, otherwise it will be NULL.
118  */
119 struct _WapiFileShareLayout *_wapi_fileshare_layout = NULL;
120
121 /*
122  * If SHM is disabled, this will point to a hash of _WapiFileShare structures, otherwise
123  * it will be NULL. We use this instead of _wapi_fileshare_layout to avoid allocating a
124  * 4MB array.
125  */
126 static GHashTable *file_share_hash;
127 static CRITICAL_SECTION file_share_hash_mutex;
128
129 #define file_share_hash_lock() EnterCriticalSection (&file_share_hash_mutex)
130 #define file_share_hash_unlock() LeaveCriticalSection (&file_share_hash_mutex)
131
132 guint32 _wapi_fd_reserve;
133
134 /* 
135  * This is an internal handle which is used for handling waiting for multiple handles.
136  * Threads which wait for multiple handles wait on this one handle, and when a handle
137  * is signalled, this handle is signalled too.
138  */
139 static gpointer _wapi_global_signal_handle;
140
141 /* Point to the mutex/cond inside _wapi_global_signal_handle */
142 mono_mutex_t *_wapi_global_signal_mutex;
143 pthread_cond_t *_wapi_global_signal_cond;
144
145 int _wapi_sem_id;
146 gboolean _wapi_has_shut_down = FALSE;
147
148 /* Use this instead of getpid(), to cope with linuxthreads.  It's a
149  * function rather than a variable lookup because we need to get at
150  * this before share_init() might have been called.
151  */
152 static pid_t _wapi_pid;
153 static mono_once_t pid_init_once = MONO_ONCE_INIT;
154
155 static gpointer _wapi_handle_real_new (WapiHandleType type, gpointer handle_specific);
156
157 static void pid_init (void)
158 {
159         _wapi_pid = getpid ();
160 }
161
162 pid_t _wapi_getpid (void)
163 {
164         mono_once (&pid_init_once, pid_init);
165         
166         return(_wapi_pid);
167 }
168
169
170 static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
171
172 static void handle_cleanup (void)
173 {
174         int i, j, k;
175         
176         _wapi_process_signal_self ();
177
178         /* Every shared handle we were using ought really to be closed
179          * by now, but to make sure just blow them all away.  The
180          * exiting finalizer thread in particular races us to the
181          * program exit and doesn't always win, so it can be left
182          * cluttering up the shared file.  Anything else left over is
183          * really a bug.
184          */
185         for(i = SLOT_INDEX (0); _wapi_private_handles[i] != NULL; i++) {
186                 for(j = SLOT_OFFSET (0); j < _WAPI_HANDLE_INITIAL_COUNT; j++) {
187                         struct _WapiHandleUnshared *handle_data = &_wapi_private_handles[i][j];
188                         int type = handle_data->type;
189                         gpointer handle = GINT_TO_POINTER (i*_WAPI_HANDLE_INITIAL_COUNT+j);
190                         
191                         if (_WAPI_SHARED_HANDLE (type)) {
192                                 if (type == WAPI_HANDLE_THREAD) {
193                                         /* Special-case thread handles
194                                          * because they need extra
195                                          * cleanup.  This also avoids
196                                          * a race condition between
197                                          * the application exit and
198                                          * the finalizer thread - if
199                                          * it finishes up between now
200                                          * and actual app termination
201                                          * it will find all its handle
202                                          * details have been blown
203                                          * away, so this sets those
204                                          * anyway.
205                                          */
206                                         _wapi_thread_set_termination_details (handle, 0);
207                                 }
208                         }
209                                 
210                         for(k = handle_data->ref; k > 0; k--) {
211 #ifdef DEBUG
212                                 g_message ("%s: unreffing %s handle %p", __func__, _wapi_handle_typename[type], handle);
213 #endif
214                                         
215                                 _wapi_handle_unref (handle);
216                         }
217                 }
218         }
219         
220         _wapi_shm_semaphores_remove ();
221
222         _wapi_shm_detach (WAPI_SHM_DATA);
223         _wapi_shm_detach (WAPI_SHM_FILESHARE);
224
225         if (file_share_hash) {
226                 g_hash_table_destroy (file_share_hash);
227                 DeleteCriticalSection (&file_share_hash_mutex);
228         }
229
230         for (i = 0; i < _WAPI_PRIVATE_MAX_SLOTS; ++i)
231                 g_free (_wapi_private_handles [i]);
232 }
233
234 void _wapi_cleanup ()
235 {
236         g_assert (_wapi_has_shut_down == FALSE);
237         
238         _wapi_has_shut_down = TRUE;
239
240         _wapi_critical_section_cleanup ();
241         _wapi_error_cleanup ();
242         _wapi_thread_cleanup ();
243 }
244
245 static mono_once_t shared_init_once = MONO_ONCE_INIT;
246 static void shared_init (void)
247 {
248         g_assert ((sizeof (handle_ops) / sizeof (handle_ops[0]))
249                   == WAPI_HANDLE_COUNT);
250         
251         _wapi_fd_reserve = getdtablesize();
252
253         /* This is needed by the code in _wapi_handle_new_internal */
254         _wapi_fd_reserve = (_wapi_fd_reserve + (_WAPI_HANDLE_INITIAL_COUNT - 1)) & ~(_WAPI_HANDLE_INITIAL_COUNT - 1);
255
256         do {
257                 /* 
258                  * The entries in _wapi_private_handles reserved for fds are allocated lazily to 
259                  * save memory.
260                  */
261                 /*
262                 _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
263                                                         _WAPI_HANDLE_INITIAL_COUNT);
264                 */
265
266                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
267                 _wapi_private_handle_slot_count ++;
268         } while(_wapi_fd_reserve > _wapi_private_handle_count);
269
270         _wapi_shm_semaphores_init ();
271         
272         _wapi_shared_layout = _wapi_shm_attach (WAPI_SHM_DATA);
273         g_assert (_wapi_shared_layout != NULL);
274         
275         if (_wapi_shm_enabled ()) {
276                 /* This allocates a 4mb array, so do it only if SHM is enabled */
277                 _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
278                 g_assert (_wapi_fileshare_layout != NULL);
279         }
280         
281 #if !defined (DISABLE_SHARED_HANDLES)
282         if (_wapi_shm_enabled ())
283                 _wapi_collection_init ();
284 #endif
285
286         /* Can't call wapi_handle_new as it calls us recursively */
287         _wapi_global_signal_handle = _wapi_handle_real_new (WAPI_HANDLE_EVENT, NULL);
288
289         _wapi_global_signal_cond = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_cond;
290         _wapi_global_signal_mutex = &_WAPI_PRIVATE_HANDLES (GPOINTER_TO_UINT (_wapi_global_signal_handle)).signal_mutex;
291
292         /* Using g_atexit here instead of an explicit function call in
293          * a cleanup routine lets us cope when a third-party library
294          * calls exit (eg if an X client loses the connection to its
295          * server.)
296          */
297         g_atexit (handle_cleanup);
298 }
299
300 static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
301                                       WapiHandleType type,
302                                       gpointer handle_specific)
303 {
304         g_assert (_wapi_has_shut_down == FALSE);
305         
306         handle->type = type;
307         handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
308         handle->signalled = FALSE;
309         handle->handle_refs = 1;
310         
311         if (handle_specific != NULL) {
312                 memcpy (&handle->u, handle_specific, sizeof (handle->u));
313         }
314 }
315
316 static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
317                                WapiHandleType type, gpointer handle_specific)
318 {
319         int thr_ret;
320         
321         g_assert (_wapi_has_shut_down == FALSE);
322         
323         handle->type = type;
324         handle->signalled = FALSE;
325         handle->ref = 1;
326         
327         if (!_WAPI_SHARED_HANDLE(type)) {
328                 thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
329                 g_assert (thr_ret == 0);
330                                 
331                 thr_ret = mono_mutex_init (&handle->signal_mutex, NULL);
332                 g_assert (thr_ret == 0);
333
334                 if (handle_specific != NULL) {
335                         memcpy (&handle->u, handle_specific,
336                                 sizeof (handle->u));
337                 }
338         }
339 }
340
341 static guint32 _wapi_handle_new_shared (WapiHandleType type,
342                                         gpointer handle_specific)
343 {
344         guint32 offset;
345         static guint32 last = 1;
346         int thr_ret;
347         
348         g_assert (_wapi_has_shut_down == FALSE);
349         
350         /* Leave the first slot empty as a guard */
351 again:
352         /* FIXME: expandable array */
353         for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT; offset++) {
354                 struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
355                 
356                 if(handle->type == WAPI_HANDLE_UNUSED) {
357                         thr_ret = _wapi_handle_lock_shared_handles ();
358                         g_assert (thr_ret == 0);
359                         
360                         if (InterlockedCompareExchange ((gint32 *)&handle->type, type, WAPI_HANDLE_UNUSED) == WAPI_HANDLE_UNUSED) {
361                                 last = offset + 1;
362                         
363                                 _wapi_handle_init_shared (handle, type,
364                                                           handle_specific);
365
366                                 _wapi_handle_unlock_shared_handles ();
367                                 
368                                 return(offset);
369                         } else {
370                                 /* Someone else beat us to it, just
371                                  * continue looking
372                                  */
373                         }
374
375                         _wapi_handle_unlock_shared_handles ();
376                 }
377         }
378
379         if(last > 1) {
380                 /* Try again from the beginning */
381                 last = 1;
382                 goto again;
383         }
384
385         /* Will need to expand the array.  The caller will sort it out */
386
387         return(0);
388 }
389
390 /*
391  * _wapi_handle_new_internal:
392  * @type: Init handle to this type
393  *
394  * Search for a free handle and initialize it. Return the handle on
395  * success and 0 on failure.  This is only called from
396  * _wapi_handle_new, and scan_mutex must be held.
397  */
398 static guint32 _wapi_handle_new_internal (WapiHandleType type,
399                                           gpointer handle_specific)
400 {
401         guint32 i, k, count;
402         static guint32 last = 0;
403         gboolean retry = FALSE;
404         
405         g_assert (_wapi_has_shut_down == FALSE);
406         
407         /* A linear scan should be fast enough.  Start from the last
408          * allocation, assuming that handles are allocated more often
409          * than they're freed. Leave the space reserved for file
410          * descriptors
411          */
412         
413         if (last < _wapi_fd_reserve) {
414                 last = _wapi_fd_reserve;
415         } else {
416                 retry = TRUE;
417         }
418
419 again:
420         count = last;
421         for(i = SLOT_INDEX (count); i < _wapi_private_handle_slot_count; i++) {
422                 if (_wapi_private_handles [i]) {
423                         for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
424                                 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
425
426                                 if(handle->type == WAPI_HANDLE_UNUSED) {
427                                         last = count + 1;
428                         
429                                         _wapi_handle_init (handle, type, handle_specific);
430                                         return (count);
431                                 }
432                                 count++;
433                         }
434                 }
435         }
436
437         if(retry && last > _wapi_fd_reserve) {
438                 /* Try again from the beginning */
439                 last = _wapi_fd_reserve;
440                 goto again;
441         }
442
443         /* Will need to expand the array.  The caller will sort it out */
444
445         return(0);
446 }
447
448 static gpointer _wapi_handle_real_new (WapiHandleType type, gpointer handle_specific)
449 {
450         guint32 handle_idx = 0;
451         gpointer handle;
452         int thr_ret;
453         
454 #ifdef DEBUG
455         g_message ("%s: Creating new handle of type %s", __func__,
456                    _wapi_handle_typename[type]);
457 #endif
458
459         g_assert(!_WAPI_FD_HANDLE(type));
460         
461         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
462                               (void *)&scan_mutex);
463         thr_ret = mono_mutex_lock (&scan_mutex);
464         g_assert (thr_ret == 0);
465                 
466         while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
467                 /* Try and expand the array, and have another go */
468                 int idx = SLOT_INDEX (_wapi_private_handle_count);
469                 if (idx >= _WAPI_PRIVATE_MAX_SLOTS) {
470                         break;
471                 }
472
473                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
474                                                 _WAPI_HANDLE_INITIAL_COUNT);
475
476                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
477                 _wapi_private_handle_slot_count ++;
478         }
479         
480         thr_ret = mono_mutex_unlock (&scan_mutex);
481         g_assert (thr_ret == 0);
482         pthread_cleanup_pop (0);
483
484         if (handle_idx == 0) {
485                 /* We ran out of slots */
486                 handle = _WAPI_HANDLE_INVALID;
487                 goto done;
488         }
489                 
490         /* Make sure we left the space for fd mappings */
491         g_assert (handle_idx >= _wapi_fd_reserve);
492         
493         handle = GUINT_TO_POINTER (handle_idx);
494
495 #ifdef DEBUG
496         g_message ("%s: Allocated new handle %p", __func__, handle);
497 #endif
498         
499         if (_WAPI_SHARED_HANDLE(type)) {
500                 /* Add the shared section too */
501                 guint32 ref;
502                 
503                 ref = _wapi_handle_new_shared (type, handle_specific);
504                 if (ref == 0) {
505                         _wapi_handle_collect ();
506                         _wapi_process_reap ();
507                         ref = _wapi_handle_new_shared (type, handle_specific);
508                         if (ref == 0) {
509                                 /* FIXME: grow the arrays */
510                                 handle = _WAPI_HANDLE_INVALID;
511                                 goto done;
512                         }
513                 }
514                 
515                 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
516 #ifdef DEBUG
517                 g_message ("%s: New shared handle at offset 0x%x", __func__,
518                            ref);
519 #endif
520         }
521                 
522 done:
523         return(handle);
524 }
525
526 gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
527 {
528         g_assert (_wapi_has_shut_down == FALSE);
529         
530         mono_once (&shared_init_once, shared_init);
531
532         return _wapi_handle_real_new (type, handle_specific);
533 }
534
535 gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
536                                        gboolean timestamp)
537 {
538         guint32 handle_idx = 0;
539         gpointer handle = INVALID_HANDLE_VALUE;
540         int thr_ret, i, k;
541         struct _WapiHandleShared *shared;
542         
543         g_assert (_wapi_has_shut_down == FALSE);
544         
545         mono_once (&shared_init_once, shared_init);
546
547 #ifdef DEBUG
548         g_message ("%s: Creating new handle of type %s to offset %d", __func__,
549                    _wapi_handle_typename[type], offset);
550 #endif
551
552         g_assert(!_WAPI_FD_HANDLE(type));
553         g_assert(_WAPI_SHARED_HANDLE(type));
554         g_assert(offset != 0);
555
556         shared = &_wapi_shared_layout->handles[offset];
557         if (timestamp) {
558                 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
559                 /* Bump up the timestamp for this offset */
560                 InterlockedExchange ((gint32 *)&shared->timestamp, now);
561         }
562                 
563         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
564                               (void *)&scan_mutex);
565         thr_ret = mono_mutex_lock (&scan_mutex);
566         g_assert (thr_ret == 0);
567
568         for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
569                 if (_wapi_private_handles [i]) {
570                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
571                                 struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
572                 
573                                 if (handle_data->type == type &&
574                                         handle_data->u.shared.offset == offset) {
575                                         handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
576                                         goto first_pass_done;
577                                 }
578                         }
579                 }
580         }
581
582 first_pass_done:
583         thr_ret = mono_mutex_unlock (&scan_mutex);
584         g_assert (thr_ret == 0);
585         pthread_cleanup_pop (0);
586
587         if (handle != INVALID_HANDLE_VALUE) {
588                 _wapi_handle_ref (handle);
589
590 #ifdef DEBUG
591                 g_message ("%s: Returning old handle %p referencing 0x%x",
592                            __func__, handle, offset);
593 #endif
594                 return (handle);
595         }
596
597         /* Prevent entries expiring under us as we search */
598         thr_ret = _wapi_handle_lock_shared_handles ();
599         g_assert (thr_ret == 0);
600         
601         if (shared->type == WAPI_HANDLE_UNUSED) {
602                 /* Someone deleted this handle while we were working */
603 #ifdef DEBUG
604                 g_message ("%s: Handle at 0x%x unused", __func__, offset);
605 #endif
606                 goto done;
607         }
608
609         if (shared->type != type) {
610 #ifdef DEBUG
611                 g_message ("%s: Wrong type at %d 0x%x! Found %s wanted %s",
612                            __func__, offset, offset,
613                            _wapi_handle_typename[shared->type],
614                            _wapi_handle_typename[type]);
615 #endif
616                 goto done;
617         }
618         
619         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
620                               (void *)&scan_mutex);
621         thr_ret = mono_mutex_lock (&scan_mutex);
622         g_assert (thr_ret == 0);
623         
624         while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
625                 /* Try and expand the array, and have another go */
626                 int idx = SLOT_INDEX (_wapi_private_handle_count);
627                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
628                                                 _WAPI_HANDLE_INITIAL_COUNT);
629
630                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
631                 _wapi_private_handle_slot_count ++;
632         }
633                 
634         thr_ret = mono_mutex_unlock (&scan_mutex);
635         g_assert (thr_ret == 0);
636         pthread_cleanup_pop (0);
637                 
638         /* Make sure we left the space for fd mappings */
639         g_assert (handle_idx >= _wapi_fd_reserve);
640         
641         handle = GUINT_TO_POINTER (handle_idx);
642                 
643         _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
644         InterlockedIncrement ((gint32 *)&shared->handle_refs);
645         
646 #ifdef DEBUG
647         g_message ("%s: Allocated new handle %p referencing 0x%x (shared refs %d)", __func__, handle, offset, shared->handle_refs);
648 #endif
649         
650 done:
651         _wapi_handle_unlock_shared_handles ();
652
653         return(handle);
654 }
655
656 static void
657 init_handles_slot (int idx)
658 {
659         int thr_ret;
660
661         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
662                                                   (void *)&scan_mutex);
663         thr_ret = mono_mutex_lock (&scan_mutex);
664         g_assert (thr_ret == 0);
665
666         if (_wapi_private_handles [idx] == NULL) {
667                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
668                                                                                           _WAPI_HANDLE_INITIAL_COUNT);
669                 g_assert (_wapi_private_handles [idx]);
670         }
671
672         thr_ret = mono_mutex_unlock (&scan_mutex);
673         g_assert (thr_ret == 0);
674         pthread_cleanup_pop (0);
675 }
676
677 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
678                               gpointer handle_specific)
679 {
680         struct _WapiHandleUnshared *handle;
681         int thr_ret;
682         
683         g_assert (_wapi_has_shut_down == FALSE);
684         
685         mono_once (&shared_init_once, shared_init);
686         
687 #ifdef DEBUG
688         g_message ("%s: Creating new handle of type %s", __func__,
689                    _wapi_handle_typename[type]);
690 #endif
691         
692         g_assert(_WAPI_FD_HANDLE(type));
693         g_assert(!_WAPI_SHARED_HANDLE(type));
694         
695         if (fd >= _wapi_fd_reserve) {
696 #ifdef DEBUG
697                 g_message ("%s: fd %d is too big", __func__, fd);
698 #endif
699
700                 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
701         }
702
703         /* Initialize the array entries on demand */
704         if (_wapi_private_handles [SLOT_INDEX (fd)] == NULL)
705                 init_handles_slot (SLOT_INDEX (fd));
706
707         handle = &_WAPI_PRIVATE_HANDLES(fd);
708         
709         if (handle->type != WAPI_HANDLE_UNUSED) {
710 #ifdef DEBUG
711                 g_message ("%s: fd %d is already in use!", __func__, fd);
712 #endif
713                 /* FIXME: clean up this handle?  We can't do anything
714                  * with the fd, cos thats the new one
715                  */
716         }
717
718 #ifdef DEBUG
719         g_message ("%s: Assigning new fd handle %d", __func__, fd);
720 #endif
721
722         /* Prevent file share entries racing with us, when the file
723          * handle is only half initialised
724          */
725         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
726         g_assert(thr_ret == 0);
727
728         _wapi_handle_init (handle, type, handle_specific);
729
730         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
731
732         return(GUINT_TO_POINTER(fd));
733 }
734
735 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
736                               gpointer *handle_specific)
737 {
738         struct _WapiHandleUnshared *handle_data;
739         guint32 handle_idx = GPOINTER_TO_UINT(handle);
740
741         if (!_WAPI_PRIVATE_VALID_SLOT (handle_idx)) {
742                 return(FALSE);
743         }
744
745         /* Initialize the array entries on demand */
746         if (_wapi_private_handles [SLOT_INDEX (handle_idx)] == NULL)
747                 init_handles_slot (SLOT_INDEX (handle_idx));
748         
749         handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
750         
751         if (handle_data->type != type) {
752                 return(FALSE);
753         }
754
755         if (handle_specific == NULL) {
756                 return(FALSE);
757         }
758         
759         if (_WAPI_SHARED_HANDLE(type)) {
760                 struct _WapiHandle_shared_ref *ref;
761                 struct _WapiHandleShared *shared_handle_data;
762                         
763                 ref = &handle_data->u.shared;
764                 shared_handle_data = &_wapi_shared_layout->handles[ref->offset];
765                 
766                 if (shared_handle_data->type != type) {
767                         /* The handle must have been deleted on us
768                          */
769                         return (FALSE);
770                 }
771                 
772                 *handle_specific = &shared_handle_data->u;
773         } else {
774                 *handle_specific = &handle_data->u;
775         }
776         
777         return(TRUE);
778 }
779
780 void
781 _wapi_handle_foreach (WapiHandleType type,
782                         gboolean (*on_each)(gpointer test, gpointer user),
783                         gpointer user_data)
784 {
785         struct _WapiHandleUnshared *handle_data = NULL;
786         gpointer ret = NULL;
787         guint32 i, k;
788         int thr_ret;
789
790         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
791                               (void *)&scan_mutex);
792         thr_ret = mono_mutex_lock (&scan_mutex);
793         g_assert (thr_ret == 0);
794
795         for (i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
796                 if (_wapi_private_handles [i]) {
797                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
798                                 handle_data = &_wapi_private_handles [i][k];
799                         
800                                 if (handle_data->type == type) {
801                                         ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
802                                         if (on_each (ret, user_data) == TRUE)
803                                                 break;
804                                 }
805                         }
806                 }
807         }
808
809         thr_ret = mono_mutex_unlock (&scan_mutex);
810         g_assert (thr_ret == 0);
811         pthread_cleanup_pop (0);
812 }
813
814 /* This might list some shared handles twice if they are already
815  * opened by this process, and the check function returns FALSE the
816  * first time.  Shared handles that are created during the search are
817  * unreffed if the check function returns FALSE, so callers must not
818  * rely on the handle persisting (unless the check function returns
819  * TRUE)
820  */
821 gpointer _wapi_search_handle (WapiHandleType type,
822                               gboolean (*check)(gpointer test, gpointer user),
823                               gpointer user_data,
824                               gpointer *handle_specific,
825                               gboolean search_shared)
826 {
827         struct _WapiHandleUnshared *handle_data = NULL;
828         struct _WapiHandleShared *shared = NULL;
829         gpointer ret = NULL;
830         guint32 i, k;
831         gboolean found = FALSE;
832         int thr_ret;
833
834         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
835                               (void *)&scan_mutex);
836         thr_ret = mono_mutex_lock (&scan_mutex);
837         g_assert (thr_ret == 0);
838         
839         for (i = SLOT_INDEX (0); !found && i < _wapi_private_handle_slot_count; i++) {
840                 if (_wapi_private_handles [i]) {
841                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
842                                 handle_data = &_wapi_private_handles [i][k];
843                 
844                                 if (handle_data->type == type) {
845                                         ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
846                                         if (check (ret, user_data) == TRUE) {
847                                                 _wapi_handle_ref (ret);
848                                                 found = TRUE;
849
850                                                 if (_WAPI_SHARED_HANDLE (type)) {
851                                                         shared = &_wapi_shared_layout->handles[i];
852                                                 }
853                                         
854                                                 break;
855                                         }
856                                 }
857                         }
858                 }
859         }
860
861         thr_ret = mono_mutex_unlock (&scan_mutex);
862         g_assert (thr_ret == 0);
863         pthread_cleanup_pop (0);
864
865         if (!found && search_shared && _WAPI_SHARED_HANDLE (type)) {
866                 /* Not found yet, so search the shared memory too */
867 #ifdef DEBUG
868                 g_message ("%s: Looking at other shared handles...", __func__);
869 #endif
870
871                 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
872                         shared = &_wapi_shared_layout->handles[i];
873                         
874                         if (shared->type == type) {
875                                 /* Tell new_from_offset to not
876                                  * timestamp this handle, because
877                                  * otherwise it will ping every handle
878                                  * in the list and they will never
879                                  * expire
880                                  */
881                                 ret = _wapi_handle_new_from_offset (type, i,
882                                                                     FALSE);
883                                 if (ret == INVALID_HANDLE_VALUE) {
884                                         /* This handle was deleted
885                                          * while we were looking at it
886                                          */
887                                         continue;
888                                 }
889                                 
890 #ifdef DEBUG
891                                 g_message ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
892 #endif
893
894                                 /* It's possible that the shared part
895                                  * of this handle has now been blown
896                                  * away (after new_from_offset
897                                  * successfully opened it,) if its
898                                  * timestamp is too old.  The check
899                                  * function needs to be aware of this,
900                                  * and cope if the handle has
901                                  * vanished.
902                                  */
903                                 if (check (ret, user_data) == TRUE) {
904                                         /* Timestamp this handle, but make
905                                          * sure it still exists first
906                                          */
907                                         thr_ret = _wapi_handle_lock_shared_handles ();
908                                         g_assert (thr_ret == 0);
909                                         
910                                         if (shared->type == type) {
911                                                 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
912                                                 InterlockedExchange ((gint32 *)&shared->timestamp, now);
913
914                                                 found = TRUE;
915                                                 handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
916                                         
917                                                 _wapi_handle_unlock_shared_handles ();
918                                                 break;
919                                         } else {
920                                                 /* It's been deleted,
921                                                  * so just keep
922                                                  * looking
923                                                  */
924                                                 _wapi_handle_unlock_shared_handles ();
925                                         }
926                                 }
927                                 
928                                 /* This isn't the handle we're looking
929                                  * for, so drop the reference we took
930                                  * in _wapi_handle_new_from_offset ()
931                                  */
932                                 _wapi_handle_unref (ret);
933                         }
934                 }
935         }
936         
937         if (!found) {
938                 ret = NULL;
939                 goto done;
940         }
941         
942         if(handle_specific != NULL) {
943                 if (_WAPI_SHARED_HANDLE(type)) {
944                         g_assert(shared->type == type);
945                         
946                         *handle_specific = &shared->u;
947                 } else {
948                         *handle_specific = &handle_data->u;
949                 }
950         }
951
952 done:
953         return(ret);
954 }
955
956 /* Returns the offset of the metadata array, or -1 on error, or 0 for
957  * not found (0 is not a valid offset)
958  */
959 gint32 _wapi_search_handle_namespace (WapiHandleType type,
960                                       gchar *utf8_name)
961 {
962         struct _WapiHandleShared *shared_handle_data;
963         guint32 i;
964         gint32 ret = 0;
965         int thr_ret;
966         
967         g_assert(_WAPI_SHARED_HANDLE(type));
968         
969 #ifdef DEBUG
970         g_message ("%s: Lookup for handle named [%s] type %s", __func__,
971                    utf8_name, _wapi_handle_typename[type]);
972 #endif
973
974         /* Do a handle collection before starting to look, so that any
975          * stale cruft gets removed
976          */
977         _wapi_handle_collect ();
978         
979         thr_ret = _wapi_handle_lock_shared_handles ();
980         g_assert (thr_ret == 0);
981         
982         for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
983                 WapiSharedNamespace *sharedns;
984                 
985                 shared_handle_data = &_wapi_shared_layout->handles[i];
986
987                 /* Check mutex, event, semaphore, timer, job and
988                  * file-mapping object names.  So far only mutex,
989                  * semaphore and event are implemented.
990                  */
991                 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
992                         continue;
993                 }
994
995 #ifdef DEBUG
996                 g_message ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
997 #endif
998
999                 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
1000                         
1001 #ifdef DEBUG
1002                 g_message ("%s: name is [%s]", __func__, sharedns->name);
1003 #endif
1004
1005                 if (strcmp (sharedns->name, utf8_name) == 0) {
1006                         if (shared_handle_data->type != type) {
1007                                 /* Its the wrong type, so fail now */
1008 #ifdef DEBUG
1009                                 g_message ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
1010 #endif
1011                                 ret = -1;
1012                                 goto done;
1013                         } else {
1014 #ifdef DEBUG
1015                                 g_message ("%s: handle 0x%x matches name and type", __func__, i);
1016 #endif
1017                                 ret = i;
1018                                 goto done;
1019                         }
1020                 }
1021         }
1022
1023 done:
1024         _wapi_handle_unlock_shared_handles ();
1025         
1026         return(ret);
1027 }
1028
1029 void _wapi_handle_ref (gpointer handle)
1030 {
1031         guint32 idx = GPOINTER_TO_UINT(handle);
1032         struct _WapiHandleUnshared *handle_data;
1033
1034         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1035                 return;
1036         }
1037         
1038         if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1039                 g_warning ("%s: Attempting to ref unused handle %p", __func__,
1040                            handle);
1041                 return;
1042         }
1043
1044         handle_data = &_WAPI_PRIVATE_HANDLES(idx);
1045         
1046         InterlockedIncrement ((gint32 *)&handle_data->ref);
1047
1048         /* It's possible for processes to exit before getting around
1049          * to updating timestamps in the collection thread, so if a
1050          * shared handle is reffed do the timestamp here as well just
1051          * to make sure.
1052          */
1053         if (_WAPI_SHARED_HANDLE(handle_data->type)) {
1054                 struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
1055                 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1056                 InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
1057         }
1058         
1059 #ifdef DEBUG_REFS
1060         g_message ("%s: %s handle %p ref now %d", __func__, 
1061                    _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1062                    handle,
1063                    _WAPI_PRIVATE_HANDLES(idx).ref);
1064 #endif
1065 }
1066
1067 /* The handle must not be locked on entry to this function */
1068 void _wapi_handle_unref (gpointer handle)
1069 {
1070         guint32 idx = GPOINTER_TO_UINT(handle);
1071         gboolean destroy = FALSE;
1072         int thr_ret;
1073
1074         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1075                 return;
1076         }
1077         
1078         if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
1079                 g_warning ("%s: Attempting to unref unused handle %p",
1080                            __func__, handle);
1081                 return;
1082         }
1083
1084         /* Possible race condition here if another thread refs the
1085          * handle between here and setting the type to UNUSED.  I
1086          * could lock a mutex, but I'm not sure that allowing a handle
1087          * reference to reach 0 isn't an application bug anyway.
1088          */
1089         destroy = (InterlockedDecrement ((gint32 *)&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
1090         
1091 #ifdef DEBUG_REFS
1092         g_message ("%s: %s handle %p ref now %d (destroy %s)", __func__,
1093                    _wapi_handle_typename[_WAPI_PRIVATE_HANDLES (idx).type],
1094                    handle,
1095                    _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
1096 #endif
1097         
1098         if(destroy==TRUE) {
1099                 /* Need to copy the handle info, reset the slot in the
1100                  * array, and _only then_ call the close function to
1101                  * avoid race conditions (eg file descriptors being
1102                  * closed, and another file being opened getting the
1103                  * same fd racing the memset())
1104                  */
1105                 struct _WapiHandleUnshared handle_data;
1106                 struct _WapiHandleShared shared_handle_data;
1107                 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
1108                 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
1109                 gboolean is_shared = _WAPI_SHARED_HANDLE(type);
1110
1111                 if (is_shared) {
1112                         /* If this is a shared handle we need to take
1113                          * the shared lock outside of the scan_mutex
1114                          * lock to avoid deadlocks
1115                          */
1116                         thr_ret = _wapi_handle_lock_shared_handles ();
1117                         g_assert (thr_ret == 0);
1118                 }
1119                 
1120                 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup, (void *)&scan_mutex);
1121                 thr_ret = mono_mutex_lock (&scan_mutex);
1122
1123 #ifdef DEBUG
1124                 g_message ("%s: Destroying handle %p", __func__, handle);
1125 #endif
1126                 
1127                 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
1128                         sizeof (struct _WapiHandleUnshared));
1129
1130                 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
1131                         sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
1132
1133                 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
1134                 
1135                 if (!is_shared) {
1136                         /* Destroy the mutex and cond var.  We hope nobody
1137                          * tried to grab them between the handle unlock and
1138                          * now, but pthreads doesn't have a
1139                          * "unlock_and_destroy" atomic function.
1140                          */
1141                         thr_ret = mono_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
1142                         g_assert (thr_ret == 0);
1143                                 
1144                         thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
1145                         g_assert (thr_ret == 0);
1146                 } else {
1147                         struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
1148
1149                         memcpy (&shared_handle_data, shared,
1150                                 sizeof (struct _WapiHandleShared));
1151                         
1152                         /* It's possible that this handle is already
1153                          * pointing at a deleted shared section
1154                          */
1155 #ifdef DEBUG_REFS
1156                         g_message ("%s: %s handle %p shared refs before dec %d", __func__, _wapi_handle_typename[type], handle, shared->handle_refs);
1157 #endif
1158
1159                         if (shared->handle_refs > 0) {
1160                                 shared->handle_refs--;
1161                                 if (shared->handle_refs == 0) {
1162                                         memset (shared, '\0', sizeof (struct _WapiHandleShared));
1163                                 }
1164                         }
1165                 }
1166
1167                 thr_ret = mono_mutex_unlock (&scan_mutex);
1168                 g_assert (thr_ret == 0);
1169                 pthread_cleanup_pop (0);
1170
1171                 if (is_shared) {
1172                         _wapi_handle_unlock_shared_handles ();
1173                 }
1174                 
1175                 if (close_func != NULL) {
1176                         if (is_shared) {
1177                                 close_func (handle, &shared_handle_data.u);
1178                         } else {
1179                                 close_func (handle, &handle_data.u);
1180                         }
1181                 }
1182         }
1183 }
1184
1185 void _wapi_handle_register_capabilities (WapiHandleType type,
1186                                          WapiHandleCapability caps)
1187 {
1188         handle_caps[type] = caps;
1189 }
1190
1191 gboolean _wapi_handle_test_capabilities (gpointer handle,
1192                                          WapiHandleCapability caps)
1193 {
1194         guint32 idx = GPOINTER_TO_UINT(handle);
1195         WapiHandleType type;
1196
1197         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1198                 return(FALSE);
1199         }
1200         
1201         type = _WAPI_PRIVATE_HANDLES(idx).type;
1202
1203 #ifdef DEBUG
1204         g_message ("%s: testing 0x%x against 0x%x (%d)", __func__,
1205                    handle_caps[type], caps, handle_caps[type] & caps);
1206 #endif
1207         
1208         return((handle_caps[type] & caps) != 0);
1209 }
1210
1211 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
1212 {
1213         if (handle_ops[type] != NULL &&
1214             handle_ops[type]->close != NULL) {
1215                 return (handle_ops[type]->close);
1216         }
1217
1218         return (NULL);
1219 }
1220
1221 void _wapi_handle_ops_close (gpointer handle, gpointer data)
1222 {
1223         guint32 idx = GPOINTER_TO_UINT(handle);
1224         WapiHandleType type;
1225
1226         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1227                 return;
1228         }
1229         
1230         type = _WAPI_PRIVATE_HANDLES(idx).type;
1231
1232         if (handle_ops[type] != NULL &&
1233             handle_ops[type]->close != NULL) {
1234                 handle_ops[type]->close (handle, data);
1235         }
1236 }
1237
1238 void _wapi_handle_ops_signal (gpointer handle)
1239 {
1240         guint32 idx = GPOINTER_TO_UINT(handle);
1241         WapiHandleType type;
1242
1243         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1244                 return;
1245         }
1246         
1247         type = _WAPI_PRIVATE_HANDLES(idx).type;
1248
1249         if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
1250                 handle_ops[type]->signal (handle);
1251         }
1252 }
1253
1254 gboolean _wapi_handle_ops_own (gpointer handle)
1255 {
1256         guint32 idx = GPOINTER_TO_UINT(handle);
1257         WapiHandleType type;
1258         
1259         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1260                 return(FALSE);
1261         }
1262         
1263         type = _WAPI_PRIVATE_HANDLES(idx).type;
1264
1265         if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
1266                 return(handle_ops[type]->own_handle (handle));
1267         } else {
1268                 return(FALSE);
1269         }
1270 }
1271
1272 gboolean _wapi_handle_ops_isowned (gpointer handle)
1273 {
1274         guint32 idx = GPOINTER_TO_UINT(handle);
1275         WapiHandleType type;
1276
1277         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1278                 return(FALSE);
1279         }
1280         
1281         type = _WAPI_PRIVATE_HANDLES(idx).type;
1282
1283         if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
1284                 return(handle_ops[type]->is_owned (handle));
1285         } else {
1286                 return(FALSE);
1287         }
1288 }
1289
1290 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout)
1291 {
1292         guint32 idx = GPOINTER_TO_UINT(handle);
1293         WapiHandleType type;
1294         
1295         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1296                 return(WAIT_FAILED);
1297         }
1298         
1299         type = _WAPI_PRIVATE_HANDLES(idx).type;
1300         
1301         if (handle_ops[type] != NULL &&
1302             handle_ops[type]->special_wait != NULL) {
1303                 return(handle_ops[type]->special_wait (handle, timeout));
1304         } else {
1305                 return(WAIT_FAILED);
1306         }
1307 }
1308
1309 void _wapi_handle_ops_prewait (gpointer handle)
1310 {
1311         guint32 idx = GPOINTER_TO_UINT (handle);
1312         WapiHandleType type;
1313         
1314         if (!_WAPI_PRIVATE_VALID_SLOT (idx)) {
1315                 return;
1316         }
1317         
1318         type = _WAPI_PRIVATE_HANDLES (idx).type;
1319         
1320         if (handle_ops[type] != NULL &&
1321             handle_ops[type]->prewait != NULL) {
1322                 handle_ops[type]->prewait (handle);
1323         }
1324 }
1325
1326
1327 /**
1328  * CloseHandle:
1329  * @handle: The handle to release
1330  *
1331  * Closes and invalidates @handle, releasing any resources it
1332  * consumes.  When the last handle to a temporary or non-persistent
1333  * object is closed, that object can be deleted.  Closing the same
1334  * handle twice is an error.
1335  *
1336  * Return value: %TRUE on success, %FALSE otherwise.
1337  */
1338 gboolean CloseHandle(gpointer handle)
1339 {
1340         if (handle == NULL) {
1341                 /* Problem: because we map file descriptors to the
1342                  * same-numbered handle we can't tell the difference
1343                  * between a bogus handle and the handle to stdin.
1344                  * Assume that it's the console handle if that handle
1345                  * exists...
1346                  */
1347                 if (_WAPI_PRIVATE_HANDLES (0).type != WAPI_HANDLE_CONSOLE) {
1348                         SetLastError (ERROR_INVALID_PARAMETER);
1349                         return(FALSE);
1350                 }
1351         }
1352         if (handle == _WAPI_HANDLE_INVALID){
1353                 SetLastError (ERROR_INVALID_PARAMETER);
1354                 return(FALSE);
1355         }
1356         
1357         _wapi_handle_unref (handle);
1358         
1359         return(TRUE);
1360 }
1361
1362 /* Lots more to implement here, but this is all we need at the moment */
1363 gboolean DuplicateHandle (gpointer srcprocess, gpointer src,
1364                           gpointer targetprocess, gpointer *target,
1365                           guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 options G_GNUC_UNUSED)
1366 {
1367         if (srcprocess != _WAPI_PROCESS_CURRENT ||
1368             targetprocess != _WAPI_PROCESS_CURRENT) {
1369                 /* Duplicating other process's handles is not supported */
1370                 SetLastError (ERROR_INVALID_HANDLE);
1371                 return(FALSE);
1372         }
1373         
1374         if (src == _WAPI_PROCESS_CURRENT) {
1375                 *target = _wapi_process_duplicate ();
1376         } else if (src == _WAPI_THREAD_CURRENT) {
1377                 *target = _wapi_thread_duplicate ();
1378         } else {
1379                 _wapi_handle_ref (src);
1380                 *target = src;
1381         }
1382         
1383         return(TRUE);
1384 }
1385
1386 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1387                                                gpointer *handles,
1388                                                gboolean waitall,
1389                                                guint32 *retcount,
1390                                                guint32 *lowest)
1391 {
1392         guint32 count, i, iter=0;
1393         gboolean ret;
1394         int thr_ret;
1395         WapiHandleType type;
1396         
1397         /* Lock all the handles, with backoff */
1398 again:
1399         thr_ret = _wapi_handle_lock_shared_handles ();
1400         g_assert (thr_ret == 0);
1401         
1402         for(i=0; i<numhandles; i++) {
1403                 gpointer handle = handles[i];
1404                 guint32 idx = GPOINTER_TO_UINT(handle);
1405
1406 #ifdef DEBUG
1407                 g_message ("%s: attempting to lock %p", __func__, handle);
1408 #endif
1409
1410                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1411
1412                 thr_ret = _wapi_handle_trylock_handle (handle);
1413                 
1414                 if (thr_ret != 0) {
1415                         /* Bummer */
1416                         
1417 #ifdef DEBUG
1418                         g_message ("%s: attempt failed for %p: %s", __func__,
1419                                    handle, strerror (thr_ret));
1420 #endif
1421
1422                         thr_ret = _wapi_handle_unlock_shared_handles ();
1423                         g_assert (thr_ret == 0);
1424                         
1425                         while (i--) {
1426                                 handle = handles[i];
1427                                 idx = GPOINTER_TO_UINT(handle);
1428
1429                                 thr_ret = _wapi_handle_unlock_handle (handle);
1430                                 g_assert (thr_ret == 0);
1431                         }
1432
1433                         /* If iter ever reaches 100 the nanosleep will
1434                          * return EINVAL immediately, but we have a
1435                          * design flaw if that happens.
1436                          */
1437                         iter++;
1438                         if(iter==100) {
1439                                 g_warning ("%s: iteration overflow!",
1440                                            __func__);
1441                                 iter=1;
1442                         }
1443                         
1444 #ifdef DEBUG
1445                         g_message ("%s: Backing off for %d ms", __func__,
1446                                    iter*10);
1447 #endif
1448                         _wapi_handle_spin (10 * iter);
1449                         
1450                         goto again;
1451                 }
1452         }
1453         
1454 #ifdef DEBUG
1455         g_message ("%s: Locked all handles", __func__);
1456 #endif
1457
1458         count=0;
1459         *lowest=numhandles;
1460         
1461         for(i=0; i<numhandles; i++) {
1462                 gpointer handle = handles[i];
1463                 guint32 idx = GPOINTER_TO_UINT(handle);
1464                 
1465                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1466
1467 #ifdef DEBUG
1468                 g_message ("%s: Checking handle %p", __func__, handle);
1469 #endif
1470
1471                 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1472                     (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1473                    (_WAPI_SHARED_HANDLE(type) &&
1474                     WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) ||
1475                    (!_WAPI_SHARED_HANDLE(type) &&
1476                     _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
1477                         count++;
1478                         
1479 #ifdef DEBUG
1480                         g_message ("%s: Handle %p signalled", __func__,
1481                                    handle);
1482 #endif
1483                         if(*lowest>i) {
1484                                 *lowest=i;
1485                         }
1486                 }
1487         }
1488         
1489 #ifdef DEBUG
1490         g_message ("%s: %d event handles signalled", __func__, count);
1491 #endif
1492
1493         if ((waitall == TRUE && count == numhandles) ||
1494             (waitall == FALSE && count > 0)) {
1495                 ret=TRUE;
1496         } else {
1497                 ret=FALSE;
1498         }
1499         
1500 #ifdef DEBUG
1501         g_message ("%s: Returning %d", __func__, ret);
1502 #endif
1503
1504         *retcount=count;
1505         
1506         return(ret);
1507 }
1508
1509 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1510 {
1511         guint32 i;
1512         int thr_ret;
1513         
1514         thr_ret = _wapi_handle_unlock_shared_handles ();
1515         g_assert (thr_ret == 0);
1516         
1517         for(i=0; i<numhandles; i++) {
1518                 gpointer handle = handles[i];
1519                 
1520 #ifdef DEBUG
1521                 g_message ("%s: unlocking handle %p", __func__, handle);
1522 #endif
1523
1524                 thr_ret = _wapi_handle_unlock_handle (handle);
1525                 g_assert (thr_ret == 0);
1526         }
1527 }
1528
1529 static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout, gboolean alertable)
1530 {
1531         struct timespec fake_timeout;
1532         int ret;
1533
1534         if (!alertable) {
1535                 if (timeout)
1536                         ret=mono_cond_timedwait (cond, mutex, timeout);
1537                 else
1538                         ret=mono_cond_wait (cond, mutex);
1539         } else {
1540                 _wapi_calc_timeout (&fake_timeout, 100);
1541         
1542                 if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
1543                                                                 (fake_timeout.tv_sec == timeout->tv_sec &&
1544                                                                  fake_timeout.tv_nsec > timeout->tv_nsec))) {
1545                         /* Real timeout is less than 100ms time */
1546                         ret=mono_cond_timedwait (cond, mutex, timeout);
1547                 } else {
1548                         ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
1549
1550                         /* Mask the fake timeout, this will cause
1551                          * another poll if the cond was not really signaled
1552                          */
1553                         if (ret==ETIMEDOUT) {
1554                                 ret=0;
1555                         }
1556                 }
1557         }
1558         
1559         return(ret);
1560 }
1561
1562 int _wapi_handle_wait_signal (gboolean poll)
1563 {
1564         return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, NULL, TRUE, poll);
1565 }
1566
1567 int _wapi_handle_timedwait_signal (struct timespec *timeout, gboolean poll)
1568 {
1569         return _wapi_handle_timedwait_signal_handle (_wapi_global_signal_handle, timeout, TRUE, poll);
1570 }
1571
1572 int _wapi_handle_wait_signal_handle (gpointer handle, gboolean alertable)
1573 {
1574 #ifdef DEBUG
1575         g_message ("%s: waiting for %p", __func__, handle);
1576 #endif
1577         
1578         return _wapi_handle_timedwait_signal_handle (handle, NULL, alertable, FALSE);
1579 }
1580
1581 int _wapi_handle_timedwait_signal_handle (gpointer handle,
1582                                                                                   struct timespec *timeout, gboolean alertable, gboolean poll)
1583 {
1584 #ifdef DEBUG
1585         g_message ("%s: waiting for %p (type %s)", __func__, handle,
1586                    _wapi_handle_typename[_wapi_handle_type (handle)]);
1587 #endif
1588         
1589         if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1590                 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1591                         return (0);
1592                 }
1593                 if (timeout != NULL) {
1594                         struct timespec fake_timeout;
1595                         _wapi_calc_timeout (&fake_timeout, 100);
1596                 
1597                         if ((fake_timeout.tv_sec > timeout->tv_sec) ||
1598                                 (fake_timeout.tv_sec == timeout->tv_sec &&
1599                                  fake_timeout.tv_nsec > timeout->tv_nsec)) {
1600                                 /* FIXME: Real timeout is less than
1601                                  * 100ms time, but is it really worth
1602                                  * calculating to the exact ms?
1603                                  */
1604                                 _wapi_handle_spin (100);
1605
1606                                 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1607                                         return (0);
1608                                 } else {
1609                                         return (ETIMEDOUT);
1610                                 }
1611                         }
1612                 }
1613                 _wapi_handle_spin (100);
1614                 return (0);
1615                 
1616         } else {
1617                 guint32 idx = GPOINTER_TO_UINT(handle);
1618                 int res;
1619                 pthread_cond_t *cond;
1620                 mono_mutex_t *mutex;
1621
1622                 if (alertable && !wapi_thread_set_wait_handle (handle))
1623                         return 0;
1624
1625                 cond = &_WAPI_PRIVATE_HANDLES (idx).signal_cond;
1626                 mutex = &_WAPI_PRIVATE_HANDLES (idx).signal_mutex;
1627
1628                 if (poll) {
1629                         /* This is needed when waiting for process handles */
1630                         res = timedwait_signal_poll_cond (cond, mutex, timeout, alertable);
1631                 } else {
1632                         if (timeout)
1633                                 res = mono_cond_timedwait (cond, mutex, timeout);
1634                         else
1635                                 res = mono_cond_wait (cond, mutex);
1636                 }
1637
1638                 if (alertable)
1639                         wapi_thread_clear_wait_handle (handle);
1640
1641                 return res;
1642         }
1643 }
1644
1645 void
1646 _wapi_free_share_info (_WapiFileShare *share_info)
1647 {
1648         if (!_wapi_shm_enabled ()) {
1649                 file_share_hash_lock ();
1650                 g_hash_table_remove (file_share_hash, share_info);
1651                 file_share_hash_unlock ();
1652         } else {
1653                 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1654         }
1655 }
1656
1657 static gint
1658 wapi_share_info_equal (gconstpointer ka, gconstpointer kb)
1659 {
1660         const _WapiFileShare *s1 = ka;
1661         const _WapiFileShare *s2 = kb;
1662
1663         return (s1->device == s2->device && s1->inode == s2->inode) ? 1 : 0;
1664 }
1665
1666 static guint
1667 wapi_share_info_hash (gconstpointer data)
1668 {
1669         const _WapiFileShare *s = data;
1670
1671         return s->inode;
1672 }
1673
1674 gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
1675                                         guint32 new_sharemode,
1676                                         guint32 new_access,
1677                                         guint32 *old_sharemode,
1678                                         guint32 *old_access,
1679                                         struct _WapiFileShare **share_info)
1680 {
1681         struct _WapiFileShare *file_share;
1682         guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1683         int thr_ret, i, first_unused = -1;
1684         gboolean exists = FALSE;
1685
1686         /* Prevents entries from expiring under us as we search
1687          */
1688         thr_ret = _wapi_handle_lock_shared_handles ();
1689         g_assert (thr_ret == 0);
1690         
1691         /* Prevent new entries racing with us */
1692         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1693         g_assert (thr_ret == 0);
1694
1695         if (!_wapi_shm_enabled ()) {
1696                 _WapiFileShare tmp;
1697
1698                 /*
1699                  * Instead of allocating a 4MB array, we use a hash table to keep track of this
1700                  * info. This is needed even if SHM is disabled, to track sharing inside
1701                  * the current process.
1702                  */
1703                 if (!file_share_hash) {
1704                         file_share_hash = g_hash_table_new_full (wapi_share_info_hash, wapi_share_info_equal, NULL, g_free);
1705                         InitializeCriticalSection (&file_share_hash_mutex);
1706                 }
1707                         
1708                 tmp.device = device;
1709                 tmp.inode = inode;
1710
1711                 file_share_hash_lock ();
1712
1713                 file_share = g_hash_table_lookup (file_share_hash, &tmp);
1714                 if (file_share) {
1715                         *old_sharemode = file_share->sharemode;
1716                         *old_access = file_share->access;
1717                         *share_info = file_share;
1718                         
1719                         InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1720                         exists = TRUE;
1721                 } else {
1722                         file_share = g_new0 (_WapiFileShare, 1);
1723
1724                         file_share->device = device;
1725                         file_share->inode = inode;
1726                         file_share->opened_by_pid = _wapi_getpid ();
1727                         file_share->sharemode = new_sharemode;
1728                         file_share->access = new_access;
1729                         file_share->handle_refs = 1;
1730                         *share_info = file_share;
1731
1732                         g_hash_table_insert (file_share_hash, file_share, file_share);
1733                 }
1734
1735                 file_share_hash_unlock ();
1736         } else {
1737                 /* If a linear scan gets too slow we'll have to fit a hash
1738                  * table onto the shared mem backing store
1739                  */
1740                 *share_info = NULL;
1741                 for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
1742                         file_share = &_wapi_fileshare_layout->share_info[i];
1743
1744                         /* Make a note of an unused slot, in case we need to
1745                          * store share info
1746                          */
1747                         if (first_unused == -1 && file_share->handle_refs == 0) {
1748                                 first_unused = i;
1749                                 continue;
1750                         }
1751                 
1752                         if (file_share->handle_refs == 0) {
1753                                 continue;
1754                         }
1755                 
1756                         if (file_share->device == device &&
1757                                 file_share->inode == inode) {
1758                                 *old_sharemode = file_share->sharemode;
1759                                 *old_access = file_share->access;
1760                                 *share_info = file_share;
1761                         
1762                                 /* Increment the reference count while we
1763                                  * still have sole access to the shared area.
1764                                  * This makes the increment atomic wrt
1765                                  * collections
1766                                  */
1767                                 InterlockedIncrement ((gint32 *)&file_share->handle_refs);
1768                         
1769                                 exists = TRUE;
1770                                 break;
1771                         }
1772                 }
1773         
1774                 if (!exists) {
1775                         if (i == _WAPI_FILESHARE_SIZE && first_unused == -1) {
1776                                 /* No more space */
1777                         } else {
1778                                 if (first_unused == -1) {
1779                                         file_share = &_wapi_fileshare_layout->share_info[++i];
1780                                         _wapi_fileshare_layout->hwm = i;
1781                                 } else {
1782                                         file_share = &_wapi_fileshare_layout->share_info[first_unused];
1783                                 }
1784                         
1785                                 file_share->device = device;
1786                                 file_share->inode = inode;
1787                                 file_share->opened_by_pid = _wapi_getpid ();
1788                                 file_share->sharemode = new_sharemode;
1789                                 file_share->access = new_access;
1790                                 file_share->handle_refs = 1;
1791                                 *share_info = file_share;
1792                         }
1793                 }
1794
1795                 if (*share_info != NULL) {
1796                         InterlockedExchange ((gint32 *)&(*share_info)->timestamp, now);
1797                 }
1798         }
1799         
1800         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1801
1802         _wapi_handle_unlock_shared_handles ();
1803
1804         return(exists);
1805 }
1806
1807 /* If we don't have the info in /proc, check if the process that
1808  * opened this share info is still there (it's not a perfect method,
1809  * due to pid reuse)
1810  */
1811 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
1812 {
1813         if (kill (share_info->opened_by_pid, 0) == -1 &&
1814             (errno == ESRCH ||
1815              errno == EPERM)) {
1816                 /* It's gone completely (or there's a new process
1817                  * owned by someone else) so mark this share info as
1818                  * dead
1819                  */
1820 #ifdef DEBUG
1821                 g_message ("%s: Didn't find it, destroying entry", __func__);
1822 #endif
1823
1824                 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1825         }
1826 }
1827
1828 #ifdef __linux__
1829 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1830  * question.  If there are none, reset the share info.
1831  *
1832  * This implementation is Linux-specific; legacy systems will have to
1833  * implement their own ways of finding out if a particular file is
1834  * open by a process.
1835  */
1836 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1837 {
1838         gboolean found = FALSE, proc_fds = FALSE;
1839         pid_t self = _wapi_getpid ();
1840         int pid;
1841         int thr_ret, i;
1842         
1843         /* Prevents entries from expiring under us if we remove this
1844          * one
1845          */
1846         thr_ret = _wapi_handle_lock_shared_handles ();
1847         g_assert (thr_ret == 0);
1848         
1849         /* Prevent new entries racing with us */
1850         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1851         g_assert (thr_ret == 0);
1852         
1853         /* If there is no /proc, there's nothing more we can do here */
1854         if (access ("/proc", F_OK) == -1) {
1855                 _wapi_handle_check_share_by_pid (share_info);
1856                 goto done;
1857         }
1858
1859         /* If there's another handle that thinks it owns this fd, then even
1860          * if the fd has been closed behind our back consider it still owned.
1861          * See bugs 75764 and 75891
1862          */
1863         for (i = 0; i < _wapi_fd_reserve; i++) {
1864                 if (_wapi_private_handles [SLOT_INDEX (i)]) {
1865                         struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
1866
1867                         if (i != fd &&
1868                                 handle->type == WAPI_HANDLE_FILE) {
1869                                 struct _WapiHandle_file *file_handle = &handle->u.file;
1870
1871                                 if (file_handle->share_info == share_info) {
1872 #ifdef DEBUG
1873                                         g_message ("%s: handle 0x%x has this file open!",
1874                                                            __func__, i);
1875 #endif
1876
1877                                         goto done;
1878                                 }
1879                         }
1880                 }
1881         }
1882
1883         for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
1884                 struct _WapiHandleShared *shared;
1885                 struct _WapiHandle_process *process_handle;
1886
1887                 shared = &_wapi_shared_layout->handles[i];
1888                 
1889                 if (shared->type == WAPI_HANDLE_PROCESS) {
1890                         DIR *fd_dir;
1891                         struct dirent *fd_entry;
1892                         char subdir[_POSIX_PATH_MAX];
1893
1894                         process_handle = &shared->u.process;
1895                         pid = process_handle->id;
1896                 
1897                         /* Look in /proc/<pid>/fd/ but ignore
1898                          * /proc/<our pid>/fd/<fd>, as we have the
1899                          * file open too
1900                          */
1901                         g_snprintf (subdir, _POSIX_PATH_MAX, "/proc/%d/fd",
1902                                     pid);
1903                         
1904                         fd_dir = opendir (subdir);
1905                         if (fd_dir == NULL) {
1906                                 continue;
1907                         }
1908
1909 #ifdef DEBUG
1910                         g_message ("%s: Looking in %s", __func__, subdir);
1911 #endif
1912                         
1913                         proc_fds = TRUE;
1914                         
1915                         while ((fd_entry = readdir (fd_dir)) != NULL) {
1916                                 char path[_POSIX_PATH_MAX];
1917                                 struct stat link_stat;
1918                                 
1919                                 if (!strcmp (fd_entry->d_name, ".") ||
1920                                     !strcmp (fd_entry->d_name, "..") ||
1921                                     (pid == self &&
1922                                      fd == atoi (fd_entry->d_name))) {
1923                                         continue;
1924                                 }
1925
1926                                 g_snprintf (path, _POSIX_PATH_MAX,
1927                                             "/proc/%d/fd/%s", pid,
1928                                             fd_entry->d_name);
1929                                 
1930                                 stat (path, &link_stat);
1931                                 if (link_stat.st_dev == share_info->device &&
1932                                     link_stat.st_ino == share_info->inode) {
1933 #ifdef DEBUG
1934                                         g_message ("%s:  Found it at %s",
1935                                                    __func__, path);
1936 #endif
1937
1938                                         found = TRUE;
1939                                 }
1940                         }
1941                         
1942                         closedir (fd_dir);
1943                 }
1944         }
1945
1946         if (proc_fds == FALSE) {
1947                 _wapi_handle_check_share_by_pid (share_info);
1948         } else if (found == FALSE) {
1949                 /* Blank out this entry, as it is stale */
1950 #ifdef DEBUG
1951                 g_message ("%s: Didn't find it, destroying entry", __func__);
1952 #endif
1953
1954                 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1955         }
1956
1957 done:
1958         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1959
1960         _wapi_handle_unlock_shared_handles ();
1961 }
1962 #else
1963 //
1964 // Other implementations (non-Linux)
1965 //
1966 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1967 {
1968         int thr_ret;
1969         
1970         /* Prevents entries from expiring under us if we remove this
1971          * one */
1972         thr_ret = _wapi_handle_lock_shared_handles ();
1973         g_assert (thr_ret == 0);
1974         
1975         /* Prevent new entries racing with us */
1976         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1977         g_assert (thr_ret == 0);
1978         
1979         _wapi_handle_check_share_by_pid (share_info);
1980
1981         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1982         _wapi_handle_unlock_shared_handles ();
1983 }
1984 #endif
1985
1986 void _wapi_handle_dump (void)
1987 {
1988         struct _WapiHandleUnshared *handle_data;
1989         guint32 i, k;
1990         int thr_ret;
1991         
1992         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
1993                               (void *)&scan_mutex);
1994         thr_ret = mono_mutex_lock (&scan_mutex);
1995         g_assert (thr_ret == 0);
1996         
1997         for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
1998                 if (_wapi_private_handles [i]) {
1999                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
2000                                 handle_data = &_wapi_private_handles [i][k];
2001
2002                                 if (handle_data->type == WAPI_HANDLE_UNUSED) {
2003                                         continue;
2004                                 }
2005                 
2006                                 g_print ("%3x [%7s] %s %d ",
2007                                                  i * _WAPI_HANDLE_INITIAL_COUNT + k,
2008                                                  _wapi_handle_typename[handle_data->type],
2009                                                  handle_data->signalled?"Sg":"Un",
2010                                                  handle_data->ref);
2011                                 handle_details[handle_data->type](&handle_data->u);
2012                                 g_print ("\n");
2013                         }
2014                 }
2015         }
2016
2017         thr_ret = mono_mutex_unlock (&scan_mutex);
2018         g_assert (thr_ret == 0);
2019         pthread_cleanup_pop (0);
2020 }
2021
2022 static void _wapi_shared_details (gpointer handle_info)
2023 {
2024         struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
2025         
2026         g_print ("offset: 0x%x", shared->offset);
2027 }
2028
2029 void _wapi_handle_update_refs (void)
2030 {
2031         guint32 i, k;
2032         int thr_ret;
2033         guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
2034         
2035         thr_ret = _wapi_handle_lock_shared_handles ();
2036         g_assert (thr_ret == 0);
2037
2038         /* Prevent file share entries racing with us */
2039         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
2040         g_assert(thr_ret == 0);
2041
2042         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
2043                               (void *)&scan_mutex);
2044         thr_ret = mono_mutex_lock (&scan_mutex);
2045         
2046         for(i = SLOT_INDEX (0); i < _wapi_private_handle_slot_count; i++) {
2047                 if (_wapi_private_handles [i]) {
2048                         for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
2049                                 struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
2050
2051                                 if (_WAPI_SHARED_HANDLE(handle->type)) {
2052                                         struct _WapiHandleShared *shared_data;
2053                                 
2054 #ifdef DEBUG
2055                                         g_message ("%s: (%d) handle 0x%x is SHARED (%s)", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
2056 #endif
2057
2058                                         shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
2059
2060 #ifdef DEBUG
2061                                         g_message ("%s: (%d) Updating timestamp of handle 0x%x", __func__, _wapi_getpid (), handle->u.shared.offset);
2062 #endif
2063
2064                                         InterlockedExchange ((gint32 *)&shared_data->timestamp, now);
2065                                 } else if (handle->type == WAPI_HANDLE_FILE) {
2066                                         struct _WapiHandle_file *file_handle = &handle->u.file;
2067                                 
2068 #ifdef DEBUG
2069                                         g_message ("%s: (%d) handle 0x%x is FILE", __func__, _wapi_getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
2070 #endif
2071                                 
2072                                         g_assert (file_handle->share_info != NULL);
2073
2074 #ifdef DEBUG
2075                                         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));
2076 #endif
2077
2078                                         InterlockedExchange ((gint32 *)&file_handle->share_info->timestamp, now);
2079                                 }
2080                         }
2081                 }
2082         }
2083
2084         thr_ret = mono_mutex_unlock (&scan_mutex);
2085         g_assert (thr_ret == 0);
2086         pthread_cleanup_pop (0);
2087         
2088         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
2089
2090         _wapi_handle_unlock_shared_handles ();
2091 }
2092