1 /* sagittarius-process.c                           -*- mode:c; coding:utf-8; -*-
2  *
3  *   Copyright (c) 2010-2015  Takashi Kato <ktakashi@ymail.com>
4  *
5  *   Redistribution and use in source and binary forms, with or without
6  *   modification, are permitted provided that the following conditions
7  *   are met:
8  *
9  *   1. Redistributions of source code must retain the above copyright
10  *      notice, this list of conditions and the following disclaimer.
11  *
12  *   2. Redistributions in binary form must reproduce the above copyright
13  *      notice, this list of conditions and the following disclaimer in the
14  *      documentation and/or other materials provided with the distribution.
15  *
16  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22  *   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  *   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24  *   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  *   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  *  $Id: $
29  */
30 #include <string.h>
31 #include <sagittarius.h>
32 #define LIBSAGITTARIUS_EXT_BODY
33 #include <sagittarius/extend.h>
34 #include "sagittarius-process.h"
35 
shm_printer(SgObject self,SgPort * port,SgWriteContext * ctx)36 static void shm_printer(SgObject self, SgPort *port, SgWriteContext *ctx)
37 {
38   Sg_Printf(port, UC("#<shared-memory %A>"), SG_SHARED_MEMORY(self)->name);
39 }
40 
41 SG_DEFINE_BUILTIN_CLASS_SIMPLE(Sg_SharedMemoryClass, shm_printer);
42 
make_shared_memory(SgString * name,InternalHandle handle,SgObject bv)43 static SgSharedMemory * make_shared_memory(SgString *name,
44 					   InternalHandle handle,
45 					   SgObject bv)
46 {
47   SgSharedMemory *z = SG_NEW(SgSharedMemory);
48   SG_SET_CLASS(z, SG_CLASS_SHARED_MEMORY);
49   z->handle = handle;
50   z->name = SG_OBJ(name);
51   z->memory = bv;
52   return z;
53 }
54 
55 #ifndef _WIN32
Sg_OpenSharedMemory(SgString * name,size_t size,int flags)56 SgObject Sg_OpenSharedMemory(SgString *name, size_t size, int flags)
57 {
58   char *memname = Sg_Utf32sToUtf8s(name);
59   int fd, f = O_RDWR, truncp = FALSE;
60   uint8_t *ptr;
61   SgSharedMemory *shm;
62   SgObject bv;
63 
64   if (flags & SG_TRUNCATE) {
65     /* f |= O_TRUNC; */
66     truncp = TRUE;
67   }
68   if (flags & SG_CREATE) f |= O_CREAT;
69 
70   /* TODO mode? should we make it executable? */
71   fd = shm_open(memname, f, 0666);
72   if (fd < 0) {
73     int e = errno;
74     const char *msg = strerror(e);
75     if (e == ENOENT) {
76       Sg_IOError(SG_IO_FILE_NOT_EXIST_ERROR,
77 		 SG_INTERN("open-shared-memory"),
78 		 Sg_Utf8sToUtf32s(msg, strlen(msg)),
79 		 name, SG_UNDEF);
80     } else {
81       Sg_SystemError(e, UC("open-shared-memory: shm_open failed. %A"),
82 		     Sg_Utf8sToUtf32s(msg, strlen(msg)));
83     }
84   }
85   /* TODO if not created? */
86   if (truncp) {
87     ftruncate(fd, size);	/* don't check return value */
88   }
89   ptr = (uint8_t *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
90   bv = Sg_MakeByteVectorFromU8Array(ptr, size);
91   shm = make_shared_memory(name, fd, bv);
92   close(fd);
93   return SG_OBJ(shm);
94 }
95 
Sg_CloseSharedMemory(SgSharedMemory * shm)96 SgObject Sg_CloseSharedMemory(SgSharedMemory *shm)
97 {
98   munmap(SG_BVECTOR_ELEMENTS(shm->memory), SG_BVECTOR_SIZE(shm->memory));
99   /* I don't care */
100   shm_unlink(Sg_Utf32sToUtf8s(SG_STRING(shm->name)));
101   SG_BVECTOR_ELEMENTS(shm->memory) = NULL;
102   SG_BVECTOR_SIZE(shm->memory) = 0;
103   return SG_TRUE;
104 }
105 #else
Sg_OpenSharedMemory(SgString * name,size_t size,int flags)106 SgObject Sg_OpenSharedMemory(SgString *name, size_t size, int flags)
107 {
108   HANDLE hMapFile;
109   uint8_t *ptr;
110   wchar_t *memname = Sg_StringToWCharTs(name);
111   DWORD high, low;
112   SgObject bv;
113 
114   high = size>>32;
115   low = size&((1LL<<32)-1);
116   if (flags & SG_CREATE) {
117     hMapFile = CreateFileMappingW(INVALID_HANDLE_VALUE,
118 				  NULL,
119 				  PAGE_READWRITE,
120 				  high,
121 				  low,
122 				  memname);
123   } else {
124     hMapFile = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, memname);
125   }
126   if (hMapFile == NULL) {
127     int err = GetLastError();
128     if (err == ERROR_FILE_NOT_FOUND) {
129       Sg_IOError(SG_IO_FILE_NOT_EXIST_ERROR,
130 		 SG_INTERN("open-shared-memory"),
131 		 Sg_GetLastErrorMessageWithErrorCode(err),
132 		 name, SG_UNDEF);
133     } else {
134       Sg_SystemError(err,
135 		     UC("open-shared-memory: CreateFileMapping failed. %A"),
136 		     Sg_GetLastErrorMessageWithErrorCode(err));
137     }
138   }
139   ptr = (uint8_t *)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, high, low);
140 
141   if (ptr == NULL) {
142     int err = GetLastError();
143     CloseHandle(hMapFile);
144     Sg_SystemError(err,
145 		   UC("open-shared-memory: MapViewOfFile failed. %A"),
146 		   Sg_GetLastErrorMessageWithErrorCode(err));
147   }
148   if (flags & SG_TRUNCATE) {
149     SecureZeroMemory(ptr, size);
150   }
151   bv = Sg_MakeByteVectorFromU8Array(ptr, size);
152   return SG_OBJ(make_shared_memory(name, hMapFile, bv));
153 }
154 
Sg_CloseSharedMemory(SgSharedMemory * shm)155 SgObject Sg_CloseSharedMemory(SgSharedMemory *shm)
156 {
157   UnmapViewOfFile(SG_BVECTOR_ELEMENTS(shm->memory));
158   CloseHandle(shm->handle);
159   return SG_TRUE;
160 }
161 #endif
162 
163 extern void Sg__Init_process_stub(SgLibrary *lib);
164 
Sg_Init_sagittarius__process()165 SG_EXTENSION_ENTRY void CDECL Sg_Init_sagittarius__process()
166 {
167   SgLibrary *lib;
168   SG_INIT_EXTENSION(sagittarius__process);
169   lib = SG_LIBRARY(Sg_FindLibrary(SG_INTERN("(sagittarius process)"), FALSE));
170 
171   Sg_InitStaticClassWithMeta(SG_CLASS_SHARED_MEMORY, UC("<shared-memory>"),
172 			     lib, NULL, SG_FALSE, NULL, 0);
173 
174   Sg__Init_process_stub(lib);
175 }
176