2 * Code to support inter-process sharing of handles.
4 * I thought of using an mmap()ed file for this. If linuxthreads
5 * supported PTHREAD_PROCESS_SHARED I would have done; however without
6 * that pthread support the only other inter-process IPC
7 * synchronisation option is a sysV semaphore, and if I'm going to use
8 * that I may as well take advantage of sysV shared memory too.
9 * Actually, semaphores seem to be buggy, or I was using them
10 * incorrectly :-). I've replaced the sysV semaphore with a shared
11 * integer controlled with Interlocked functions.
13 * mmap() files have the advantage of avoiding namespace collisions,
14 * but have the disadvantage of needing cleaning up, and also msync().
15 * sysV shared memory has a really stupid way of getting random key
16 * IDs, which can lead to collisions.
18 * I deliberately don't ever delete the shared memory: I'd like to
19 * have been able to set the shared memory segment to destroy itself
20 * on last close, but it doesn't support that. (Setting IPC_RMID on a
21 * segment causes subsequent shmat() with the same key to get a new
22 * segment :-( ). The function to delete the shared memory segment is
23 * only called from a debugging tool (mono/handles/shmdel).
25 * w32 processes do not have the POSIX parent-child relationship, so a
26 * process handle is available to any other process to find out exit
27 * status. Handles are destroyed when the last reference to them is
28 * closed. New handles can be created for long lasting items such as
29 * processes or threads, and also for named synchronisation objects so
30 * long as these haven't been deleted by having the last referencing
38 #include <sys/types.h>
44 #include <mono/io-layer/wapi.h>
45 #include <mono/io-layer/wapi-private.h>
46 #include <mono/io-layer/shared.h>
50 gpointer _wapi_shm_attach (gboolean daemon)
55 gboolean fork_daemon=FALSE;
56 struct _WapiHandleShared_list *data;
59 * This is an attempt to get a unique key id. The first arg
60 * to ftok is a path, so when the config file support is done
63 key=ftok (g_get_home_dir (), _WAPI_HANDLE_VERSION);
66 shm_id=shmget (key, sizeof(struct _WapiHandleShared_list)+
67 _WAPI_SHM_SCRATCH_SIZE, IPC_CREAT | IPC_EXCL | 0600);
68 if(shm_id==-1 && errno==EEXIST) {
69 /* Cool, we dont have to fork the handle daemon, but
70 * we still need to try and get the shm_id.
72 shm_id=shmget (key, 0, 0600);
74 /* it's possible that the shared memory segment was
75 * deleted in between seeing if it exists, and
76 * attaching it. If we got an error here, just try
82 } else if (shm_id!=-1) {
83 /* We created the shared memory segment, so we need to
84 * fork the handle daemon too
88 /* sysv shared mem is set to all zero when allocated,
89 * so we don't need to do any more initialisation here
92 /* Some error other than EEXIST */
93 g_message (G_GNUC_PRETTY_FUNCTION ": shmget error: %s",
98 /* From now on, we need to delete the shm segment before
99 * exiting on error if we created it (ie, if
102 shm_seg=shmat (shm_id, NULL, 0);
103 if(shm_seg==(gpointer)-1) {
104 g_message (G_GNUC_PRETTY_FUNCTION ": shmat error: %s",
106 if(fork_daemon==TRUE) {
107 _wapi_shm_destroy ();
113 /* No more to do in the daemon */
119 if(fork_daemon==TRUE) {
124 g_message (G_GNUC_PRETTY_FUNCTION ": fork error: %s",
126 _wapi_shm_destroy ();
131 execl (MONO_BINDIR "/mono-handle-d", "mono-handle-d",
133 g_message (G_GNUC_PRETTY_FUNCTION ": exec error: %s",
135 data->daemon_running=2;
138 /* parent carries on */
141 /* Set up the handle daemon connection */
143 while(data->daemon_running==0) {
144 /* wait for the daemon to sort itself out. To be
145 * completely safe, we should have a timeout before
148 struct timespec sleepytime;
151 sleepytime.tv_nsec=10000000; /* 10ms */
153 nanosleep (&sleepytime, NULL);
155 if(data->daemon_running==2) {
156 /* Oh dear, the daemon had an error starting up */
157 if(fork_daemon==TRUE) {
158 _wapi_shm_destroy ();
160 g_error ("Handle daemon failed to start");
163 /* From now on, it's up to the daemon to delete the shared
170 void _wapi_shm_destroy (void)
172 #ifndef DISABLE_SHARED_HANDLES
177 * This is an attempt to get a unique key id. The
178 * first arg to ftok is a path, so when the config
179 * file support is done we should use that.
181 key=ftok (g_get_home_dir (), _WAPI_HANDLE_VERSION);
183 shm_id=shmget (key, 0, 0600);
184 if(shm_id==-1 && errno==ENOENT) {
186 } else if (shm_id==-1) {
187 g_message (G_GNUC_PRETTY_FUNCTION ": shmget error: %s",
191 if(shmctl (shm_id, IPC_RMID, NULL)==-1) {
192 g_message (G_GNUC_PRETTY_FUNCTION ": shmctl error: %s",
196 #endif /* DISABLE_SHARED_HANDLES */