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