2002-10-02 Dick Porter <dick@ximian.com>
authorDick Porter <dick@acm.org>
Wed, 2 Oct 2002 17:00:17 +0000 (17:00 -0000)
committerDick Porter <dick@acm.org>
Wed, 2 Oct 2002 17:00:17 +0000 (17:00 -0000)
* shared.c: Use mmap() instead of sysv shm for the shared data.

* wapi-private.h (_WAPI_HANDLE_VERSION): Reset back to 0, for the
new system

* daemon-private.h:
* daemon.c: mmap()ed regions survive fork, so just pass the
pointer to _wapi_daemon_main instead of mapping it again.

svn path=/trunk/mono/; revision=7946

mono/handles/hps.c
mono/handles/scratch.c
mono/io-layer/ChangeLog
mono/io-layer/daemon-private.h
mono/io-layer/daemon.c
mono/io-layer/handles.c
mono/io-layer/shared.c
mono/io-layer/shared.h
mono/io-layer/wapi-private.h

index 5bd7b3eb132e804274cdaf7f8d078ff714653cb9..70ebaded67e6a6e8bc6257c3ad8361794de7c9ab 100644 (file)
@@ -58,11 +58,10 @@ int main (int argc, char **argv)
 {
        guint32 idx;
        gboolean success;
-       int shm_id;
        
-       _wapi_shared_data=_wapi_shm_attach (FALSE, &success, &shm_id);
+       _wapi_shared_data=_wapi_shm_attach (&success);
        if(success==FALSE) {
-               g_error ("Failed to attach shared memory! (tried shared memory ID 0x%x)", shm_id);
+               g_error ("Failed to attach shared memory!");
                exit (-1);
        }
        
index 3ad845b0ace911b9e9b62b87cc545d23ba49f2a9..b1b62e2174095db1efdf398bc502eca3d249000a 100644 (file)
@@ -36,11 +36,10 @@ int main (int argc, char **argv)
        guint32 idx=0;
        struct _WapiScratchHeader *hdr;
        gboolean success;
-       int shm_id;
        
-       _wapi_shared_data=_wapi_shm_attach (FALSE, &success, &shm_id);
+       _wapi_shared_data=_wapi_shm_attach (&success);
        if(success==FALSE) {
-               g_error ("Failed to attach shared memory! (tried shared memory ID 0x%x)", shm_id);
+               g_error ("Failed to attach shared memory!");
                exit (-1);
        }
 
index 062d025e6bdbf62f81670a62a5a058c8af8aeb57..68f61f43e832db4a76a6672bb951c8ed98ca479e 100644 (file)
@@ -1,3 +1,14 @@
+2002-10-02  Dick Porter  <dick@ximian.com>
+
+       * shared.c: Use mmap() instead of sysv shm for the shared data.
+
+       * wapi-private.h (_WAPI_HANDLE_VERSION): Reset back to 0, for the
+       new system
+
+       * daemon-private.h: 
+       * daemon.c: mmap()ed regions survive fork, so just pass the
+       pointer to _wapi_daemon_main instead of mapping it again.
+
 2002-10-01  Dick Porter  <dick@ximian.com>
 
        * timed-thread.c: Kludge for CREATE_SUSPENDED thread creation.
index f370d3d95baab49fb9a058f520314c944920cc47..34517bad744aaef8e0c62c55ed54fa3ec64acde5 100644 (file)
@@ -16,6 +16,6 @@ typedef enum {
        DAEMON_DIED_AT_STARTUP = 2,
 } _wapi_daemon_status;
 
-extern void _wapi_daemon_main (void);
+extern void _wapi_daemon_main (gpointer shm);
 
 #endif /* _WAPI_DAEMON_PRIVATE_H_ */
index 4a5a01f73723dc9f924c2c59bc7bbb86d94d242e..a05b1a7ac76800466219307f7ca151f93199e88d 100644 (file)
@@ -130,8 +130,6 @@ static void sigchld_handler (int unused)
 static void startup (void)
 {
        struct sigaction sa;
-       gboolean success;
-       int shm_id;
        
        sa.sa_handler=signal_handler;
        sigemptyset (&sa.sa_mask);
@@ -148,12 +146,6 @@ static void startup (void)
        sa.sa_flags=SA_NOCLDSTOP;
        sigaction (SIGCHLD, &sa, NULL);
        
-       _wapi_shared_data=_wapi_shm_attach (TRUE, &success, &shm_id);
-       if(success==FALSE) {
-               g_error ("Failed to attach shared memory! (tried shared memory ID 0x%x)", shm_id);
-               exit (-1);
-       }
-
 #ifdef NEED_LINK_UNLINK
        /* Here's a more portable method... */
        snprintf (_wapi_shared_data->daemon, MONO_SIZEOF_SUNPATH-1,
@@ -1002,7 +994,7 @@ static gboolean fd_activity (GIOChannel *channel, GIOCondition condition,
  * Open socket, create shared mem segment and begin listening for
  * clients.
  */
-void _wapi_daemon_main(void)
+void _wapi_daemon_main(gpointer shm)
 {
        struct sockaddr_un main_socket_address;
        int ret;
@@ -1011,6 +1003,7 @@ void _wapi_daemon_main(void)
        g_message ("Starting up...");
 #endif
 
+       _wapi_shared_data=shm;
        startup ();
        
        main_sock=socket(PF_UNIX, SOCK_STREAM, 0);
index 7e1c6848400068b374ef68e5925e87bde7daef86..fb82829fb23c123739b624bbdec225628f556c2c 100644 (file)
@@ -81,7 +81,6 @@ attach_again:
                shared=FALSE;
 #ifndef DISABLE_SHARED_HANDLES
        } else {
-               int shm_id;
                gboolean success;
                
                /* Ensure that shared==FALSE while _wapi_shm_attach()
@@ -89,13 +88,11 @@ attach_again:
                 */
                shared=FALSE;
                
-               _wapi_shared_data=_wapi_shm_attach (FALSE, &success, &shm_id);
+               _wapi_shared_data=_wapi_shm_attach (&success);
                shared=success;
                if(shared==FALSE) {
                        g_warning ("Failed to attach shared memory! "
-                                  "(tried shared memory ID 0x%x). "
-                                  "Falling back to non-shared handles",
-                                  shm_id);
+                                  "Falling back to non-shared handles");
                }
 #endif /* DISABLE_SHARED_HANDLES */
        }
index 2e52aac997e92083e1cd5159dacfe97b1850ef95..2406b03d1db8a531840a25136296b0ecaefe9b6f 100644 (file)
  * that I may as well take advantage of sysV shared memory too.
  * Actually, semaphores seem to be buggy, or I was using them
  * incorrectly :-).  I've replaced the sysV semaphore with a shared
- * integer controlled with Interlocked functions.
-
+ * integer controlled with Interlocked functions.  And I've since
+ * replaced that with a separate process to serialise access to the
+ * shared memory, to avoid the possibility of DOS by leaving the
+ * shared memory locked, and also to allow the shared memory to be
+ * cleaned up.
+ *
  * mmap() files have the advantage of avoiding namespace collisions,
  * but have the disadvantage of needing cleaning up, and also msync().
  * sysV shared memory has a really stupid way of getting random key
  * IDs, which can lead to collisions.
  *
- * I deliberately don't ever delete the shared memory: I'd like to
- * have been able to set the shared memory segment to destroy itself
- * on last close, but it doesn't support that. (Setting IPC_RMID on a
- * segment causes subsequent shmat() with the same key to get a new
- * segment :-( ).  The function to delete the shared memory segment is
- * only called from a debugging tool (mono/handles/shmdel).
+ * Having tried sysv shm, I tested mmap() and found that MAP_SHARED
+ * makes msync() irrelevent, and both types need cleaning up.  Seeing
+ * as mmap() doesn't suffer from the bonkers method of allocating
+ * segments, it seems to be the best method.
  *
- * w32 processes do not have the POSIX parent-child relationship, so a
- * process handle is available to any other process to find out exit
- * status.  Handles are destroyed when the last reference to them is
- * closed.  New handles can be created for long lasting items such as
- * processes or threads, and also for named synchronisation objects so
- * long as these haven't been deleted by having the last referencing
- * handle closed.
+ * This shared memory is needed because w32 processes do not have the
+ * POSIX parent-child relationship, so a process handle is available
+ * to any other process to find out exit status.  Handles are
+ * destroyed when the last reference to them is closed.  New handles
+ * can be created for long lasting items such as processes or threads,
+ * and also for named synchronisation objects so long as these haven't
+ * been deleted by having the last referencing handle closed.
  */
 
+
 #include <config.h>
 #include <glib.h>
 #include <stdio.h>
+#include <fcntl.h>
 #include <unistd.h>
+#include <sys/mman.h>
 #include <sys/types.h>
-#include <sys/ipc.h>
-#include <sys/shm.h>
+#include <sys/stat.h>
 #include <errno.h>
 #include <string.h>
-#include <fcntl.h>
 
 #include <mono/io-layer/wapi.h>
 #include <mono/io-layer/wapi-private.h>
 
 #undef DEBUG
 
+static guchar *shared_file (void)
+{
+       static guchar *file=NULL;
+       guchar *name, *dir;
+       
+       if(file!=NULL) {
+               return(file);
+       }
+       
+       /* Change the filename whenever the format of the contents
+        * changes
+        */
+       name=g_strdup_printf ("shared_data-%d", _WAPI_HANDLE_VERSION);
+
+       /* I don't know how nfs affects mmap.  If mmap() of files on
+        * nfs mounts breaks, then there should be an option to set
+        * the directory.
+        */
+       file=g_build_filename (g_get_home_dir (), ".wapi", name, NULL);
+       g_free (name);
+
+       /* No need to check if the dir already exists or check
+        * mkdir() errors, because on any error the open() call will
+        * report the problem.
+        */
+       dir=g_path_get_dirname (file);
+       mkdir (dir, 0755);
+       g_free (dir);
+               
+       return(file);
+}
+
 /*
  * _wapi_shm_attach:
- * @daemon: Is it the daemon trying to attach to the segment
  * @success: Was it a success
- * @shm_id: The ID of the segment created/attached to
  *
- * Attach to the shared memory segment or create it if it did not
+ * Attach to the shared memory file or create it if it did not
  * exist. If it was created and daemon was FALSE a new daemon is
- * forked into existence. Returns the memory area the segment was
- * attached to.
+ * forked into existence. Returns the memory area the file was mmapped
+ * to.
  */
-gpointer _wapi_shm_attach (gboolean daemon, gboolean *success, int *shm_id)
+gpointer _wapi_shm_attach (gboolean *success)
 {
        gpointer shm_seg;
-       key_t key;
+       int fd;
        gboolean fork_daemon=FALSE;
+       struct stat statbuf;
        struct _WapiHandleShared_list *data;
        int tries;
-       
-       /*
-        * This is an attempt to get a unique key id.  The first arg
-        * to ftok is a path, so when the config file support is done
-        * we should use that.
-        */
-       key=ftok (g_get_home_dir (), _WAPI_HANDLE_VERSION);
+       int wanted_size=sizeof(struct _WapiHandleShared_list) +
+               _WAPI_SHM_SCRATCH_SIZE;
        
 try_again:
-       *shm_id=shmget (key, sizeof(struct _WapiHandleShared_list)+
-                       _WAPI_SHM_SCRATCH_SIZE, IPC_CREAT | IPC_EXCL | 0600);
-       if(*shm_id==-1 && errno==EEXIST) {
-               /* Cool, we dont have to fork the handle daemon, but
-                * we still need to try and get the shm_id.
-                */
-               *shm_id=shmget (key, 0, 0600);
-                       
-               /* it's possible that the shared memory segment was
-                * deleted in between seeing if it exists, and
-                * attaching it.  If we got an error here, just try
-                * attaching it again.
+       /* No O_CREAT yet, because we need to initialise the file if
+        * we have to create it.
+        */
+       fd=open (shared_file (), O_RDWR, 0600);
+       if(fd==-1 && errno==ENOENT) {
+               /* OK, its up to us to create it.  O_EXCL to avoid a
+                * race condition where two processes can
+                * simultaneously try and create the file
                 */
-               if(*shm_id==-1) {
+               fd=open (shared_file (), O_CREAT|O_EXCL|O_RDWR, 0600);
+               if(fd==-1 && errno==EEXIST) {
+                       /* It's possible that the file was created in
+                        * between finding it didn't exist, and trying
+                        * to create it.  Just try opening it again
+                        */
                        goto try_again;
-               }
-       } else if (*shm_id!=-1) {
-               /* We created the shared memory segment, so we need to
-                * fork the handle daemon too
-                */
-               fork_daemon=TRUE;
+               } else if (fd==-1) {
+                       g_critical (G_GNUC_PRETTY_FUNCTION
+                                   ": shared file [%s] open error: %s",
+                                   shared_file (), g_strerror (errno));
+                       exit (-1);
+               } else {
+                       /* We created the file, so we need to expand
+                        * the file and fork the handle daemon too
+                        */
+                       if(lseek (fd, wanted_size, SEEK_SET)==-1) {
+                               g_critical (G_GNUC_PRETTY_FUNCTION ": shared file [%s] lseek error: %s", shared_file (), g_strerror (errno));
+                               _wapi_shm_destroy ();
+                               exit (-1);
+                       }
+                       
+                       if(write (fd, "", 1)==-1) {
+                               g_critical (G_GNUC_PRETTY_FUNCTION ": shared file [%s] write error: %s", shared_file (), g_strerror (errno));
+                               _wapi_shm_destroy ();
+                               exit (-1);
+                       }
+                       
+                       fork_daemon=TRUE;
 
-               /* sysv shared mem is set to all zero when allocated,
-                * so we don't need to do any more initialisation here
-                */
-       } else {
-               /* Some error other than EEXIST */
-               g_critical (G_GNUC_PRETTY_FUNCTION ": shmget error: %s",
-                           strerror (errno));
+                       /* The contents of the file is set to all
+                        * zero, because it is opened up with lseek,
+                        * so we don't need to do any more
+                        * initialisation here
+                        */
+               }
+       } else if(fd==-1) {
+               g_critical (G_GNUC_PRETTY_FUNCTION
+                           ": shared file [%s] open error: %s",
+                           shared_file (), g_strerror (errno));
                exit (-1);
+       } else {
+               /* We dont need to fork the handle daemon */
        }
        
-       /* From now on, we need to delete the shm segment before
-        * exiting on error if we created it (ie, if
-        * fork_daemon==TRUE)
+       /* From now on, we need to delete the file before exiting on
+        * error if we created it (ie, if fork_daemon==TRUE)
+        */
+
+       /* Use stat to find the file size (instead of hard coding it)
+        * so that we can expand the file later if needed (for more
+        * handles or scratch space, though that will require a tweak
+        * to the file format to store the count).
         */
-       shm_seg=shmat (*shm_id, NULL, 0);
-       if(shm_seg==(gpointer)-1) {
-               g_critical (G_GNUC_PRETTY_FUNCTION ": shmat error: %s",
-                           strerror (errno));
+       if(fstat (fd, &statbuf)==-1) {
+               g_critical (G_GNUC_PRETTY_FUNCTION ": fstat error: %s",
+                           g_strerror (errno));
                if(fork_daemon==TRUE) {
                        _wapi_shm_destroy ();
                }
                exit (-1);
        }
 
-       if(daemon==TRUE) {
-               /* No more to do in the daemon */
-               *success=TRUE;
-               return(shm_seg);
+       if(statbuf.st_size < wanted_size) {
+#ifdef HAVE_LARGE_FILE_SUPPORT
+               /* Keep gcc quiet... */
+               g_critical (G_GNUC_PRETTY_FUNCTION ": shared file [%s] is not big enough! (found %lld, need %d bytes)", shared_file (), statbuf.st_size, wanted_size);
+#else
+               g_critical (G_GNUC_PRETTY_FUNCTION ": shared file [%s] is not big enough! (found %ld, need %d bytes)", shared_file (), statbuf.st_size, wanted_size);
+#endif
+               if(fork_daemon==TRUE) {
+                       _wapi_shm_destroy ();
+               }
+               exit (-1);
+       }
+       
+       shm_seg=mmap (NULL, statbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED,
+                     fd, 0);
+       if(shm_seg==MAP_FAILED) {
+               g_critical (G_GNUC_PRETTY_FUNCTION ": mmap error: %s",
+                           g_strerror (errno));
+               if(fork_daemon==TRUE) {
+                       _wapi_shm_destroy ();
+               }
+               exit (-1);
        }
+       close (fd);
                
        data=shm_seg;
 
@@ -169,7 +243,7 @@ try_again:
                        }
                        
                        /* _wapi_daemon_main() does not return */
-                       _wapi_daemon_main ();
+                       _wapi_daemon_main (data);
                        
                        /* But just in case... */
                        data->daemon_running=DAEMON_DIED_AT_STARTUP;
@@ -242,28 +316,10 @@ try_again:
 void _wapi_shm_destroy (void)
 {
 #ifndef DISABLE_SHARED_HANDLES
-       int shm_id;
-       key_t key;
-               
-       /*
-        * This is an attempt to get a unique key id.  The
-        * first arg to ftok is a path, so when the config
-        * file support is done we should use that.
-        */
-       key=ftok (g_get_home_dir (), _WAPI_HANDLE_VERSION);
-       
-       shm_id=shmget (key, 0, 0600);
-       if(shm_id==-1 && errno==ENOENT) {
-               return;
-       } else if (shm_id==-1) {
-               g_message (G_GNUC_PRETTY_FUNCTION ": shmget error: %s",
-                          strerror (errno));
-               exit (-1);
-       }
-       if(shmctl (shm_id, IPC_RMID, NULL)==-1) {
-               g_message (G_GNUC_PRETTY_FUNCTION ": shmctl error: %s",
-                          strerror (errno));
-               exit (-1);
-       }
+#ifdef DEBUG
+       g_message (G_GNUC_PRETTY_FUNCTION ": unlinking %s", shared_file ());
+#endif
+       unlink (shared_file ());
 #endif /* DISABLE_SHARED_HANDLES */
 }
+
index fe4698986437a875cbfa35bcb8c0bd3303bc1cdd..08dc47c9bb5671c8c01124bc0ea756158bfc5e82 100644 (file)
@@ -23,8 +23,7 @@ enum {
 
 #define _WAPI_SHM_SCRATCH_SIZE 409600
 
-extern gpointer _wapi_shm_attach (gboolean daemon, gboolean *success,
-                                 int *shm_id);
+extern gpointer _wapi_shm_attach (gboolean *success);
 extern void _wapi_shm_destroy (void);
 
 #endif /* _WAPI_SHARED_H_ */
index 8730db425271da0193b3ef9cd7fbfec50c97fdf1..0f035fec6cce38d2ac406fb3538a98960bc4ee0e 100644 (file)
 
 /* Increment this whenever an incompatible change is made to the
  * shared handle structure.
- *
- * If this ever reaches 255, we have problems :-(
  */
-#define _WAPI_HANDLE_VERSION 7
+#define _WAPI_HANDLE_VERSION 0
 
 typedef enum {
        WAPI_HANDLE_UNUSED=0,