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