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