+/*
+ * mono-mmap.c: Support for mapping code into the process address space
+ *
+ * Author:
+ * Mono Team (mono-list@lists.ximian.com)
+ *
+ * Copyright 2001-2008 Novell, Inc.
+ */
+
#include "config.h"
#ifdef PLATFORM_WIN32
#include <io.h>
#else
#include <sys/types.h>
+#if HAVE_SYS_STAT_H
#include <sys/stat.h>
+#endif
+#if HAVE_SYS_MMAN_H
#include <sys/mman.h>
+#endif
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
#endif
#include "mono-mmap.h"
+#include "mono-proclib.h"
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#define MAP_32BIT 0
#endif
+typedef struct {
+ int size;
+ int pid;
+ int reserved;
+ short stats_start;
+ short stats_end;
+} SAreaHeader;
+
+static void* malloced_shared_area = NULL;
+
+static void*
+malloc_shared_area (int pid)
+{
+ int size = mono_pagesize ();
+ SAreaHeader *sarea = g_malloc0 (size);
+ sarea->size = size;
+ sarea->pid = pid;
+ sarea->stats_start = sizeof (SAreaHeader);
+ sarea->stats_end = sizeof (SAreaHeader);
+
+ return sarea;
+}
+
#ifdef PLATFORM_WIN32
int
int
mono_vfree (void *addr, size_t length)
{
- return VirtualFree (addr, length, MEM_RELEASE) == 0;
+ int res = VirtualFree (addr, 0, MEM_RELEASE);
+
+ g_assert (res);
+
+ return 0;
}
void*
return VirtualProtect (addr, length, prot, &oldprot) == 0;
}
-#elif defined(HAVE_MMAP)
+void*
+mono_shared_area (void)
+{
+ /* get the pid here */
+ return malloc_shared_area (0);
+}
+
+void
+mono_shared_area_remove (void)
+{
+ if (malloced_shared_area)
+ g_free (malloced_shared_area);
+}
+
+void*
+mono_shared_area_for_pid (void *pid)
+{
+ return NULL;
+}
+
+void
+mono_shared_area_unload (void *area)
+{
+}
+
+int
+mono_shared_area_instances (void **array, int count)
+{
+ return 0;
+}
+
+#else
+#if defined(HAVE_MMAP)
/**
* mono_pagesize:
return 0;
}
+int
+mono_mprotect (void *addr, size_t length, int flags)
+{
+ if (flags & MONO_MMAP_DISCARD) {
+ memset (addr, 0, length);
+ }
+ return 0;
+}
+#endif // HAVE_MMAP
+
+#if defined(HAVE_SHM_OPEN)
+
+static int
+mono_shared_area_instances_slow (void **array, int count, gboolean cleanup)
+{
+ int i, j = 0;
+ int num;
+ void *data;
+ gpointer *processes = mono_process_list (&num);
+ for (i = 0; i < num; ++i) {
+ data = mono_shared_area_for_pid (processes [i]);
+ if (!data)
+ continue;
+ mono_shared_area_unload (data);
+ if (!cleanup) {
+ if (j < count)
+ array [j++] = processes [i];
+ else
+ break;
+ }
+ }
+ g_free (processes);
+ return j;
+}
+
+static int
+mono_shared_area_instances_helper (void **array, int count, gboolean cleanup)
+{
+ const char *name;
+ int i = 0;
+ int curpid = getpid ();
+ GDir *dir = g_dir_open ("/dev/shm/", 0, NULL);
+ if (!dir)
+ return mono_shared_area_instances_slow (array, count, cleanup);
+ while ((name = g_dir_read_name (dir))) {
+ int pid;
+ char *nend;
+ if (strncmp (name, "mono.", 5))
+ continue;
+ pid = strtol (name + 5, &nend, 10);
+ if (pid <= 0 || nend == name + 5 || *nend)
+ continue;
+ if (!cleanup) {
+ if (i < count)
+ array [i++] = GINT_TO_POINTER (pid);
+ else
+ break;
+ }
+ if (curpid != pid && kill (pid, SIGCONT) == -1 && errno == ESRCH) {
+ char buf [128];
+ g_snprintf (buf, sizeof (buf), "/mono.%d", pid);
+ shm_unlink (buf);
+ }
+ }
+ g_dir_close (dir);
+ return i;
+}
+
void*
-mono_file_map (size_t length, int flags, int fd, guint64 offset, void **ret_handle)
+mono_shared_area (void)
+{
+ int fd;
+ int pid = getpid ();
+ /* we should allow the user to configure the size */
+ int size = mono_pagesize ();
+ char buf [128];
+ void *res;
+ SAreaHeader *header;
+
+ /* perform cleanup of segments left over from dead processes */
+ mono_shared_area_instances_helper (NULL, 0, TRUE);
+
+ g_snprintf (buf, sizeof (buf), "/mono.%d", pid);
+
+ fd = shm_open (buf, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP);
+ if (fd == -1 && errno == EEXIST) {
+ /* leftover */
+ shm_unlink (buf);
+ fd = shm_open (buf, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP);
+ }
+ /* in case of failure we try to return a memory area anyway,
+ * even if it means the data can't be read by other processes
+ */
+ if (fd == -1)
+ return malloc_shared_area (pid);
+ if (ftruncate (fd, size) != 0) {
+ shm_unlink (buf);
+ close (fd);
+ }
+ res = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ if (res == MAP_FAILED) {
+ shm_unlink (buf);
+ close (fd);
+ return malloc_shared_area (pid);
+ }
+ /* we don't need the file descriptor anymore */
+ close (fd);
+ header = res;
+ header->size = size;
+ header->pid = pid;
+ header->stats_start = sizeof (SAreaHeader);
+ header->stats_end = sizeof (SAreaHeader);
+
+ atexit (mono_shared_area_remove);
+ return res;
+}
+
+void
+mono_shared_area_remove (void)
+{
+ char buf [128];
+ g_snprintf (buf, sizeof (buf), "/mono.%d", getpid ());
+ shm_unlink (buf);
+ if (malloced_shared_area)
+ g_free (malloced_shared_area);
+}
+
+void*
+mono_shared_area_for_pid (void *pid)
{
- guint64 cur_offset;
- size_t bytes_read;
- void *ptr = malloc (length);
- if (!ptr)
+ int fd;
+ /* we should allow the user to configure the size */
+ int size = mono_pagesize ();
+ char buf [128];
+ void *res;
+
+ g_snprintf (buf, sizeof (buf), "/mono.%d", GPOINTER_TO_INT (pid));
+
+ fd = shm_open (buf, O_RDONLY, S_IRUSR|S_IRGRP);
+ if (fd == -1)
return NULL;
- cur_offset = lseek (fd, 0, SEEK_CUR);
- if (lseek (fd, offset, SEEK_SET) != offset) {
- free (ptr);
+ res = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+ if (res == MAP_FAILED) {
+ close (fd);
return NULL;
}
- bytes_read = read (fd, ptr, length);
- lseek (fd, cur_offset, SEEK_SET);
- *ret_handle = NULL;
- return ptr;
+ /* FIXME: validate the area */
+ /* we don't need the file descriptor anymore */
+ close (fd);
+ return res;
+}
+
+void
+mono_shared_area_unload (void *area)
+{
+ /* FIXME: currently we load only a page */
+ munmap (area, mono_pagesize ());
}
int
-mono_file_unmap (void *addr, void *handle)
+mono_shared_area_instances (void **array, int count)
+{
+ return mono_shared_area_instances_helper (array, count, FALSE);
+}
+#else
+void*
+mono_shared_area (void)
+{
+ return malloc_shared_area (getpid ());
+}
+
+void
+mono_shared_area_remove (void)
+{
+ if (malloced_shared_area)
+ g_free (malloced_shared_area);
+ malloced_shared_area = NULL;
+}
+
+void*
+mono_shared_area_for_pid (void *pid)
+{
+ return NULL;
+}
+
+void
+mono_shared_area_unload (void *area)
{
- free (addr);
- return 0;
}
int
-mono_mprotect (void *addr, size_t length, int flags)
+mono_shared_area_instances (void **array, int count)
{
- if (flags & MONO_MMAP_DISCARD) {
- memset (addr, 0, length);
- }
return 0;
}
-#endif
+#endif // HAVE_SHM_OPEN
+#endif // PLATFORM_WIN32