c9d4e62576589056ff4fa879f901631da9a1e1f1
[mono.git] / mono / io-layer / shared.c
1 /*
2  * Code to support inter-process sharing of handles.
3  *
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.
12
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.
17  *
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).
24  *
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
31  * handle closed.
32  */
33
34 #include <config.h>
35 #include <glib.h>
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/ipc.h>
40 #include <sys/shm.h>
41 #include <errno.h>
42
43 #include <mono/io-layer/wapi.h>
44 #include <mono/io-layer/wapi-private.h>
45 #include <mono/io-layer/shared.h>
46
47 #undef DEBUG
48
49 static gboolean shared;
50
51 gpointer _wapi_shm_attach (guint32 *scratch_size)
52 {
53         gpointer shm_seg;
54
55         *scratch_size=getpagesize ()*100;
56         
57 #ifndef DISABLE_SHARED_HANDLES
58         if(getenv ("MONO_DISABLE_SHM"))
59 #endif
60         {
61 #ifdef DEBUG
62                 g_message (G_GNUC_PRETTY_FUNCTION
63                            ": Using process-private handles");
64 #endif
65
66                 shared=FALSE;
67                 shm_seg=g_malloc0 (sizeof(struct _WapiHandleShared_list)+
68                                    *scratch_size);
69 #ifndef DISABLE_SHARED_HANDLES
70         } else {
71                 int shm_id;
72                 key_t key;
73         
74                 shared=TRUE;
75                 
76                 /*
77                  * This is an attempt to get a unique key id.  The
78                  * first arg to ftok is a path, so when the config
79                  * file support is done we should use that.
80                  */
81                 key=ftok (g_get_home_dir (), _WAPI_HANDLE_VERSION);
82         
83                 /* sysv shared mem is set to all zero when allocated,
84                  * so we don't need to do any more initialisation here
85                  */
86                 shm_id=shmget (key, sizeof(struct _WapiHandleShared_list)+
87                                *scratch_size, IPC_CREAT | 0600);
88                 if(shm_id==-1) {
89                         perror ("shmget");
90                         exit (-1);
91                 }
92         
93                 shm_seg=shmat (shm_id, NULL, 0);
94                 if(shm_seg==(gpointer)-1) {
95                         perror ("shmat");
96                         exit (-1);
97                 }
98 #endif /* DISABLE_SHARED_HANDLES */
99         }
100
101         return(shm_seg);
102 }
103
104 void _wapi_shm_destroy (void)
105 {
106 #ifndef DISABLE_SHARED_HANDLES
107         int shm_id;
108         key_t key;
109                 
110         /*
111          * This is an attempt to get a unique key id.  The
112          * first arg to ftok is a path, so when the config
113          * file support is done we should use that.
114          */
115         key=ftok (g_get_home_dir (), _WAPI_HANDLE_VERSION);
116         
117         /* sysv shared mem is set to all zero when allocated,
118          * so we don't need to do any more initialisation here
119          */
120         shm_id=shmget (key, 0, 0600);
121         if(shm_id==-1 && errno==ENOENT) {
122                 return;
123         } else if (shm_id==-1) {
124                 perror ("shmget");
125                 exit (-1);
126         }
127         if(shmctl (shm_id, IPC_RMID, NULL)==-1) {
128                 perror ("shmctl");
129                 exit (-1);
130         }
131 #endif /* DISABLE_SHARED_HANDLES */
132 }