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