2 * shared.c: Shared memory handling, and daemon launching
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
17 #include <sys/types.h>
24 #include <mono/io-layer/wapi.h>
25 #include <mono/io-layer/wapi-private.h>
26 #include <mono/io-layer/shared.h>
27 #include <mono/io-layer/handles-private.h>
31 static guchar *_wapi_shm_file (_wapi_shm_t type)
33 static guchar file[_POSIX_PATH_MAX];
34 guchar *name = NULL, *filename, *dir, *wapi_dir;
35 gchar machine_name[256];
37 if (gethostname(machine_name, sizeof(machine_name)) != 0)
38 machine_name[0] = '\0';
42 name = g_strdup_printf ("shared_data-%s-%d-%d",
43 machine_name, _WAPI_HANDLE_VERSION, 0);
46 case WAPI_SHM_FILESHARE:
47 name = g_strdup_printf ("shared_fileshare-%s-%d-%d",
48 machine_name, _WAPI_HANDLE_VERSION, 0);
52 /* I don't know how nfs affects mmap. If mmap() of files on
53 * nfs mounts breaks, then there should be an option to set
56 wapi_dir = getenv ("MONO_SHARED_DIR");
57 if (wapi_dir == NULL) {
58 filename = g_build_filename (g_get_home_dir (), ".wapi", name,
61 filename = g_build_filename (wapi_dir, ".wapi", name, NULL);
65 g_snprintf (file, _POSIX_PATH_MAX, "%s", filename);
68 /* No need to check if the dir already exists or check
69 * mkdir() errors, because on any error the open() call will
72 dir = g_path_get_dirname (file);
79 static int _wapi_shm_file_open (const guchar *filename, guint32 wanted_size)
84 gboolean created = FALSE;
87 /* No O_CREAT yet, because we need to initialise the file if
88 * we have to create it.
90 fd = open (filename, O_RDWR, 0600);
91 if (fd == -1 && errno == ENOENT) {
92 /* OK, its up to us to create it. O_EXCL to avoid a
93 * race condition where two processes can
94 * simultaneously try and create the file
96 fd = open (filename, O_CREAT|O_EXCL|O_RDWR, 0600);
97 if (fd == -1 && errno == EEXIST) {
98 /* It's possible that the file was created in
99 * between finding it didn't exist, and trying
100 * to create it. Just try opening it again
103 } else if (fd == -1) {
104 g_critical ("%s: shared file [%s] open error: %s",
105 __func__, filename, g_strerror (errno));
108 /* We created the file, so we need to expand
111 * (wanted_size-1, because we're about to
112 * write the other byte to actually expand the
115 if (lseek (fd, wanted_size-1, SEEK_SET) == -1) {
116 g_critical ("%s: shared file [%s] lseek error: %s", __func__, filename, g_strerror (errno));
123 ret = write (fd, "", 1);
124 } while (ret == -1 && errno == EINTR);
127 g_critical ("%s: shared file [%s] write error: %s", __func__, filename, g_strerror (errno));
135 /* The contents of the file is set to all
136 * zero, because it is opened up with lseek,
137 * so we don't need to do any more
138 * initialisation here
141 } else if (fd == -1) {
142 g_critical ("%s: shared file [%s] open error: %s", __func__,
143 filename, g_strerror (errno));
147 /* Use stat to find the file size (instead of hard coding it)
148 * because we can expand the file later if needed (for more
149 * handles or scratch space.)
151 if (fstat (fd, &statbuf) == -1) {
152 g_critical ("%s: fstat error: %s", __func__,
154 if (created == TRUE) {
161 if (statbuf.st_size < wanted_size) {
163 if (created == TRUE) {
164 #ifdef HAVE_LARGE_FILE_SUPPORT
165 /* Keep gcc quiet... */
166 g_critical ("%s: shared file [%s] is not big enough! (found %lld, need %d bytes)", __func__, filename, statbuf.st_size, wanted_size);
168 g_critical ("%s: shared file [%s] is not big enough! (found %ld, need %d bytes)", __func__, filename, statbuf.st_size, wanted_size);
173 /* We didn't create it, so just try opening it again */
183 * @success: Was it a success
185 * Attach to the shared memory file or create it if it did not exist.
186 * Returns the memory area the file was mmapped to.
188 gpointer _wapi_shm_attach (_wapi_shm_t type)
193 guchar *filename=_wapi_shm_file (type);
198 size = sizeof(struct _WapiHandleSharedLayout);
201 case WAPI_SHM_FILESHARE:
202 size = sizeof(struct _WapiFileShareLayout);
206 fd = _wapi_shm_file_open (filename, size);
208 g_critical ("%s: shared file [%s] open error", __func__,
213 if (fstat (fd, &statbuf)==-1) {
214 g_critical ("%s: fstat error: %s", __func__,
220 shm_seg = mmap (NULL, statbuf.st_size, PROT_READ|PROT_WRITE,
222 if (shm_seg == MAP_FAILED) {
223 g_critical ("%s: mmap error: %s", __func__,
233 void _wapi_shm_semaphores_init ()
235 key_t key = ftok (_wapi_shm_file (WAPI_SHM_DATA), 'M');
238 /* Yet more barmy API - this union is a well-defined parameter
239 * in a syscall, yet I still have to define it here as it
240 * doesn't appear in a header
244 struct semid_ds *buf;
247 ushort def_vals[_WAPI_SHARED_SEM_COUNT];
251 for (i = 0; i < _WAPI_SHARED_SEM_COUNT; i++) {
254 defs.array = def_vals;
258 oldkey = _wapi_shared_layout->sem_key;
262 g_message ("%s: Creating with new key (0x%x)", __func__, key);
265 /* The while loop attempts to make some sense of the
266 * bonkers 'think of a random number' method of
267 * picking a key without collision with other
270 while ((_wapi_sem_id = semget (key, _WAPI_SHARED_SEM_COUNT,
271 IPC_CREAT | IPC_EXCL | 0600)) == -1) {
272 if (errno != EEXIST) {
274 g_warning ("%s: semget error: %s key 0x%x - trying again", __func__,
275 g_strerror (errno), key);
280 g_message ("%s: Got (%s), trying with new key (0x%x)",
281 __func__, g_strerror (errno), key);
284 /* Got a semaphore array, so initialise it and install
285 * the key into the shared memory
288 if (semctl (_wapi_sem_id, 0, SETALL, defs) == -1) {
290 g_warning ("%s: semctl init error: %s - trying again", __func__, g_strerror (errno));
292 /* Something went horribly wrong, so try
293 * getting a new set from scratch
295 semctl (_wapi_sem_id, 0, IPC_RMID);
299 if (InterlockedCompareExchange (&_wapi_shared_layout->sem_key,
301 /* Someone else created one and installed the
302 * key while we were working, so delete the
303 * array we created and fall through to the
304 * 'key already known' case.
306 semctl (_wapi_sem_id, 0, IPC_RMID);
307 oldkey = _wapi_shared_layout->sem_key;
309 /* We've installed this semaphore set's key into
317 g_message ("%s: Trying with old key 0x%x", __func__, oldkey);
320 _wapi_sem_id = semget (oldkey, _WAPI_SHARED_SEM_COUNT, 0600);
321 if (_wapi_sem_id == -1) {
323 g_warning ("%s: semget error opening old key 0x%x (%s) - trying again",
324 __func__, oldkey,g_strerror (errno));
326 /* Someone must have deleted the semaphore set, so
327 * blow away the bad key and try again
329 InterlockedCompareExchange (&_wapi_shared_layout->sem_key, 0,
336 int _wapi_shm_sem_lock (int sem)
342 g_message ("%s: locking sem %d", __func__, sem);
347 ops.sem_flg = SEM_UNDO;
350 ret = semop (_wapi_sem_id, &ops, 1);
351 } while (ret == -1 && errno == EINTR);
354 /* Turn this into a pthreads-style return value */
359 g_message ("%s: returning %d (%s)", __func__, ret, g_strerror (ret));
365 int _wapi_shm_sem_trylock (int sem)
371 g_message ("%s: trying to lock sem %d", __func__, sem);
376 ops.sem_flg = IPC_NOWAIT | SEM_UNDO;
379 ret = semop (_wapi_sem_id, &ops, 1);
380 } while (ret == -1 && errno == EINTR);
383 /* Turn this into a pthreads-style return value */
388 /* But pthreads uses this code instead */
393 g_message ("%s: returning %d (%s)", __func__, ret, g_strerror (ret));
399 int _wapi_shm_sem_unlock (int sem)
405 g_message ("%s: unlocking sem %d", __func__, sem);
410 ops.sem_flg = SEM_UNDO;
413 ret = semop (_wapi_sem_id, &ops, 1);
414 } while (ret == -1 && errno == EINTR);
417 /* Turn this into a pthreads-style return value */
422 g_message ("%s: returning %d (%s)", __func__, ret, g_strerror (ret));