Fix sleeps in the keepalive thread. Stop timestamp updates racing with
[mono.git] / mono / io-layer / collection.c
1 /*
2  * collection.c:  Garbage collection for handles
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2004 Novell, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <pthread.h>
13 #include <signal.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16
17 #include <mono/io-layer/wapi.h>
18 #include <mono/io-layer/collection.h>
19 #include <mono/io-layer/handles-private.h>
20
21 #define DEBUG
22
23 static pthread_t collection_thread_id;
24
25 static gpointer collection_thread (gpointer args) G_GNUC_NORETURN;
26 static gpointer collection_thread (gpointer unused G_GNUC_UNUSED)
27 {
28         struct timespec sleepytime;
29
30         sleepytime.tv_sec = 10;
31         sleepytime.tv_nsec = 0;
32
33         while (1) {
34                 //_wapi_handle_dump ();
35                 _wapi_handle_update_refs ();
36                 nanosleep (&sleepytime, NULL);
37         }
38 }
39
40 void _wapi_collection_init (void)
41 {
42         pthread_attr_t attr;
43         int ret;
44         
45         ret = pthread_attr_init (&attr);
46         g_assert (ret == 0);
47         
48 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
49         ret = pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN);
50         g_assert (ret == 0);
51 #endif
52
53         ret = pthread_create (&collection_thread_id, &attr, collection_thread,
54                               NULL);
55         if (ret != 0) {
56                 g_error ("%s: Couldn't create handle collection thread: %s",
57                          __func__, g_strerror (ret));
58         }
59 }
60
61 void _wapi_handle_collect (void)
62 {
63         guint32 count = _wapi_shared_layout->collection_count;
64         int i;
65         
66 #ifdef DEBUG
67         g_message ("%s: (%d) Starting a collection", __func__, getpid ());
68 #endif
69
70         /* Become the collection master */
71         _WAPI_HANDLE_COLLECTION_UNSAFE;
72         
73 #ifdef DEBUG
74         g_message ("%s: (%d) Master set", __func__, getpid ());
75 #endif
76         
77         /* If count has changed, someone else jumped in as master */
78         if (count == _wapi_shared_layout->collection_count) {
79                 for (i = 0; i < _WAPI_HANDLE_INITIAL_COUNT; i++) {
80                         struct _WapiHandleShared *shared;
81                         struct _WapiHandleSharedMetadata *meta;
82                         guint32 too_old = (guint32)(time(NULL) & 0xFFFFFFFF) - 300; /* 5 minutes without update */
83                         
84                         meta = &_wapi_shared_layout->metadata[i];
85                         if (meta->timestamp < too_old && meta->offset != 0) {
86 #ifdef DEBUG
87                                 g_message ("%s: (%d) Deleting metadata slot 0x%x handle 0x%x", __func__, getpid (), i, meta->offset);
88 #endif
89                                 memset (&_wapi_shared_layout->handles[meta->offset], '\0', sizeof(struct _WapiHandleShared));
90                                 memset (&_wapi_shared_layout->metadata[i], '\0', sizeof(struct _WapiHandleSharedMetadata));
91                         }
92
93                         /* Need to blank any handles data that is no
94                          * longer pointed to by a metadata entry too
95                          */
96                         shared = &_wapi_shared_layout->handles[i];
97                         if (shared->stale == TRUE) {
98 #ifdef DEBUG
99                                 g_message ("%s: (%d) Deleting stale handle 0x%x", __func__, getpid (), i);
100 #endif
101                                 memset (&_wapi_shared_layout->handles[i], '\0',
102                                         sizeof(struct _WapiHandleShared));
103                         }
104                 }
105
106                 for (i = 0; i < _wapi_fileshare_layout->hwm; i++) {
107                         struct _WapiFileShare *file_share = &_wapi_fileshare_layout->share_info[i];
108                         guint32 too_old = (guint32)(time(NULL) & 0xFFFFFFFF) - 300; /* 5 minutes without update */
109                         
110                         if (file_share->timestamp < too_old) {
111                                 memset (file_share, '\0',
112                                         sizeof(struct _WapiFileShare));
113                         }
114                 }
115
116                 InterlockedIncrement (&_wapi_shared_layout->collection_count);
117         }
118         
119         _WAPI_HANDLE_COLLECTION_SAFE;
120
121 #ifdef DEBUG
122         g_message ("%s: (%d) Collection done", __func__, getpid ());
123 #endif
124 }