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