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