2005-10-19 Dick Porter <dick@ximian.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 Ximian, 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 #include <sys/socket.h>
18 #include <sys/un.h>
19 #include <sys/mman.h>
20 #include <dirent.h>
21 #include <sys/stat.h>
22
23 #include <mono/os/gc_wrapper.h>
24
25 #include <mono/io-layer/wapi.h>
26 #include <mono/io-layer/wapi-private.h>
27 #include <mono/io-layer/handles-private.h>
28 #include <mono/io-layer/mono-mutex.h>
29 #include <mono/io-layer/misc-private.h>
30 #include <mono/io-layer/shared.h>
31 #include <mono/io-layer/collection.h>
32
33 #undef DEBUG
34 #undef DEBUG_REFS
35
36 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer);
37
38 static WapiHandleCapability handle_caps[WAPI_HANDLE_COUNT]={0};
39 static struct _WapiHandleOps *handle_ops[WAPI_HANDLE_COUNT]={
40         NULL,
41         &_wapi_file_ops,
42         &_wapi_console_ops,
43         &_wapi_thread_ops,
44         &_wapi_sem_ops,
45         &_wapi_mutex_ops,
46         &_wapi_event_ops,
47         &_wapi_socket_ops,
48         &_wapi_find_ops,
49         &_wapi_process_ops,
50         &_wapi_pipe_ops,
51         &_wapi_namedmutex_ops,
52 };
53
54 static void _wapi_shared_details (gpointer handle_info);
55
56 static void (*handle_details[WAPI_HANDLE_COUNT])(gpointer) = {
57         NULL,
58         _wapi_file_details,
59         _wapi_console_details,
60         _wapi_shared_details,   /* thread */
61         _wapi_sem_details,
62         _wapi_mutex_details,
63         _wapi_event_details,
64         NULL,                   /* Nothing useful to see in a socket handle */
65         NULL,                   /* Nothing useful to see in a find handle */
66         _wapi_shared_details,   /* process */
67         _wapi_pipe_details,
68         _wapi_shared_details,   /* namedmutex */
69 };
70
71 const char *_wapi_handle_typename[] = {
72         "Unused",
73         "File",
74         "Console",
75         "Thread",
76         "Sem",
77         "Mutex",
78         "Event",
79         "Socket",
80         "Find",
81         "Process",
82         "Pipe",
83         "N.Mutex",
84         "Error!!"
85 };
86
87 /*
88  * We can hold _WAPI_PRIVATE_MAX_SLOTS * _WAPI_HANDLE_INITIAL_COUNT handles.
89  * If 4M handles are not enough... Oh, well... we will crash.
90  */
91 #define SLOT_INDEX(x)   (x / _WAPI_HANDLE_INITIAL_COUNT)
92 #define SLOT_OFFSET(x)  (x % _WAPI_HANDLE_INITIAL_COUNT)
93
94 struct _WapiHandleUnshared *_wapi_private_handles [_WAPI_PRIVATE_MAX_SLOTS];
95 static guint32 _wapi_private_handle_count = 0;
96
97 struct _WapiHandleSharedLayout *_wapi_shared_layout = NULL;
98 struct _WapiFileShareLayout *_wapi_fileshare_layout = NULL;
99
100 guint32 _wapi_fd_reserve;
101
102 mono_mutex_t _wapi_global_signal_mutex;
103 pthread_cond_t _wapi_global_signal_cond;
104
105 int _wapi_sem_id;
106
107 static mono_mutex_t scan_mutex = MONO_MUTEX_INITIALIZER;
108
109 static mono_once_t shared_init_once = MONO_ONCE_INIT;
110 static void shared_init (void)
111 {
112         int thr_ret;
113         int idx = 0;
114         
115         _wapi_fd_reserve = getdtablesize();
116
117         do {
118                 _wapi_private_handles [idx++] = g_new0 (struct _WapiHandleUnshared,
119                                                         _WAPI_HANDLE_INITIAL_COUNT);
120
121                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
122         } while(_wapi_fd_reserve > _wapi_private_handle_count);
123         
124         _wapi_shared_layout = _wapi_shm_attach (WAPI_SHM_DATA);
125         g_assert (_wapi_shared_layout != NULL);
126
127         _wapi_shm_semaphores_init ();
128         
129         _wapi_fileshare_layout = _wapi_shm_attach (WAPI_SHM_FILESHARE);
130         g_assert (_wapi_fileshare_layout != NULL);
131         
132         _wapi_collection_init ();
133         
134         thr_ret = pthread_cond_init(&_wapi_global_signal_cond, NULL);
135         g_assert (thr_ret == 0);
136         
137         thr_ret = mono_mutex_init(&_wapi_global_signal_mutex, NULL);
138         g_assert (thr_ret == 0);
139 }
140
141 static void _wapi_handle_init_shared (struct _WapiHandleShared *handle,
142                                       WapiHandleType type,
143                                       gpointer handle_specific)
144 {
145         handle->type = type;
146         handle->timestamp = (guint32)(time (NULL) & 0xFFFFFFFF);
147         handle->signalled = FALSE;
148         handle->handle_refs = 1;
149         
150         if (handle_specific != NULL) {
151                 memcpy (&handle->u, handle_specific, sizeof (handle->u));
152         }
153 }
154
155 static void _wapi_handle_init (struct _WapiHandleUnshared *handle,
156                                WapiHandleType type, gpointer handle_specific)
157 {
158         int thr_ret;
159         
160         handle->type = type;
161         handle->signalled = FALSE;
162         handle->ref = 1;
163         
164         if (!_WAPI_SHARED_HANDLE(type)) {
165                 thr_ret = pthread_cond_init (&handle->signal_cond, NULL);
166                 g_assert (thr_ret == 0);
167                                 
168                 thr_ret = mono_mutex_init (&handle->signal_mutex, NULL);
169                 g_assert (thr_ret == 0);
170
171                 if (handle_specific != NULL) {
172                         memcpy (&handle->u, handle_specific,
173                                 sizeof (handle->u));
174                 }
175         }
176 }
177
178 static guint32 _wapi_handle_new_shared (WapiHandleType type,
179                                         gpointer handle_specific)
180 {
181         guint32 offset;
182         static guint32 last = 1;
183         int thr_ret;
184         
185         /* Leave the first slot empty as a guard */
186 again:
187         /* FIXME: expandable array */
188         for(offset = last; offset <_WAPI_HANDLE_INITIAL_COUNT; offset++) {
189                 struct _WapiHandleShared *handle = &_wapi_shared_layout->handles[offset];
190                 
191                 if(handle->type == WAPI_HANDLE_UNUSED) {
192                         thr_ret = _wapi_handle_lock_shared_handles ();
193                         g_assert (thr_ret == 0);
194                         
195                         if (InterlockedCompareExchange ((gint32 *)&handle->type, type, WAPI_HANDLE_UNUSED) == WAPI_HANDLE_UNUSED) {
196                                 last = offset + 1;
197                         
198                                 _wapi_handle_init_shared (handle, type,
199                                                           handle_specific);
200
201                                 _wapi_handle_unlock_shared_handles ();
202                                 
203                                 return(offset);
204                         } else {
205                                 /* Someone else beat us to it, just
206                                  * continue looking
207                                  */
208                         }
209
210                         _wapi_handle_unlock_shared_handles ();
211                 }
212         }
213
214         if(last > 1) {
215                 /* Try again from the beginning */
216                 last = 1;
217                 goto again;
218         }
219
220         /* Will need to expand the array.  The caller will sort it out */
221
222         return(0);
223 }
224
225 /*
226  * _wapi_handle_new_internal:
227  * @type: Init handle to this type
228  *
229  * Search for a free handle and initialize it. Return the handle on
230  * success and 0 on failure.  This is only called from
231  * _wapi_handle_new, and scan_mutex must be held.
232  */
233 static guint32 _wapi_handle_new_internal (WapiHandleType type,
234                                           gpointer handle_specific)
235 {
236         guint32 i, k, count;
237         static guint32 last = 0;
238         gboolean retry = FALSE;
239         
240         /* A linear scan should be fast enough.  Start from the last
241          * allocation, assuming that handles are allocated more often
242          * than they're freed. Leave the space reserved for file
243          * descriptors
244          */
245         
246         if (last < _wapi_fd_reserve) {
247                 last = _wapi_fd_reserve;
248         } else {
249                 retry = TRUE;
250         }
251
252 again:
253         count = last;
254         for(i = SLOT_INDEX (count); _wapi_private_handles [i] != NULL; i++) {
255                 for (k = SLOT_OFFSET (count); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
256                         struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
257
258                         if(handle->type == WAPI_HANDLE_UNUSED) {
259                                 last = count + 1;
260                         
261                                 _wapi_handle_init (handle, type, handle_specific);
262                                 return (count);
263                         }
264                         count++;
265                 }
266         }
267
268         if(retry && last > _wapi_fd_reserve) {
269                 /* Try again from the beginning */
270                 last = _wapi_fd_reserve;
271                 goto again;
272         }
273
274         /* Will need to expand the array.  The caller will sort it out */
275
276         return(0);
277 }
278
279 gpointer _wapi_handle_new (WapiHandleType type, gpointer handle_specific)
280 {
281         guint32 handle_idx = 0;
282         gpointer handle;
283         int thr_ret;
284         
285         mono_once (&shared_init_once, shared_init);
286         
287 #ifdef DEBUG
288         g_message ("%s: Creating new handle of type %s", __func__,
289                    _wapi_handle_typename[type]);
290 #endif
291
292         g_assert(!_WAPI_FD_HANDLE(type));
293         
294         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
295                               (void *)&scan_mutex);
296         thr_ret = mono_mutex_lock (&scan_mutex);
297         g_assert (thr_ret == 0);
298                 
299         while ((handle_idx = _wapi_handle_new_internal (type, handle_specific)) == 0) {
300                 /* Try and expand the array, and have another go */
301                 int idx = SLOT_INDEX (_wapi_private_handle_count);
302                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
303                                                 _WAPI_HANDLE_INITIAL_COUNT);
304
305                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
306         }
307
308         thr_ret = mono_mutex_unlock (&scan_mutex);
309         g_assert (thr_ret == 0);
310         pthread_cleanup_pop (0);
311                 
312         /* Make sure we left the space for fd mappings */
313         g_assert (handle_idx >= _wapi_fd_reserve);
314         
315         handle = GUINT_TO_POINTER (handle_idx);
316
317 #ifdef DEBUG
318         g_message ("%s: Allocated new handle %p", __func__, handle);
319 #endif
320         
321         if (_WAPI_SHARED_HANDLE(type)) {
322                 /* Add the shared section too */
323                 guint32 ref;
324                 
325                 ref = _wapi_handle_new_shared (type, handle_specific);
326                 if (ref == 0) {
327                         _wapi_handle_collect ();
328                         ref = _wapi_handle_new_shared (type, handle_specific);
329                         if (ref == 0) {
330                                 /* FIXME: grow the arrays */
331                                 handle = _WAPI_HANDLE_INVALID;
332                                 goto done;
333                         }
334                 }
335                 
336                 _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = ref;
337 #ifdef DEBUG
338                 g_message ("%s: New shared handle at offset 0x%x", __func__,
339                            ref);
340 #endif
341         }
342                 
343 done:
344         return(handle);
345 }
346
347 gpointer _wapi_handle_new_from_offset (WapiHandleType type, guint32 offset,
348                                        gboolean timestamp)
349 {
350         guint32 handle_idx = 0;
351         gpointer handle = INVALID_HANDLE_VALUE;
352         int thr_ret, i, k;
353         struct _WapiHandleShared *shared;
354         guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
355         
356         mono_once (&shared_init_once, shared_init);
357
358 #ifdef DEBUG
359         g_message ("%s: Creating new handle of type %s to offset %d", __func__,
360                    _wapi_handle_typename[type], offset);
361 #endif
362
363         g_assert(!_WAPI_FD_HANDLE(type));
364         g_assert(_WAPI_SHARED_HANDLE(type));
365         g_assert(offset != 0);
366
367         shared = &_wapi_shared_layout->handles[offset];
368         if (timestamp) {
369                 /* Bump up the timestamp for this offset */
370                 InterlockedExchange (&shared->timestamp, now);
371         }
372                 
373         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
374                               (void *)&scan_mutex);
375         thr_ret = mono_mutex_lock (&scan_mutex);
376         g_assert (thr_ret == 0);
377
378         for (i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
379                 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
380                         struct _WapiHandleUnshared *handle_data = &_wapi_private_handles [i][k];
381                 
382                         if (handle_data->type == type &&
383                             handle_data->u.shared.offset == offset) {
384                                 handle = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
385                                 goto first_pass_done;
386                         }
387                 }
388         }
389
390 first_pass_done:
391         thr_ret = mono_mutex_unlock (&scan_mutex);
392         g_assert (thr_ret == 0);
393         pthread_cleanup_pop (0);
394
395         if (handle != INVALID_HANDLE_VALUE) {
396                 _wapi_handle_ref (handle);
397
398 #ifdef DEBUG
399                 g_message ("%s: Returning old handle %p referencing 0x%x",
400                            __func__, handle, offset);
401 #endif
402                 return (handle);
403         }
404
405         /* Prevent entries expiring under us as we search */
406         thr_ret = _wapi_handle_lock_shared_handles ();
407         g_assert (thr_ret == 0);
408         
409         if (shared->type == WAPI_HANDLE_UNUSED) {
410                 /* Someone deleted this handle while we were working */
411                 goto done;
412         }
413         
414         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
415                               (void *)&scan_mutex);
416         thr_ret = mono_mutex_lock (&scan_mutex);
417         g_assert (thr_ret == 0);
418         
419         while ((handle_idx = _wapi_handle_new_internal (type, NULL)) == 0) {
420                 /* Try and expand the array, and have another go */
421                 int idx = SLOT_INDEX (_wapi_private_handle_count);
422                 _wapi_private_handles [idx] = g_new0 (struct _WapiHandleUnshared,
423                                                 _WAPI_HANDLE_INITIAL_COUNT);
424
425                 _wapi_private_handle_count += _WAPI_HANDLE_INITIAL_COUNT;
426         }
427                 
428         thr_ret = mono_mutex_unlock (&scan_mutex);
429         g_assert (thr_ret == 0);
430         pthread_cleanup_pop (0);
431                 
432         /* Make sure we left the space for fd mappings */
433         g_assert (handle_idx >= _wapi_fd_reserve);
434         
435         handle = GUINT_TO_POINTER (handle_idx);
436                 
437         _WAPI_PRIVATE_HANDLES(handle_idx).u.shared.offset = offset;
438         InterlockedIncrement (&shared->handle_refs);
439         
440 #ifdef DEBUG
441         g_message ("%s: Allocated new handle %p referencing 0x%x", __func__,
442                    handle, offset);
443 #endif
444         
445 done:
446         _wapi_handle_unlock_shared_handles ();
447
448         return(handle);
449 }
450
451 gpointer _wapi_handle_new_fd (WapiHandleType type, int fd,
452                               gpointer handle_specific)
453 {
454         struct _WapiHandleUnshared *handle;
455         int thr_ret;
456         
457         mono_once (&shared_init_once, shared_init);
458         
459 #ifdef DEBUG
460         g_message ("%s: Creating new handle of type %s", __func__,
461                    _wapi_handle_typename[type]);
462 #endif
463         
464         g_assert(_WAPI_FD_HANDLE(type));
465         g_assert(!_WAPI_SHARED_HANDLE(type));
466         
467         if (fd >= _wapi_fd_reserve) {
468 #ifdef DEBUG
469                 g_message ("%s: fd %d is too big", __func__, fd);
470 #endif
471
472                 return(GUINT_TO_POINTER (_WAPI_HANDLE_INVALID));
473         }
474
475         handle = &_WAPI_PRIVATE_HANDLES(fd);
476         
477         if (handle->type != WAPI_HANDLE_UNUSED) {
478 #ifdef DEBUG
479                 g_message ("%s: fd %d is already in use!", __func__, fd);
480 #endif
481                 /* FIXME: clean up this handle?  We can't do anything
482                  * with the fd, cos thats the new one
483                  */
484         }
485
486 #ifdef DEBUG
487         g_message ("%s: Assigning new fd handle %d", __func__, fd);
488 #endif
489
490         /* Prevent file share entries racing with us, when the file
491          * handle is only half initialised
492          */
493         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
494         g_assert(thr_ret == 0);
495
496         _wapi_handle_init (handle, type, handle_specific);
497
498         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
499
500         return(GUINT_TO_POINTER(fd));
501 }
502
503 gboolean _wapi_lookup_handle (gpointer handle, WapiHandleType type,
504                               gpointer *handle_specific)
505 {
506         struct _WapiHandleUnshared *handle_data;
507         guint32 handle_idx = GPOINTER_TO_UINT(handle);
508
509         handle_data = &_WAPI_PRIVATE_HANDLES(handle_idx);
510         
511         if (handle_data->type != type) {
512                 return(FALSE);
513         }
514
515         if (handle_specific == NULL) {
516                 return(FALSE);
517         }
518         
519         if (_WAPI_SHARED_HANDLE(type)) {
520                 struct _WapiHandle_shared_ref *ref;
521                 struct _WapiHandleShared *shared_handle_data;
522                         
523                 ref = &handle_data->u.shared;
524                 shared_handle_data = &_wapi_shared_layout->handles[ref->offset];
525                 
526                 g_assert(shared_handle_data->type == type);
527                 
528                 *handle_specific = &shared_handle_data->u;
529         } else {
530                 *handle_specific = &handle_data->u;
531         }
532         
533         return(TRUE);
534 }
535
536 void
537 _wapi_handle_foreach (WapiHandleType type,
538                         gboolean (*on_each)(gpointer test, gpointer user),
539                         gpointer user_data)
540 {
541         struct _WapiHandleUnshared *handle_data = NULL;
542         gpointer ret = NULL;
543         guint32 i, k;
544         int thr_ret;
545
546         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
547                               (void *)&scan_mutex);
548         thr_ret = mono_mutex_lock (&scan_mutex);
549         g_assert (thr_ret == 0);
550
551         for (i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
552                 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
553                         handle_data = &_wapi_private_handles [i][k];
554                 
555                         if (handle_data->type == type) {
556                                 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
557                                 if (on_each (ret, user_data) == TRUE)
558                                         break;
559                         }
560                 }
561         }
562
563         thr_ret = mono_mutex_unlock (&scan_mutex);
564         g_assert (thr_ret == 0);
565         pthread_cleanup_pop (0);
566 }
567
568 /* This might list some shared handles twice if they are already
569  * opened by this process, and the check function returns FALSE the
570  * first time.  Shared handles that are created during the search are
571  * unreffed if the check function returns FALSE, so callers must not
572  * rely on the handle persisting (unless the check function returns
573  * TRUE)
574  */
575 gpointer _wapi_search_handle (WapiHandleType type,
576                               gboolean (*check)(gpointer test, gpointer user),
577                               gpointer user_data,
578                               gpointer *handle_specific)
579 {
580         struct _WapiHandleUnshared *handle_data = NULL;
581         struct _WapiHandleShared *shared;
582         gpointer ret = NULL;
583         guint32 i, k;
584         gboolean found = FALSE;
585         int thr_ret;
586
587         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
588                               (void *)&scan_mutex);
589         thr_ret = mono_mutex_lock (&scan_mutex);
590         g_assert (thr_ret == 0);
591         
592         for (i = SLOT_INDEX (0); !found && _wapi_private_handles [i] != NULL; i++) {
593                 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
594                         handle_data = &_wapi_private_handles [i][k];
595                 
596                         if (handle_data->type == type) {
597                                 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
598                                 if (check (ret, user_data) == TRUE) {
599                                         found = TRUE;
600                                         break;
601                                 }
602                         }
603                 }
604         }
605
606         thr_ret = mono_mutex_unlock (&scan_mutex);
607         g_assert (thr_ret == 0);
608         pthread_cleanup_pop (0);
609
610         if (!found && _WAPI_SHARED_HANDLE (type)) {
611                 /* Not found yet, so search the shared memory too */
612 #ifdef DEBUG
613                 g_message ("%s: Looking at other shared handles...", __func__);
614 #endif
615
616                 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
617                         shared = &_wapi_shared_layout->handles[i];
618                         
619                         if (shared->type == type) {
620                                 /* Tell new_from_offset to not
621                                  * timestamp this handle, because
622                                  * otherwise it will ping every handle
623                                  * in the list and they will never
624                                  * expire
625                                  */
626                                 ret = _wapi_handle_new_from_offset (type, i,
627                                                                     FALSE);
628                                 if (ret == INVALID_HANDLE_VALUE) {
629                                         /* This handle was deleted
630                                          * while we were looking at it
631                                          */
632                                         continue;
633                                 }
634                                 
635 #ifdef DEBUG
636                                 g_message ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
637 #endif
638
639                                 if (check (ret, user_data) == TRUE) {
640                                         /* Timestamp this handle, but make
641                                          * sure it still exists first
642                                          */
643                                         thr_ret = _wapi_handle_lock_shared_handles ();
644                                         g_assert (thr_ret == 0);
645                                         
646                                         if (shared->type == type) {
647                                                 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
648                                                 InterlockedExchange (&shared->timestamp, now);
649
650                                                 found = TRUE;
651                                                 handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
652                                         
653                                                 _wapi_handle_unlock_shared_handles ();
654                                                 break;
655                                         } else {
656                                                 /* It's been deleted,
657                                                  * so just keep
658                                                  * looking
659                                                  */
660                                                 _wapi_handle_unlock_shared_handles ();
661                                         }
662                                 }
663                                 
664                                 /* This isn't the handle we're looking
665                                  * for, so drop the reference we took
666                                  * in _wapi_handle_new_from_offset ()
667                                  */
668                                 _wapi_handle_unref (ret);
669                         }
670                 }
671         }
672         
673         if (!found) {
674                 goto done;
675         }
676         
677         if(handle_specific != NULL) {
678                 if (_WAPI_SHARED_HANDLE(type)) {
679                         g_assert(shared->type == type);
680                         
681                         *handle_specific = &shared->u;
682                 } else {
683                         *handle_specific = &handle_data->u;
684                 }
685         }
686
687 done:
688         return(ret);
689 }
690
691 /* Returns the offset of the metadata array, or -1 on error, or 0 for
692  * not found (0 is not a valid offset)
693  */
694 gint32 _wapi_search_handle_namespace (WapiHandleType type,
695                                       gchar *utf8_name)
696 {
697         struct _WapiHandleShared *shared_handle_data;
698         guint32 i;
699         gint32 ret = 0;
700         int thr_ret;
701         
702         g_assert(_WAPI_SHARED_HANDLE(type));
703         
704 #ifdef DEBUG
705         g_message ("%s: Lookup for handle named [%s] type %s", __func__,
706                    utf8_name, _wapi_handle_typename[type]);
707 #endif
708
709         thr_ret = _wapi_handle_lock_shared_handles ();
710         g_assert (thr_ret == 0);
711         
712         for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
713                 WapiSharedNamespace *sharedns;
714                 
715                 shared_handle_data = &_wapi_shared_layout->handles[i];
716
717                 /* Check mutex, event, semaphore, timer, job and file-mapping
718                  * object names.  So far only mutex is implemented.
719                  */
720                 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
721                         continue;
722                 }
723
724 #ifdef DEBUG
725                 g_message ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
726 #endif
727
728                 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
729                         
730 #ifdef DEBUG
731                 g_message ("%s: name is [%s]", __func__, sharedns->name);
732 #endif
733
734                 if (strcmp (sharedns->name, utf8_name) == 0) {
735                         if (shared_handle_data->type != type) {
736                                 /* Its the wrong type, so fail now */
737 #ifdef DEBUG
738                                 g_message ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
739 #endif
740                                 ret = -1;
741                                 goto done;
742                         } else {
743 #ifdef DEBUG
744                                 g_message ("%s: handle 0x%x matches name and type", __func__, i);
745 #endif
746                                 ret = i;
747                                 goto done;
748                         }
749                 }
750         }
751
752 done:
753         _wapi_handle_unlock_shared_handles ();
754         
755         return(ret);
756 }
757
758 void _wapi_handle_ref (gpointer handle)
759 {
760         guint32 idx = GPOINTER_TO_UINT(handle);
761         guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
762         struct _WapiHandleUnshared *handle_data = &_WAPI_PRIVATE_HANDLES(idx);
763         
764         InterlockedIncrement (&handle_data->ref);
765
766         /* It's possible for processes to exit before getting around
767          * to updating timestamps in the collection thread, so if a
768          * shared handle is reffed do the timestamp here as well just
769          * to make sure.
770          */
771         if (_WAPI_SHARED_HANDLE(handle_data->type)) {
772                 struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
773                 
774                 InterlockedExchange (&shared_data->timestamp, now);
775         }
776         
777 #ifdef DEBUG_REFS
778         g_message ("%s: handle %p ref now %d", __func__, handle,
779                    _WAPI_PRIVATE_HANDLES(idx).ref);
780 #endif
781 }
782
783 /* The handle must not be locked on entry to this function */
784 void _wapi_handle_unref (gpointer handle)
785 {
786         guint32 idx = GPOINTER_TO_UINT(handle);
787         gboolean destroy = FALSE;
788         int thr_ret;
789
790         /* Possible race condition here if another thread refs the
791          * handle between here and setting the type to UNUSED.  I
792          * could lock a mutex, but I'm not sure that allowing a handle
793          * reference to reach 0 isn't an application bug anyway.
794          */
795         destroy = (InterlockedDecrement (&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
796         
797 #ifdef DEBUG_REFS
798         g_message ("%s: handle %p ref now %d (destroy %s)", __func__, handle,
799                    _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
800 #endif
801         
802         if(destroy==TRUE) {
803                 /* Need to copy the handle info, reset the slot in the
804                  * array, and _only then_ call the close function to
805                  * avoid race conditions (eg file descriptors being
806                  * closed, and another file being opened getting the
807                  * same fd racing the memset())
808                  */
809                 struct _WapiHandleUnshared handle_data;
810                 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
811                 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
812                 gboolean is_shared = _WAPI_SHARED_HANDLE(type);
813
814                 if (is_shared) {
815                         /* If this is a shared handle we need to take
816                          * the shared lock outside of the scan_mutex
817                          * lock to avoid deadlocks
818                          */
819                         thr_ret = _wapi_handle_lock_shared_handles ();
820                         g_assert (thr_ret == 0);
821                 }
822                 
823                 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup, (void *)&scan_mutex);
824                 thr_ret = mono_mutex_lock (&scan_mutex);
825
826 #ifdef DEBUG
827                 g_message ("%s: Destroying handle %p", __func__, handle);
828 #endif
829                 
830                 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
831                         sizeof (struct _WapiHandleUnshared));
832
833                 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
834                         sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
835
836                 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
837                 
838                 if (!_WAPI_SHARED_HANDLE(type)) {
839                         /* Destroy the mutex and cond var.  We hope nobody
840                          * tried to grab them between the handle unlock and
841                          * now, but pthreads doesn't have a
842                          * "unlock_and_destroy" atomic function.
843                          */
844                         thr_ret = mono_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
845                         g_assert (thr_ret == 0);
846                                 
847                         thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
848                         g_assert (thr_ret == 0);
849                 } else {
850                         struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
851                         
852                         if (InterlockedDecrement (&shared->handle_refs) == 0) {
853                                 memset (shared, '\0',
854                                         sizeof (struct _WapiHandleShared));
855                         }
856                 }
857
858                 thr_ret = mono_mutex_unlock (&scan_mutex);
859                 g_assert (thr_ret == 0);
860                 pthread_cleanup_pop (0);
861
862                 if (is_shared) {
863                         _wapi_handle_unlock_shared_handles ();
864                 }
865                 
866                 if (close_func != NULL) {
867                         close_func (handle, &handle_data.u);
868                 }
869         }
870 }
871
872 void _wapi_handle_register_capabilities (WapiHandleType type,
873                                          WapiHandleCapability caps)
874 {
875         handle_caps[type] = caps;
876 }
877
878 gboolean _wapi_handle_test_capabilities (gpointer handle,
879                                          WapiHandleCapability caps)
880 {
881         guint32 idx = GPOINTER_TO_UINT(handle);
882         WapiHandleType type;
883
884         type = _WAPI_PRIVATE_HANDLES(idx).type;
885
886 #ifdef DEBUG
887         g_message ("%s: testing 0x%x against 0x%x (%d)", __func__,
888                    handle_caps[type], caps, handle_caps[type] & caps);
889 #endif
890         
891         return((handle_caps[type] & caps) != 0);
892 }
893
894 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
895 {
896         if (handle_ops[type] != NULL &&
897             handle_ops[type]->close != NULL) {
898                 return (handle_ops[type]->close);
899         }
900
901         return (NULL);
902 }
903
904 void _wapi_handle_ops_close (gpointer handle, gpointer data)
905 {
906         guint32 idx = GPOINTER_TO_UINT(handle);
907         WapiHandleType type;
908
909         type = _WAPI_PRIVATE_HANDLES(idx).type;
910
911         if (handle_ops[type] != NULL &&
912             handle_ops[type]->close != NULL) {
913                 handle_ops[type]->close (handle, data);
914         }
915 }
916
917 void _wapi_handle_ops_signal (gpointer handle)
918 {
919         guint32 idx = GPOINTER_TO_UINT(handle);
920         WapiHandleType type;
921
922         type = _WAPI_PRIVATE_HANDLES(idx).type;
923
924         if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
925                 handle_ops[type]->signal (handle);
926         }
927 }
928
929 gboolean _wapi_handle_ops_own (gpointer handle)
930 {
931         guint32 idx = GPOINTER_TO_UINT(handle);
932         WapiHandleType type;
933         
934         type = _WAPI_PRIVATE_HANDLES(idx).type;
935
936         if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
937                 return(handle_ops[type]->own_handle (handle));
938         } else {
939                 return(FALSE);
940         }
941 }
942
943 gboolean _wapi_handle_ops_isowned (gpointer handle)
944 {
945         guint32 idx = GPOINTER_TO_UINT(handle);
946         WapiHandleType type;
947
948         type = _WAPI_PRIVATE_HANDLES(idx).type;
949
950         if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
951                 return(handle_ops[type]->is_owned (handle));
952         } else {
953                 return(FALSE);
954         }
955 }
956
957 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout)
958 {
959         guint32 idx = GPOINTER_TO_UINT(handle);
960         WapiHandleType type;
961         
962         type = _WAPI_PRIVATE_HANDLES(idx).type;
963         
964         if (handle_ops[type] != NULL &&
965             handle_ops[type]->special_wait != NULL) {
966                 return(handle_ops[type]->special_wait (handle, timeout));
967         } else {
968                 return(WAIT_FAILED);
969         }
970 }
971
972
973 /**
974  * CloseHandle:
975  * @handle: The handle to release
976  *
977  * Closes and invalidates @handle, releasing any resources it
978  * consumes.  When the last handle to a temporary or non-persistent
979  * object is closed, that object can be deleted.  Closing the same
980  * handle twice is an error.
981  *
982  * Return value: %TRUE on success, %FALSE otherwise.
983  */
984 gboolean CloseHandle(gpointer handle)
985 {
986         _wapi_handle_unref (handle);
987         
988         return(TRUE);
989 }
990
991 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
992                                                gpointer *handles,
993                                                gboolean waitall,
994                                                guint32 *retcount,
995                                                guint32 *lowest)
996 {
997         guint32 count, i, iter=0;
998         gboolean ret;
999         int thr_ret;
1000         WapiHandleType type;
1001         
1002         /* Lock all the handles, with backoff */
1003 again:
1004         thr_ret = _wapi_handle_lock_shared_handles ();
1005         g_assert (thr_ret == 0);
1006         
1007         for(i=0; i<numhandles; i++) {
1008                 gpointer handle = handles[i];
1009                 guint32 idx = GPOINTER_TO_UINT(handle);
1010
1011 #ifdef DEBUG
1012                 g_message ("%s: attempting to lock %p", __func__, handle);
1013 #endif
1014
1015                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1016
1017                 thr_ret = _wapi_handle_trylock_handle (handle);
1018                 
1019                 if (thr_ret != 0) {
1020                         /* Bummer */
1021                         
1022 #ifdef DEBUG
1023                         g_message ("%s: attempt failed for %p: %s", __func__,
1024                                    handle, strerror (thr_ret));
1025 #endif
1026
1027                         thr_ret = _wapi_handle_unlock_shared_handles ();
1028                         g_assert (thr_ret == 0);
1029                         
1030                         while (i--) {
1031                                 handle = handles[i];
1032                                 idx = GPOINTER_TO_UINT(handle);
1033
1034                                 thr_ret = _wapi_handle_unlock_handle (handle);
1035                                 g_assert (thr_ret == 0);
1036                         }
1037
1038                         /* If iter ever reaches 100 the nanosleep will
1039                          * return EINVAL immediately, but we have a
1040                          * design flaw if that happens.
1041                          */
1042                         iter++;
1043                         if(iter==100) {
1044                                 g_warning ("%s: iteration overflow!",
1045                                            __func__);
1046                                 iter=1;
1047                         }
1048                         
1049 #ifdef DEBUG
1050                         g_message ("%s: Backing off for %d ms", __func__,
1051                                    iter*10);
1052 #endif
1053                         _wapi_handle_spin (10 * iter);
1054                         
1055                         goto again;
1056                 }
1057         }
1058         
1059 #ifdef DEBUG
1060         g_message ("%s: Locked all handles", __func__);
1061 #endif
1062
1063         count=0;
1064         *lowest=numhandles;
1065         
1066         for(i=0; i<numhandles; i++) {
1067                 gpointer handle = handles[i];
1068                 guint32 idx = GPOINTER_TO_UINT(handle);
1069                 
1070                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1071
1072                 _wapi_handle_ref (handle);
1073                 
1074 #ifdef DEBUG
1075                 g_message ("%s: Checking handle %p", __func__, handle);
1076 #endif
1077
1078                 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1079                     (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1080                    (_WAPI_SHARED_HANDLE(type) &&
1081                     WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) ||
1082                    (!_WAPI_SHARED_HANDLE(type) &&
1083                     _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
1084                         count++;
1085                         
1086 #ifdef DEBUG
1087                         g_message ("%s: Handle %p signalled", __func__,
1088                                    handle);
1089 #endif
1090                         if(*lowest>i) {
1091                                 *lowest=i;
1092                         }
1093                 }
1094         }
1095         
1096 #ifdef DEBUG
1097         g_message ("%s: %d event handles signalled", __func__, count);
1098 #endif
1099
1100         if ((waitall == TRUE && count == numhandles) ||
1101             (waitall == FALSE && count > 0)) {
1102                 ret=TRUE;
1103         } else {
1104                 ret=FALSE;
1105         }
1106         
1107 #ifdef DEBUG
1108         g_message ("%s: Returning %d", __func__, ret);
1109 #endif
1110
1111         *retcount=count;
1112         
1113         return(ret);
1114 }
1115
1116 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1117 {
1118         guint32 i;
1119         int thr_ret;
1120         
1121         thr_ret = _wapi_handle_unlock_shared_handles ();
1122         g_assert (thr_ret == 0);
1123         
1124         for(i=0; i<numhandles; i++) {
1125                 gpointer handle = handles[i];
1126                 
1127 #ifdef DEBUG
1128                 g_message ("%s: unlocking handle %p", __func__, handle);
1129 #endif
1130
1131                 thr_ret = _wapi_handle_unlock_handle (handle);
1132                 g_assert (thr_ret == 0);
1133         }
1134 }
1135
1136 static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout)
1137 {
1138         struct timespec fake_timeout;
1139         int ret;
1140         
1141         _wapi_calc_timeout (&fake_timeout, 100);
1142         
1143         if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
1144            (fake_timeout.tv_sec == timeout->tv_sec &&
1145                 fake_timeout.tv_nsec > timeout->tv_nsec))) {
1146                 /* Real timeout is less than 100ms time */
1147                 ret=mono_cond_timedwait (cond, mutex, timeout);
1148         } else {
1149                 ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
1150
1151                 /* Mask the fake timeout, this will cause
1152                  * another poll if the cond was not really signaled
1153                  */
1154                 if (ret==ETIMEDOUT) {
1155                         ret=0;
1156                 }
1157         }
1158         
1159         return(ret);
1160 }
1161
1162 int _wapi_handle_wait_signal (void)
1163 {
1164         return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, NULL);
1165 }
1166
1167 int _wapi_handle_timedwait_signal (struct timespec *timeout)
1168 {
1169         return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout);
1170 }
1171
1172 int _wapi_handle_wait_signal_handle (gpointer handle)
1173 {
1174 #ifdef DEBUG
1175         g_message ("%s: waiting for %p", __func__, handle);
1176 #endif
1177         
1178         return _wapi_handle_timedwait_signal_handle (handle, NULL);
1179 }
1180
1181 int _wapi_handle_timedwait_signal_handle (gpointer handle,
1182                                           struct timespec *timeout)
1183 {
1184 #ifdef DEBUG
1185         g_message ("%s: waiting for %p (type %s)", __func__, handle,
1186                    _wapi_handle_typename[_wapi_handle_type (handle)]);
1187 #endif
1188         
1189         if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1190                 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1191                         return (0);
1192                 }
1193                 if (timeout != NULL) {
1194                         struct timespec fake_timeout;
1195                         _wapi_calc_timeout (&fake_timeout, 100);
1196                 
1197                         if ((fake_timeout.tv_sec > timeout->tv_sec) ||
1198                                 (fake_timeout.tv_sec == timeout->tv_sec &&
1199                                  fake_timeout.tv_nsec > timeout->tv_nsec)) {
1200                                 /* FIXME: Real timeout is less than
1201                                  * 100ms time, but is it really worth
1202                                  * calculating to the exact ms?
1203                                  */
1204                                 _wapi_handle_spin (100);
1205
1206                                 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1207                                         return (0);
1208                                 } else {
1209                                         return (ETIMEDOUT);
1210                                 }
1211                         }
1212                 }
1213                 _wapi_handle_spin (100);
1214                 return (0);
1215                 
1216         } else {
1217                 guint32 idx = GPOINTER_TO_UINT(handle);
1218                 return timedwait_signal_poll_cond (&_WAPI_PRIVATE_HANDLES(idx).signal_cond, &_WAPI_PRIVATE_HANDLES(idx).signal_mutex, timeout);
1219         }
1220 }
1221
1222 gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
1223                                         guint32 new_sharemode,
1224                                         guint32 new_access,
1225                                         guint32 *old_sharemode,
1226                                         guint32 *old_access,
1227                                         struct _WapiFileShare **share_info)
1228 {
1229         struct _WapiFileShare *file_share;
1230         guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1231         int thr_ret, i, first_unused = -1;
1232         gboolean exists = FALSE;
1233         
1234         /* Prevents entries from expiring under us as we search
1235          */
1236         thr_ret = _wapi_handle_lock_shared_handles ();
1237         g_assert (thr_ret == 0);
1238         
1239         /* Prevent new entries racing with us */
1240         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1241         g_assert (thr_ret == 0);
1242         
1243         /* If a linear scan gets too slow we'll have to fit a hash
1244          * table onto the shared mem backing store
1245          */
1246         *share_info = NULL;
1247         for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
1248                 file_share = &_wapi_fileshare_layout->share_info[i];
1249
1250                 /* Make a note of an unused slot, in case we need to
1251                  * store share info
1252                  */
1253                 if (first_unused == -1 && file_share->handle_refs == 0) {
1254                         first_unused = i;
1255                         continue;
1256                 }
1257                 
1258                 if (file_share->handle_refs == 0) {
1259                         continue;
1260                 }
1261                 
1262                 if (file_share->device == device &&
1263                     file_share->inode == inode) {
1264                         *old_sharemode = file_share->sharemode;
1265                         *old_access = file_share->access;
1266                         *share_info = file_share;
1267                         
1268                         /* Increment the reference count while we
1269                          * still have sole access to the shared area.
1270                          * This makes the increment atomic wrt
1271                          * collections
1272                          */
1273                         InterlockedIncrement (&file_share->handle_refs);
1274                         
1275                         exists = TRUE;
1276                         break;
1277                 }
1278         }
1279         
1280         if (!exists) {
1281                 if (i == _WAPI_FILESHARE_SIZE && first_unused == -1) {
1282                         /* No more space */
1283                 } else {
1284                         if (first_unused == -1) {
1285                                 file_share = &_wapi_fileshare_layout->share_info[++i];
1286                                 _wapi_fileshare_layout->hwm = i;
1287                         } else {
1288                                 file_share = &_wapi_fileshare_layout->share_info[first_unused];
1289                         }
1290                         
1291                         file_share->device = device;
1292                         file_share->inode = inode;
1293                         file_share->opened_by_pid = getpid ();
1294                         file_share->sharemode = new_sharemode;
1295                         file_share->access = new_access;
1296                         file_share->handle_refs = 1;
1297                         *share_info = file_share;
1298                 }
1299         }
1300
1301         if (*share_info != NULL) {
1302                 InterlockedExchange (&(*share_info)->timestamp, now);
1303         }
1304         
1305         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1306
1307         _wapi_handle_unlock_shared_handles ();
1308
1309         return(exists);
1310 }
1311
1312 /* If we don't have the info in /proc, check if the process that
1313  * opened this share info is still there (it's not a perfect method,
1314  * due to pid reuse)
1315  */
1316 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
1317 {
1318         if (kill (share_info->opened_by_pid, 0) == -1 &&
1319             (errno == ESRCH ||
1320              errno == EPERM)) {
1321                 /* It's gone completely (or there's a new process
1322                  * owned by someone else) so mark this share info as
1323                  * dead
1324                  */
1325 #ifdef DEBUG
1326                 g_message ("%s: Didn't find it, destroying entry", __func__);
1327 #endif
1328
1329                 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1330         }
1331 }
1332
1333 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1334  * question.  If there are none, reset the share info.
1335  *
1336  * This implementation is Linux-specific; legacy systems will have to
1337  * implement their own ways of finding out if a particular file is
1338  * open by a process.
1339  */
1340 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1341 {
1342         gboolean found = FALSE, proc_fds = FALSE;
1343         pid_t self = getpid();
1344         int pid;
1345         int thr_ret, i;
1346         
1347         /* Prevents entries from expiring under us if we remove this
1348          * one
1349          */
1350         thr_ret = _wapi_handle_lock_shared_handles ();
1351         g_assert (thr_ret == 0);
1352         
1353         /* Prevent new entries racing with us */
1354         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1355         g_assert (thr_ret == 0);
1356         
1357         /* If there is no /proc, there's nothing more we can do here */
1358         if (access ("/proc", F_OK) == -1) {
1359                 _wapi_handle_check_share_by_pid (share_info);
1360                 goto done;
1361         }
1362
1363         /* If there's another handle that thinks it owns this fd, then even
1364          * if the fd has been closed behind our back consider it still owned.
1365          * See bugs 75764 and 75891
1366          */
1367         for (i = 0; i < _wapi_fd_reserve; i++) {
1368                 struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
1369
1370                 if (i != fd &&
1371                     handle->type == WAPI_HANDLE_FILE) {
1372                         struct _WapiHandle_file *file_handle = &handle->u.file;
1373
1374                         if (file_handle->share_info == share_info) {
1375 #ifdef DEBUG
1376                                 g_message ("%s: handle 0x%x has this file open!",
1377                                            __func__, i);
1378 #endif
1379
1380                                 goto done;
1381                         }
1382                 }
1383         }
1384
1385         for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
1386                 struct _WapiHandleShared *shared;
1387                 struct _WapiHandle_process *process_handle;
1388
1389                 shared = &_wapi_shared_layout->handles[i];
1390                 
1391                 if (shared->type == WAPI_HANDLE_PROCESS) {
1392                         DIR *fd_dir;
1393                         struct dirent *fd_entry;
1394                         char subdir[_POSIX_PATH_MAX];
1395
1396                         process_handle = &shared->u.process;
1397                         pid = process_handle->id;
1398                 
1399                         /* Look in /proc/<pid>/fd/ but ignore
1400                          * /proc/<our pid>/fd/<fd>, as we have the
1401                          * file open too
1402                          */
1403                         g_snprintf (subdir, _POSIX_PATH_MAX, "/proc/%d/fd",
1404                                     pid);
1405                         
1406                         fd_dir = opendir (subdir);
1407                         if (fd_dir == NULL) {
1408                                 continue;
1409                         }
1410
1411 #ifdef DEBUG
1412                         g_message ("%s: Looking in %s", __func__, subdir);
1413 #endif
1414                         
1415                         proc_fds = TRUE;
1416                         
1417                         while ((fd_entry = readdir (fd_dir)) != NULL) {
1418                                 char path[_POSIX_PATH_MAX];
1419                                 struct stat link_stat;
1420                                 
1421                                 if (!strcmp (fd_entry->d_name, ".") ||
1422                                     !strcmp (fd_entry->d_name, "..") ||
1423                                     (pid == self &&
1424                                      fd == atoi (fd_entry->d_name))) {
1425                                         continue;
1426                                 }
1427
1428                                 g_snprintf (path, _POSIX_PATH_MAX,
1429                                             "/proc/%d/fd/%s", pid,
1430                                             fd_entry->d_name);
1431                                 
1432                                 stat (path, &link_stat);
1433                                 if (link_stat.st_dev == share_info->device &&
1434                                     link_stat.st_ino == share_info->inode) {
1435 #ifdef DEBUG
1436                                         g_message ("%s:  Found it at %s",
1437                                                    __func__, path);
1438 #endif
1439
1440                                         found = TRUE;
1441                                 }
1442                         }
1443                         
1444                         closedir (fd_dir);
1445                 }
1446         }
1447
1448         if (proc_fds == FALSE) {
1449                 _wapi_handle_check_share_by_pid (share_info);
1450         } else if (found == FALSE) {
1451                 /* Blank out this entry, as it is stale */
1452 #ifdef DEBUG
1453                 g_message ("%s: Didn't find it, destroying entry", __func__);
1454 #endif
1455
1456                 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1457         }
1458
1459 done:
1460         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1461
1462         _wapi_handle_unlock_shared_handles ();
1463 }
1464
1465 void _wapi_handle_dump (void)
1466 {
1467         struct _WapiHandleUnshared *handle_data;
1468         guint32 i, k;
1469         int thr_ret;
1470         
1471         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
1472                               (void *)&scan_mutex);
1473         thr_ret = mono_mutex_lock (&scan_mutex);
1474         g_assert (thr_ret == 0);
1475         
1476         for(i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
1477                 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1478                         handle_data = &_wapi_private_handles [i][k];
1479
1480                         if (handle_data->type == WAPI_HANDLE_UNUSED) {
1481                                 continue;
1482                         }
1483                 
1484                         g_print ("%3x [%7s] %s %d ",
1485                                  i * _WAPI_HANDLE_INITIAL_COUNT + k,
1486                                  _wapi_handle_typename[handle_data->type],
1487                                  handle_data->signalled?"Sg":"Un",
1488                                  handle_data->ref);
1489                         handle_details[handle_data->type](&handle_data->u);
1490                         g_print ("\n");
1491                 }
1492         }
1493
1494         thr_ret = mono_mutex_unlock (&scan_mutex);
1495         g_assert (thr_ret == 0);
1496         pthread_cleanup_pop (0);
1497 }
1498
1499 static void _wapi_shared_details (gpointer handle_info)
1500 {
1501         struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1502         
1503         g_print ("offset: 0x%x", shared->offset);
1504 }
1505
1506 void _wapi_handle_update_refs (void)
1507 {
1508         guint32 i, k;
1509         int thr_ret;
1510         guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1511         
1512         thr_ret = _wapi_handle_lock_shared_handles ();
1513         g_assert (thr_ret == 0);
1514
1515         /* Prevent file share entries racing with us */
1516         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1517         g_assert(thr_ret == 0);
1518
1519         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
1520                               (void *)&scan_mutex);
1521         thr_ret = mono_mutex_lock (&scan_mutex);
1522         
1523         for(i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
1524                 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1525                         struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
1526
1527                         if (_WAPI_SHARED_HANDLE(handle->type)) {
1528                                 struct _WapiHandleShared *shared_data;
1529                                 
1530 #ifdef DEBUG
1531                                 g_message ("%s: (%d) handle 0x%x is SHARED (%s)", __func__,
1532                                            getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
1533 #endif
1534
1535                                 shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
1536
1537 #ifdef DEBUG
1538                                 g_message ("%s: (%d) Updating timestamp of handle 0x%x",
1539                                            __func__, getpid(),
1540                                            handle->u.shared.offset);
1541 #endif
1542
1543                                 InterlockedExchange (&shared_data->timestamp,
1544                                                      now);
1545                         } else if (handle->type == WAPI_HANDLE_FILE) {
1546                                 struct _WapiHandle_file *file_handle = &handle->u.file;
1547                                 
1548 #ifdef DEBUG
1549                                 g_message ("%s: (%d) handle 0x%x is FILE", __func__,
1550                                            getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
1551 #endif
1552                                 
1553                                 g_assert (file_handle->share_info != NULL);
1554
1555 #ifdef DEBUG
1556                                 g_message ("%s: (%d) Inc refs on fileshare 0x%x",
1557                                            __func__, getpid(),
1558                                            (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
1559 #endif
1560
1561                                 InterlockedExchange (&file_handle->share_info->timestamp, now);
1562                         }
1563                 }
1564         }
1565
1566         thr_ret = mono_mutex_unlock (&scan_mutex);
1567         g_assert (thr_ret == 0);
1568         pthread_cleanup_pop (0);
1569         
1570         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1571
1572         _wapi_handle_unlock_shared_handles ();
1573 }