start populating the new System.Web.Configuration_2.0 dir
[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                 if (shared_handle_data->type != type) {
527                         /* The handle must have been deleted on us
528                          */
529                         return (FALSE);
530                 }
531                 
532                 *handle_specific = &shared_handle_data->u;
533         } else {
534                 *handle_specific = &handle_data->u;
535         }
536         
537         return(TRUE);
538 }
539
540 void
541 _wapi_handle_foreach (WapiHandleType type,
542                         gboolean (*on_each)(gpointer test, gpointer user),
543                         gpointer user_data)
544 {
545         struct _WapiHandleUnshared *handle_data = NULL;
546         gpointer ret = NULL;
547         guint32 i, k;
548         int thr_ret;
549
550         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
551                               (void *)&scan_mutex);
552         thr_ret = mono_mutex_lock (&scan_mutex);
553         g_assert (thr_ret == 0);
554
555         for (i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
556                 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
557                         handle_data = &_wapi_private_handles [i][k];
558                 
559                         if (handle_data->type == type) {
560                                 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
561                                 if (on_each (ret, user_data) == TRUE)
562                                         break;
563                         }
564                 }
565         }
566
567         thr_ret = mono_mutex_unlock (&scan_mutex);
568         g_assert (thr_ret == 0);
569         pthread_cleanup_pop (0);
570 }
571
572 /* This might list some shared handles twice if they are already
573  * opened by this process, and the check function returns FALSE the
574  * first time.  Shared handles that are created during the search are
575  * unreffed if the check function returns FALSE, so callers must not
576  * rely on the handle persisting (unless the check function returns
577  * TRUE)
578  */
579 gpointer _wapi_search_handle (WapiHandleType type,
580                               gboolean (*check)(gpointer test, gpointer user),
581                               gpointer user_data,
582                               gpointer *handle_specific)
583 {
584         struct _WapiHandleUnshared *handle_data = NULL;
585         struct _WapiHandleShared *shared;
586         gpointer ret = NULL;
587         guint32 i, k;
588         gboolean found = FALSE;
589         int thr_ret;
590
591         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
592                               (void *)&scan_mutex);
593         thr_ret = mono_mutex_lock (&scan_mutex);
594         g_assert (thr_ret == 0);
595         
596         for (i = SLOT_INDEX (0); !found && _wapi_private_handles [i] != NULL; i++) {
597                 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
598                         handle_data = &_wapi_private_handles [i][k];
599                 
600                         if (handle_data->type == type) {
601                                 ret = GUINT_TO_POINTER (i * _WAPI_HANDLE_INITIAL_COUNT + k);
602                                 if (check (ret, user_data) == TRUE) {
603                                         found = TRUE;
604                                         break;
605                                 }
606                         }
607                 }
608         }
609
610         thr_ret = mono_mutex_unlock (&scan_mutex);
611         g_assert (thr_ret == 0);
612         pthread_cleanup_pop (0);
613
614         if (!found && _WAPI_SHARED_HANDLE (type)) {
615                 /* Not found yet, so search the shared memory too */
616 #ifdef DEBUG
617                 g_message ("%s: Looking at other shared handles...", __func__);
618 #endif
619
620                 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
621                         shared = &_wapi_shared_layout->handles[i];
622                         
623                         if (shared->type == type) {
624                                 /* Tell new_from_offset to not
625                                  * timestamp this handle, because
626                                  * otherwise it will ping every handle
627                                  * in the list and they will never
628                                  * expire
629                                  */
630                                 ret = _wapi_handle_new_from_offset (type, i,
631                                                                     FALSE);
632                                 if (ret == INVALID_HANDLE_VALUE) {
633                                         /* This handle was deleted
634                                          * while we were looking at it
635                                          */
636                                         continue;
637                                 }
638                                 
639 #ifdef DEBUG
640                                 g_message ("%s: Opened tmp handle %p (type %s) from offset %d", __func__, ret, _wapi_handle_typename[type], i);
641 #endif
642
643                                 /* It's possible that the shared part
644                                  * of this handle has now been blown
645                                  * away (after new_from_offset
646                                  * successfully opened it,) if its
647                                  * timestamp is too old.  The check
648                                  * function needs to be aware of this,
649                                  * and cope if the handle has
650                                  * vanished.
651                                  */
652                                 if (check (ret, user_data) == TRUE) {
653                                         /* Timestamp this handle, but make
654                                          * sure it still exists first
655                                          */
656                                         thr_ret = _wapi_handle_lock_shared_handles ();
657                                         g_assert (thr_ret == 0);
658                                         
659                                         if (shared->type == type) {
660                                                 guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
661                                                 InterlockedExchange (&shared->timestamp, now);
662
663                                                 found = TRUE;
664                                                 handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(ret));
665                                         
666                                                 _wapi_handle_unlock_shared_handles ();
667                                                 break;
668                                         } else {
669                                                 /* It's been deleted,
670                                                  * so just keep
671                                                  * looking
672                                                  */
673                                                 _wapi_handle_unlock_shared_handles ();
674                                         }
675                                 }
676                                 
677                                 /* This isn't the handle we're looking
678                                  * for, so drop the reference we took
679                                  * in _wapi_handle_new_from_offset ()
680                                  */
681                                 _wapi_handle_unref (ret);
682                         }
683                 }
684         }
685         
686         if (!found) {
687                 ret = NULL;
688                 goto done;
689         }
690         
691         if(handle_specific != NULL) {
692                 if (_WAPI_SHARED_HANDLE(type)) {
693                         g_assert(shared->type == type);
694                         
695                         *handle_specific = &shared->u;
696                 } else {
697                         *handle_specific = &handle_data->u;
698                 }
699         }
700
701 done:
702         return(ret);
703 }
704
705 /* Returns the offset of the metadata array, or -1 on error, or 0 for
706  * not found (0 is not a valid offset)
707  */
708 gint32 _wapi_search_handle_namespace (WapiHandleType type,
709                                       gchar *utf8_name)
710 {
711         struct _WapiHandleShared *shared_handle_data;
712         guint32 i;
713         gint32 ret = 0;
714         int thr_ret;
715         
716         g_assert(_WAPI_SHARED_HANDLE(type));
717         
718 #ifdef DEBUG
719         g_message ("%s: Lookup for handle named [%s] type %s", __func__,
720                    utf8_name, _wapi_handle_typename[type]);
721 #endif
722
723         thr_ret = _wapi_handle_lock_shared_handles ();
724         g_assert (thr_ret == 0);
725         
726         for(i = 1; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
727                 WapiSharedNamespace *sharedns;
728                 
729                 shared_handle_data = &_wapi_shared_layout->handles[i];
730
731                 /* Check mutex, event, semaphore, timer, job and file-mapping
732                  * object names.  So far only mutex is implemented.
733                  */
734                 if (!_WAPI_SHARED_NAMESPACE (shared_handle_data->type)) {
735                         continue;
736                 }
737
738 #ifdef DEBUG
739                 g_message ("%s: found a shared namespace handle at 0x%x (type %s)", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
740 #endif
741
742                 sharedns=(WapiSharedNamespace *)&shared_handle_data->u;
743                         
744 #ifdef DEBUG
745                 g_message ("%s: name is [%s]", __func__, sharedns->name);
746 #endif
747
748                 if (strcmp (sharedns->name, utf8_name) == 0) {
749                         if (shared_handle_data->type != type) {
750                                 /* Its the wrong type, so fail now */
751 #ifdef DEBUG
752                                 g_message ("%s: handle 0x%x matches name but is wrong type: %s", __func__, i, _wapi_handle_typename[shared_handle_data->type]);
753 #endif
754                                 ret = -1;
755                                 goto done;
756                         } else {
757 #ifdef DEBUG
758                                 g_message ("%s: handle 0x%x matches name and type", __func__, i);
759 #endif
760                                 ret = i;
761                                 goto done;
762                         }
763                 }
764         }
765
766 done:
767         _wapi_handle_unlock_shared_handles ();
768         
769         return(ret);
770 }
771
772 void _wapi_handle_ref (gpointer handle)
773 {
774         guint32 idx = GPOINTER_TO_UINT(handle);
775         guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
776         struct _WapiHandleUnshared *handle_data = &_WAPI_PRIVATE_HANDLES(idx);
777
778         if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
779                 g_warning ("%s: Attempting to ref unused handle %p", __func__,
780                            handle);
781                 return;
782         }
783         
784         InterlockedIncrement (&handle_data->ref);
785
786         /* It's possible for processes to exit before getting around
787          * to updating timestamps in the collection thread, so if a
788          * shared handle is reffed do the timestamp here as well just
789          * to make sure.
790          */
791         if (_WAPI_SHARED_HANDLE(handle_data->type)) {
792                 struct _WapiHandleShared *shared_data = &_wapi_shared_layout->handles[handle_data->u.shared.offset];
793                 
794                 InterlockedExchange (&shared_data->timestamp, now);
795         }
796         
797 #ifdef DEBUG_REFS
798         g_message ("%s: handle %p ref now %d", __func__, handle,
799                    _WAPI_PRIVATE_HANDLES(idx).ref);
800 #endif
801 }
802
803 /* The handle must not be locked on entry to this function */
804 void _wapi_handle_unref (gpointer handle)
805 {
806         guint32 idx = GPOINTER_TO_UINT(handle);
807         gboolean destroy = FALSE;
808         int thr_ret;
809
810         if (_wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) {
811                 g_warning ("%s: Attempting to unref unused handle %p",
812                            __func__, handle);
813                 return;
814         }
815
816         /* Possible race condition here if another thread refs the
817          * handle between here and setting the type to UNUSED.  I
818          * could lock a mutex, but I'm not sure that allowing a handle
819          * reference to reach 0 isn't an application bug anyway.
820          */
821         destroy = (InterlockedDecrement (&_WAPI_PRIVATE_HANDLES(idx).ref) ==0);
822         
823 #ifdef DEBUG_REFS
824         g_message ("%s: handle %p ref now %d (destroy %s)", __func__, handle,
825                    _WAPI_PRIVATE_HANDLES(idx).ref, destroy?"TRUE":"FALSE");
826 #endif
827         
828         if(destroy==TRUE) {
829                 /* Need to copy the handle info, reset the slot in the
830                  * array, and _only then_ call the close function to
831                  * avoid race conditions (eg file descriptors being
832                  * closed, and another file being opened getting the
833                  * same fd racing the memset())
834                  */
835                 struct _WapiHandleUnshared handle_data;
836                 WapiHandleType type = _WAPI_PRIVATE_HANDLES(idx).type;
837                 void (*close_func)(gpointer, gpointer) = _wapi_handle_ops_get_close_func (type);
838                 gboolean is_shared = _WAPI_SHARED_HANDLE(type);
839
840                 if (is_shared) {
841                         /* If this is a shared handle we need to take
842                          * the shared lock outside of the scan_mutex
843                          * lock to avoid deadlocks
844                          */
845                         thr_ret = _wapi_handle_lock_shared_handles ();
846                         g_assert (thr_ret == 0);
847                 }
848                 
849                 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup, (void *)&scan_mutex);
850                 thr_ret = mono_mutex_lock (&scan_mutex);
851
852 #ifdef DEBUG
853                 g_message ("%s: Destroying handle %p", __func__, handle);
854 #endif
855                 
856                 memcpy (&handle_data, &_WAPI_PRIVATE_HANDLES(idx),
857                         sizeof (struct _WapiHandleUnshared));
858
859                 memset (&_WAPI_PRIVATE_HANDLES(idx).u, '\0',
860                         sizeof(_WAPI_PRIVATE_HANDLES(idx).u));
861
862                 _WAPI_PRIVATE_HANDLES(idx).type = WAPI_HANDLE_UNUSED;
863                 
864                 if (!is_shared) {
865                         /* Destroy the mutex and cond var.  We hope nobody
866                          * tried to grab them between the handle unlock and
867                          * now, but pthreads doesn't have a
868                          * "unlock_and_destroy" atomic function.
869                          */
870                         thr_ret = mono_mutex_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_mutex);
871                         g_assert (thr_ret == 0);
872                                 
873                         thr_ret = pthread_cond_destroy (&_WAPI_PRIVATE_HANDLES(idx).signal_cond);
874                         g_assert (thr_ret == 0);
875                 } else {
876                         struct _WapiHandleShared *shared = &_wapi_shared_layout->handles[handle_data.u.shared.offset];
877                         
878                         /* It's possible that this handle is already
879                          * pointing at a deleted shared section
880                          */
881                         if (shared->handle_refs > 0) {
882                                 shared->handle_refs--;
883                                 if (shared->handle_refs == 0) {
884                                         memset (shared, '\0', sizeof (struct _WapiHandleShared));
885                                 }
886                         }
887                 }
888
889                 thr_ret = mono_mutex_unlock (&scan_mutex);
890                 g_assert (thr_ret == 0);
891                 pthread_cleanup_pop (0);
892
893                 if (is_shared) {
894                         _wapi_handle_unlock_shared_handles ();
895                 }
896                 
897                 if (close_func != NULL) {
898                         close_func (handle, &handle_data.u);
899                 }
900         }
901 }
902
903 void _wapi_handle_register_capabilities (WapiHandleType type,
904                                          WapiHandleCapability caps)
905 {
906         handle_caps[type] = caps;
907 }
908
909 gboolean _wapi_handle_test_capabilities (gpointer handle,
910                                          WapiHandleCapability caps)
911 {
912         guint32 idx = GPOINTER_TO_UINT(handle);
913         WapiHandleType type;
914
915         type = _WAPI_PRIVATE_HANDLES(idx).type;
916
917 #ifdef DEBUG
918         g_message ("%s: testing 0x%x against 0x%x (%d)", __func__,
919                    handle_caps[type], caps, handle_caps[type] & caps);
920 #endif
921         
922         return((handle_caps[type] & caps) != 0);
923 }
924
925 static void (*_wapi_handle_ops_get_close_func (WapiHandleType type))(gpointer, gpointer)
926 {
927         if (handle_ops[type] != NULL &&
928             handle_ops[type]->close != NULL) {
929                 return (handle_ops[type]->close);
930         }
931
932         return (NULL);
933 }
934
935 void _wapi_handle_ops_close (gpointer handle, gpointer data)
936 {
937         guint32 idx = GPOINTER_TO_UINT(handle);
938         WapiHandleType type;
939
940         type = _WAPI_PRIVATE_HANDLES(idx).type;
941
942         if (handle_ops[type] != NULL &&
943             handle_ops[type]->close != NULL) {
944                 handle_ops[type]->close (handle, data);
945         }
946 }
947
948 void _wapi_handle_ops_signal (gpointer handle)
949 {
950         guint32 idx = GPOINTER_TO_UINT(handle);
951         WapiHandleType type;
952
953         type = _WAPI_PRIVATE_HANDLES(idx).type;
954
955         if (handle_ops[type] != NULL && handle_ops[type]->signal != NULL) {
956                 handle_ops[type]->signal (handle);
957         }
958 }
959
960 gboolean _wapi_handle_ops_own (gpointer handle)
961 {
962         guint32 idx = GPOINTER_TO_UINT(handle);
963         WapiHandleType type;
964         
965         type = _WAPI_PRIVATE_HANDLES(idx).type;
966
967         if (handle_ops[type] != NULL && handle_ops[type]->own_handle != NULL) {
968                 return(handle_ops[type]->own_handle (handle));
969         } else {
970                 return(FALSE);
971         }
972 }
973
974 gboolean _wapi_handle_ops_isowned (gpointer handle)
975 {
976         guint32 idx = GPOINTER_TO_UINT(handle);
977         WapiHandleType type;
978
979         type = _WAPI_PRIVATE_HANDLES(idx).type;
980
981         if (handle_ops[type] != NULL && handle_ops[type]->is_owned != NULL) {
982                 return(handle_ops[type]->is_owned (handle));
983         } else {
984                 return(FALSE);
985         }
986 }
987
988 guint32 _wapi_handle_ops_special_wait (gpointer handle, guint32 timeout)
989 {
990         guint32 idx = GPOINTER_TO_UINT(handle);
991         WapiHandleType type;
992         
993         type = _WAPI_PRIVATE_HANDLES(idx).type;
994         
995         if (handle_ops[type] != NULL &&
996             handle_ops[type]->special_wait != NULL) {
997                 return(handle_ops[type]->special_wait (handle, timeout));
998         } else {
999                 return(WAIT_FAILED);
1000         }
1001 }
1002
1003
1004 /**
1005  * CloseHandle:
1006  * @handle: The handle to release
1007  *
1008  * Closes and invalidates @handle, releasing any resources it
1009  * consumes.  When the last handle to a temporary or non-persistent
1010  * object is closed, that object can be deleted.  Closing the same
1011  * handle twice is an error.
1012  *
1013  * Return value: %TRUE on success, %FALSE otherwise.
1014  */
1015 gboolean CloseHandle(gpointer handle)
1016 {
1017         _wapi_handle_unref (handle);
1018         
1019         return(TRUE);
1020 }
1021
1022 gboolean _wapi_handle_count_signalled_handles (guint32 numhandles,
1023                                                gpointer *handles,
1024                                                gboolean waitall,
1025                                                guint32 *retcount,
1026                                                guint32 *lowest)
1027 {
1028         guint32 count, i, iter=0;
1029         gboolean ret;
1030         int thr_ret;
1031         WapiHandleType type;
1032         
1033         /* Lock all the handles, with backoff */
1034 again:
1035         thr_ret = _wapi_handle_lock_shared_handles ();
1036         g_assert (thr_ret == 0);
1037         
1038         for(i=0; i<numhandles; i++) {
1039                 gpointer handle = handles[i];
1040                 guint32 idx = GPOINTER_TO_UINT(handle);
1041
1042 #ifdef DEBUG
1043                 g_message ("%s: attempting to lock %p", __func__, handle);
1044 #endif
1045
1046                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1047
1048                 thr_ret = _wapi_handle_trylock_handle (handle);
1049                 
1050                 if (thr_ret != 0) {
1051                         /* Bummer */
1052                         
1053 #ifdef DEBUG
1054                         g_message ("%s: attempt failed for %p: %s", __func__,
1055                                    handle, strerror (thr_ret));
1056 #endif
1057
1058                         thr_ret = _wapi_handle_unlock_shared_handles ();
1059                         g_assert (thr_ret == 0);
1060                         
1061                         while (i--) {
1062                                 handle = handles[i];
1063                                 idx = GPOINTER_TO_UINT(handle);
1064
1065                                 thr_ret = _wapi_handle_unlock_handle (handle);
1066                                 g_assert (thr_ret == 0);
1067                         }
1068
1069                         /* If iter ever reaches 100 the nanosleep will
1070                          * return EINVAL immediately, but we have a
1071                          * design flaw if that happens.
1072                          */
1073                         iter++;
1074                         if(iter==100) {
1075                                 g_warning ("%s: iteration overflow!",
1076                                            __func__);
1077                                 iter=1;
1078                         }
1079                         
1080 #ifdef DEBUG
1081                         g_message ("%s: Backing off for %d ms", __func__,
1082                                    iter*10);
1083 #endif
1084                         _wapi_handle_spin (10 * iter);
1085                         
1086                         goto again;
1087                 }
1088         }
1089         
1090 #ifdef DEBUG
1091         g_message ("%s: Locked all handles", __func__);
1092 #endif
1093
1094         count=0;
1095         *lowest=numhandles;
1096         
1097         for(i=0; i<numhandles; i++) {
1098                 gpointer handle = handles[i];
1099                 guint32 idx = GPOINTER_TO_UINT(handle);
1100                 
1101                 type = _WAPI_PRIVATE_HANDLES(idx).type;
1102
1103                 _wapi_handle_ref (handle);
1104                 
1105 #ifdef DEBUG
1106                 g_message ("%s: Checking handle %p", __func__, handle);
1107 #endif
1108
1109                 if(((_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN)==TRUE) &&
1110                     (_wapi_handle_ops_isowned (handle) == TRUE)) ||
1111                    (_WAPI_SHARED_HANDLE(type) &&
1112                     WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) ||
1113                    (!_WAPI_SHARED_HANDLE(type) &&
1114                     _WAPI_PRIVATE_HANDLES(idx).signalled == TRUE)) {
1115                         count++;
1116                         
1117 #ifdef DEBUG
1118                         g_message ("%s: Handle %p signalled", __func__,
1119                                    handle);
1120 #endif
1121                         if(*lowest>i) {
1122                                 *lowest=i;
1123                         }
1124                 }
1125         }
1126         
1127 #ifdef DEBUG
1128         g_message ("%s: %d event handles signalled", __func__, count);
1129 #endif
1130
1131         if ((waitall == TRUE && count == numhandles) ||
1132             (waitall == FALSE && count > 0)) {
1133                 ret=TRUE;
1134         } else {
1135                 ret=FALSE;
1136         }
1137         
1138 #ifdef DEBUG
1139         g_message ("%s: Returning %d", __func__, ret);
1140 #endif
1141
1142         *retcount=count;
1143         
1144         return(ret);
1145 }
1146
1147 void _wapi_handle_unlock_handles (guint32 numhandles, gpointer *handles)
1148 {
1149         guint32 i;
1150         int thr_ret;
1151         
1152         thr_ret = _wapi_handle_unlock_shared_handles ();
1153         g_assert (thr_ret == 0);
1154         
1155         for(i=0; i<numhandles; i++) {
1156                 gpointer handle = handles[i];
1157                 
1158 #ifdef DEBUG
1159                 g_message ("%s: unlocking handle %p", __func__, handle);
1160 #endif
1161
1162                 thr_ret = _wapi_handle_unlock_handle (handle);
1163                 g_assert (thr_ret == 0);
1164         }
1165 }
1166
1167 static int timedwait_signal_poll_cond (pthread_cond_t *cond, mono_mutex_t *mutex, struct timespec *timeout)
1168 {
1169         struct timespec fake_timeout;
1170         int ret;
1171         
1172         _wapi_calc_timeout (&fake_timeout, 100);
1173         
1174         if (timeout != NULL && ((fake_timeout.tv_sec > timeout->tv_sec) ||
1175            (fake_timeout.tv_sec == timeout->tv_sec &&
1176                 fake_timeout.tv_nsec > timeout->tv_nsec))) {
1177                 /* Real timeout is less than 100ms time */
1178                 ret=mono_cond_timedwait (cond, mutex, timeout);
1179         } else {
1180                 ret=mono_cond_timedwait (cond, mutex, &fake_timeout);
1181
1182                 /* Mask the fake timeout, this will cause
1183                  * another poll if the cond was not really signaled
1184                  */
1185                 if (ret==ETIMEDOUT) {
1186                         ret=0;
1187                 }
1188         }
1189         
1190         return(ret);
1191 }
1192
1193 int _wapi_handle_wait_signal (void)
1194 {
1195         return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, NULL);
1196 }
1197
1198 int _wapi_handle_timedwait_signal (struct timespec *timeout)
1199 {
1200         return timedwait_signal_poll_cond (&_wapi_global_signal_cond, &_wapi_global_signal_mutex, timeout);
1201 }
1202
1203 int _wapi_handle_wait_signal_handle (gpointer handle)
1204 {
1205 #ifdef DEBUG
1206         g_message ("%s: waiting for %p", __func__, handle);
1207 #endif
1208         
1209         return _wapi_handle_timedwait_signal_handle (handle, NULL);
1210 }
1211
1212 int _wapi_handle_timedwait_signal_handle (gpointer handle,
1213                                           struct timespec *timeout)
1214 {
1215 #ifdef DEBUG
1216         g_message ("%s: waiting for %p (type %s)", __func__, handle,
1217                    _wapi_handle_typename[_wapi_handle_type (handle)]);
1218 #endif
1219         
1220         if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) {
1221                 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1222                         return (0);
1223                 }
1224                 if (timeout != NULL) {
1225                         struct timespec fake_timeout;
1226                         _wapi_calc_timeout (&fake_timeout, 100);
1227                 
1228                         if ((fake_timeout.tv_sec > timeout->tv_sec) ||
1229                                 (fake_timeout.tv_sec == timeout->tv_sec &&
1230                                  fake_timeout.tv_nsec > timeout->tv_nsec)) {
1231                                 /* FIXME: Real timeout is less than
1232                                  * 100ms time, but is it really worth
1233                                  * calculating to the exact ms?
1234                                  */
1235                                 _wapi_handle_spin (100);
1236
1237                                 if (WAPI_SHARED_HANDLE_DATA(handle).signalled == TRUE) {
1238                                         return (0);
1239                                 } else {
1240                                         return (ETIMEDOUT);
1241                                 }
1242                         }
1243                 }
1244                 _wapi_handle_spin (100);
1245                 return (0);
1246                 
1247         } else {
1248                 guint32 idx = GPOINTER_TO_UINT(handle);
1249                 return timedwait_signal_poll_cond (&_WAPI_PRIVATE_HANDLES(idx).signal_cond, &_WAPI_PRIVATE_HANDLES(idx).signal_mutex, timeout);
1250         }
1251 }
1252
1253 gboolean _wapi_handle_get_or_set_share (dev_t device, ino_t inode,
1254                                         guint32 new_sharemode,
1255                                         guint32 new_access,
1256                                         guint32 *old_sharemode,
1257                                         guint32 *old_access,
1258                                         struct _WapiFileShare **share_info)
1259 {
1260         struct _WapiFileShare *file_share;
1261         guint32 now = (guint32)(time(NULL) & 0xFFFFFFFF);
1262         int thr_ret, i, first_unused = -1;
1263         gboolean exists = FALSE;
1264         
1265         /* Prevents entries from expiring under us as we search
1266          */
1267         thr_ret = _wapi_handle_lock_shared_handles ();
1268         g_assert (thr_ret == 0);
1269         
1270         /* Prevent new entries racing with us */
1271         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1272         g_assert (thr_ret == 0);
1273         
1274         /* If a linear scan gets too slow we'll have to fit a hash
1275          * table onto the shared mem backing store
1276          */
1277         *share_info = NULL;
1278         for (i = 0; i <= _wapi_fileshare_layout->hwm; i++) {
1279                 file_share = &_wapi_fileshare_layout->share_info[i];
1280
1281                 /* Make a note of an unused slot, in case we need to
1282                  * store share info
1283                  */
1284                 if (first_unused == -1 && file_share->handle_refs == 0) {
1285                         first_unused = i;
1286                         continue;
1287                 }
1288                 
1289                 if (file_share->handle_refs == 0) {
1290                         continue;
1291                 }
1292                 
1293                 if (file_share->device == device &&
1294                     file_share->inode == inode) {
1295                         *old_sharemode = file_share->sharemode;
1296                         *old_access = file_share->access;
1297                         *share_info = file_share;
1298                         
1299                         /* Increment the reference count while we
1300                          * still have sole access to the shared area.
1301                          * This makes the increment atomic wrt
1302                          * collections
1303                          */
1304                         InterlockedIncrement (&file_share->handle_refs);
1305                         
1306                         exists = TRUE;
1307                         break;
1308                 }
1309         }
1310         
1311         if (!exists) {
1312                 if (i == _WAPI_FILESHARE_SIZE && first_unused == -1) {
1313                         /* No more space */
1314                 } else {
1315                         if (first_unused == -1) {
1316                                 file_share = &_wapi_fileshare_layout->share_info[++i];
1317                                 _wapi_fileshare_layout->hwm = i;
1318                         } else {
1319                                 file_share = &_wapi_fileshare_layout->share_info[first_unused];
1320                         }
1321                         
1322                         file_share->device = device;
1323                         file_share->inode = inode;
1324                         file_share->opened_by_pid = getpid ();
1325                         file_share->sharemode = new_sharemode;
1326                         file_share->access = new_access;
1327                         file_share->handle_refs = 1;
1328                         *share_info = file_share;
1329                 }
1330         }
1331
1332         if (*share_info != NULL) {
1333                 InterlockedExchange (&(*share_info)->timestamp, now);
1334         }
1335         
1336         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1337
1338         _wapi_handle_unlock_shared_handles ();
1339
1340         return(exists);
1341 }
1342
1343 /* If we don't have the info in /proc, check if the process that
1344  * opened this share info is still there (it's not a perfect method,
1345  * due to pid reuse)
1346  */
1347 static void _wapi_handle_check_share_by_pid (struct _WapiFileShare *share_info)
1348 {
1349         if (kill (share_info->opened_by_pid, 0) == -1 &&
1350             (errno == ESRCH ||
1351              errno == EPERM)) {
1352                 /* It's gone completely (or there's a new process
1353                  * owned by someone else) so mark this share info as
1354                  * dead
1355                  */
1356 #ifdef DEBUG
1357                 g_message ("%s: Didn't find it, destroying entry", __func__);
1358 #endif
1359
1360                 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1361         }
1362 }
1363
1364 /* Scan /proc/<pids>/fd/ for open file descriptors to the file in
1365  * question.  If there are none, reset the share info.
1366  *
1367  * This implementation is Linux-specific; legacy systems will have to
1368  * implement their own ways of finding out if a particular file is
1369  * open by a process.
1370  */
1371 void _wapi_handle_check_share (struct _WapiFileShare *share_info, int fd)
1372 {
1373         gboolean found = FALSE, proc_fds = FALSE;
1374         pid_t self = getpid();
1375         int pid;
1376         int thr_ret, i;
1377         
1378         /* Prevents entries from expiring under us if we remove this
1379          * one
1380          */
1381         thr_ret = _wapi_handle_lock_shared_handles ();
1382         g_assert (thr_ret == 0);
1383         
1384         /* Prevent new entries racing with us */
1385         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1386         g_assert (thr_ret == 0);
1387         
1388         /* If there is no /proc, there's nothing more we can do here */
1389         if (access ("/proc", F_OK) == -1) {
1390                 _wapi_handle_check_share_by_pid (share_info);
1391                 goto done;
1392         }
1393
1394         /* If there's another handle that thinks it owns this fd, then even
1395          * if the fd has been closed behind our back consider it still owned.
1396          * See bugs 75764 and 75891
1397          */
1398         for (i = 0; i < _wapi_fd_reserve; i++) {
1399                 struct _WapiHandleUnshared *handle = &_WAPI_PRIVATE_HANDLES(i);
1400
1401                 if (i != fd &&
1402                     handle->type == WAPI_HANDLE_FILE) {
1403                         struct _WapiHandle_file *file_handle = &handle->u.file;
1404
1405                         if (file_handle->share_info == share_info) {
1406 #ifdef DEBUG
1407                                 g_message ("%s: handle 0x%x has this file open!",
1408                                            __func__, i);
1409 #endif
1410
1411                                 goto done;
1412                         }
1413                 }
1414         }
1415
1416         for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
1417                 struct _WapiHandleShared *shared;
1418                 struct _WapiHandle_process *process_handle;
1419
1420                 shared = &_wapi_shared_layout->handles[i];
1421                 
1422                 if (shared->type == WAPI_HANDLE_PROCESS) {
1423                         DIR *fd_dir;
1424                         struct dirent *fd_entry;
1425                         char subdir[_POSIX_PATH_MAX];
1426
1427                         process_handle = &shared->u.process;
1428                         pid = process_handle->id;
1429                 
1430                         /* Look in /proc/<pid>/fd/ but ignore
1431                          * /proc/<our pid>/fd/<fd>, as we have the
1432                          * file open too
1433                          */
1434                         g_snprintf (subdir, _POSIX_PATH_MAX, "/proc/%d/fd",
1435                                     pid);
1436                         
1437                         fd_dir = opendir (subdir);
1438                         if (fd_dir == NULL) {
1439                                 continue;
1440                         }
1441
1442 #ifdef DEBUG
1443                         g_message ("%s: Looking in %s", __func__, subdir);
1444 #endif
1445                         
1446                         proc_fds = TRUE;
1447                         
1448                         while ((fd_entry = readdir (fd_dir)) != NULL) {
1449                                 char path[_POSIX_PATH_MAX];
1450                                 struct stat link_stat;
1451                                 
1452                                 if (!strcmp (fd_entry->d_name, ".") ||
1453                                     !strcmp (fd_entry->d_name, "..") ||
1454                                     (pid == self &&
1455                                      fd == atoi (fd_entry->d_name))) {
1456                                         continue;
1457                                 }
1458
1459                                 g_snprintf (path, _POSIX_PATH_MAX,
1460                                             "/proc/%d/fd/%s", pid,
1461                                             fd_entry->d_name);
1462                                 
1463                                 stat (path, &link_stat);
1464                                 if (link_stat.st_dev == share_info->device &&
1465                                     link_stat.st_ino == share_info->inode) {
1466 #ifdef DEBUG
1467                                         g_message ("%s:  Found it at %s",
1468                                                    __func__, path);
1469 #endif
1470
1471                                         found = TRUE;
1472                                 }
1473                         }
1474                         
1475                         closedir (fd_dir);
1476                 }
1477         }
1478
1479         if (proc_fds == FALSE) {
1480                 _wapi_handle_check_share_by_pid (share_info);
1481         } else if (found == FALSE) {
1482                 /* Blank out this entry, as it is stale */
1483 #ifdef DEBUG
1484                 g_message ("%s: Didn't find it, destroying entry", __func__);
1485 #endif
1486
1487                 memset (share_info, '\0', sizeof(struct _WapiFileShare));
1488         }
1489
1490 done:
1491         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1492
1493         _wapi_handle_unlock_shared_handles ();
1494 }
1495
1496 void _wapi_handle_dump (void)
1497 {
1498         struct _WapiHandleUnshared *handle_data;
1499         guint32 i, k;
1500         int thr_ret;
1501         
1502         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
1503                               (void *)&scan_mutex);
1504         thr_ret = mono_mutex_lock (&scan_mutex);
1505         g_assert (thr_ret == 0);
1506         
1507         for(i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
1508                 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1509                         handle_data = &_wapi_private_handles [i][k];
1510
1511                         if (handle_data->type == WAPI_HANDLE_UNUSED) {
1512                                 continue;
1513                         }
1514                 
1515                         g_print ("%3x [%7s] %s %d ",
1516                                  i * _WAPI_HANDLE_INITIAL_COUNT + k,
1517                                  _wapi_handle_typename[handle_data->type],
1518                                  handle_data->signalled?"Sg":"Un",
1519                                  handle_data->ref);
1520                         handle_details[handle_data->type](&handle_data->u);
1521                         g_print ("\n");
1522                 }
1523         }
1524
1525         thr_ret = mono_mutex_unlock (&scan_mutex);
1526         g_assert (thr_ret == 0);
1527         pthread_cleanup_pop (0);
1528 }
1529
1530 static void _wapi_shared_details (gpointer handle_info)
1531 {
1532         struct _WapiHandle_shared_ref *shared = (struct _WapiHandle_shared_ref *)handle_info;
1533         
1534         g_print ("offset: 0x%x", shared->offset);
1535 }
1536
1537 void _wapi_handle_update_refs (void)
1538 {
1539         guint32 i, k;
1540         int thr_ret;
1541         guint32 now = (guint32)(time (NULL) & 0xFFFFFFFF);
1542         
1543         thr_ret = _wapi_handle_lock_shared_handles ();
1544         g_assert (thr_ret == 0);
1545
1546         /* Prevent file share entries racing with us */
1547         thr_ret = _wapi_shm_sem_lock (_WAPI_SHARED_SEM_FILESHARE);
1548         g_assert(thr_ret == 0);
1549
1550         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
1551                               (void *)&scan_mutex);
1552         thr_ret = mono_mutex_lock (&scan_mutex);
1553         
1554         for(i = SLOT_INDEX (0); _wapi_private_handles [i] != NULL; i++) {
1555                 for (k = SLOT_OFFSET (0); k < _WAPI_HANDLE_INITIAL_COUNT; k++) {
1556                         struct _WapiHandleUnshared *handle = &_wapi_private_handles [i][k];
1557
1558                         if (_WAPI_SHARED_HANDLE(handle->type)) {
1559                                 struct _WapiHandleShared *shared_data;
1560                                 
1561 #ifdef DEBUG
1562                                 g_message ("%s: (%d) handle 0x%x is SHARED (%s)", __func__,
1563                                            getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k, _wapi_handle_typename[handle->type]);
1564 #endif
1565
1566                                 shared_data = &_wapi_shared_layout->handles[handle->u.shared.offset];
1567
1568 #ifdef DEBUG
1569                                 g_message ("%s: (%d) Updating timestamp of handle 0x%x",
1570                                            __func__, getpid(),
1571                                            handle->u.shared.offset);
1572 #endif
1573
1574                                 InterlockedExchange (&shared_data->timestamp,
1575                                                      now);
1576                         } else if (handle->type == WAPI_HANDLE_FILE) {
1577                                 struct _WapiHandle_file *file_handle = &handle->u.file;
1578                                 
1579 #ifdef DEBUG
1580                                 g_message ("%s: (%d) handle 0x%x is FILE", __func__,
1581                                            getpid (), i * _WAPI_HANDLE_INITIAL_COUNT + k);
1582 #endif
1583                                 
1584                                 g_assert (file_handle->share_info != NULL);
1585
1586 #ifdef DEBUG
1587                                 g_message ("%s: (%d) Inc refs on fileshare 0x%x",
1588                                            __func__, getpid(),
1589                                            (file_handle->share_info - &_wapi_fileshare_layout->share_info[0]) / sizeof(struct _WapiFileShare));
1590 #endif
1591
1592                                 InterlockedExchange (&file_handle->share_info->timestamp, now);
1593                         }
1594                 }
1595         }
1596
1597         thr_ret = mono_mutex_unlock (&scan_mutex);
1598         g_assert (thr_ret == 0);
1599         pthread_cleanup_pop (0);
1600         
1601         thr_ret = _wapi_shm_sem_unlock (_WAPI_SHARED_SEM_FILESHARE);
1602
1603         _wapi_handle_unlock_shared_handles ();
1604 }