Bump version to 0.3.5next
[archipelago] / xseg / drivers / user / xseg_posix.c
1 /*
2  * Copyright 2012 GRNET S.A. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or
5  * without modification, are permitted provided that the following
6  * conditions are met:
7  *
8  *   1. Redistributions of source code must retain the above
9  *      copyright notice, this list of conditions and the following
10  *      disclaimer.
11  *   2. Redistributions in binary form must reproduce the above
12  *      copyright notice, this list of conditions and the following
13  *      disclaimer in the documentation and/or other materials
14  *      provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  * The views and conclusions contained in the software and
30  * documentation are those of the authors and should not be
31  * interpreted as representing official policies, either expressed
32  * or implied, of GRNET S.A.
33  */
34
35 #define _GNU_SOURCE
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/mman.h>
42 #include <sys/syscall.h>
43 #include <fcntl.h>
44 #include <errno.h>
45 #include <string.h>
46 #include <signal.h>
47 #include <sys/util.h>
48 #include <xseg/xseg.h>
49 #include <xtypes/xobj.h>
50 #include <drivers/xseg_posix.h>
51 #define ERRSIZE 512
52 char errbuf[ERRSIZE];
53
54 static long posix_allocate(const char *name, uint64_t size)
55 {
56         int fd, r;
57         fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0770);
58         if (fd < 0) {
59                 XSEGLOG("Cannot create shared segment: %s\n",
60                         strerror_r(errno, errbuf, ERRSIZE));
61                 return fd;
62         }
63
64         r = lseek(fd, size -1, SEEK_SET);
65         if (r < 0) {
66                 close(fd);
67                 XSEGLOG("Cannot seek into segment file: %s\n",
68                         strerror_r(errno, errbuf, ERRSIZE));
69                 return r;
70         }
71
72         errbuf[0] = 0;
73         r = write(fd, errbuf, 1);
74         if (r != 1) {
75                 close(fd);
76                 XSEGLOG("Failed to set segment size: %s\n",
77                         strerror_r(errno, errbuf, ERRSIZE));
78                 return r;
79         }
80
81         close(fd);
82         return 0;
83 }
84
85 static long posix_deallocate(const char *name)
86 {
87         return shm_unlink(name);
88 }
89
90 static void *posix_map(const char *name, uint64_t size, struct xseg *seg)
91 {
92         struct xseg *xseg;
93         int fd;
94
95 //      if (seg)
96 //              XSEGLOG("struct xseg * is not NULL. Ignoring...\n");
97
98         fd = shm_open(name, O_RDWR, 0000);
99         if (fd < 0) {
100                 XSEGLOG("Failed to open '%s' for mapping: %s\n",
101                         name, strerror_r(errno, errbuf, ERRSIZE));
102                 return NULL;
103         }
104
105         xseg = mmap (   XSEG_BASE_AS_PTR,
106                         size,
107                         PROT_READ | PROT_WRITE,
108                         MAP_SHARED | MAP_FIXED /* | MAP_LOCKED */,
109                         fd, 0   );
110
111         if (xseg == MAP_FAILED) {
112                 XSEGLOG("Could not map segment: %s\n",
113                         strerror_r(errno, errbuf, ERRSIZE));
114                 return NULL;
115         }
116
117         close(fd);
118         return xseg;
119 }
120
121 static void posix_unmap(void *ptr, uint64_t size)
122 {
123         struct xseg *xseg = ptr;
124         (void)munmap(xseg, xseg->segment_size);
125 }
126
127
128 static void handler(int signum)
129 {
130         static unsigned long counter;
131         printf("%lu: signal %d: this shouldn't have happened.\n", counter, signum);
132         counter ++;
133 }
134
135 static sigset_t savedset, set;
136 static pid_t pid;
137
138 static int posix_local_signal_init(struct xseg *xseg, xport portno)
139 {
140         void (*h)(int);
141         int r;
142         h = signal(SIGIO, handler);
143         if (h == SIG_ERR)
144                 return -1;
145
146         sigemptyset(&set);
147         sigaddset(&set, SIGIO);
148
149         r = sigprocmask(SIG_BLOCK, &set, &savedset);
150         if (r < 0)
151                 return -1;
152
153         pid = syscall(SYS_gettid);
154         return 0;
155 }
156
157 static void posix_local_signal_quit(struct xseg *xseg, xport portno)
158 {
159         pid = 0;
160         signal(SIGIO, SIG_DFL);
161         sigprocmask(SIG_SETMASK, &savedset, NULL);
162 }
163
164 static int posix_remote_signal_init(void)
165 {
166         return 0;
167 }
168
169 static void posix_remote_signal_quit(void)
170 {
171         return;
172 }
173
174 static int posix_prepare_wait(struct xseg *xseg, uint32_t portno)
175 {
176         struct xseg_port *port = xseg_get_port(xseg, portno);
177         if (!port)
178                 return -1;
179         struct posix_signal_desc *psd = xseg_get_signal_desc(xseg, port);
180         if (!psd)
181                 return -1;
182         psd->waitcue = pid;
183         return 0;
184 }
185
186 static int posix_cancel_wait(struct xseg *xseg, uint32_t portno)
187 {
188         struct xseg_port *port = xseg_get_port(xseg, portno);
189         if (!port)
190                 return -1;
191         struct posix_signal_desc *psd = xseg_get_signal_desc(xseg, port);
192         if (!psd)
193                 return -1;
194         psd->waitcue = 0;
195         return 0;
196 }
197
198 static int posix_wait_signal(struct xseg *xseg, void *sd, uint32_t usec_timeout)
199 {
200         int r;
201         siginfo_t siginfo;
202         struct timespec ts;
203
204         ts.tv_sec = usec_timeout / 1000000;
205         ts.tv_nsec = 1000 * (usec_timeout - ts.tv_sec * 1000000);
206
207         /* FIXME: Now that posix signaling is fixed, we could get rid of the timeout
208          * and use a NULL timespec linux-specific)
209          */
210         r = sigtimedwait(&set, &siginfo, &ts);
211         if (r < 0)
212                 return r;
213
214         return siginfo.si_signo;
215 }
216
217 static int posix_signal(struct xseg *xseg, uint32_t portno)
218 {
219         struct xseg_port *port = xseg_get_port(xseg, portno);
220         if (!port)
221                 return -1;
222         struct posix_signal_desc *psd = xseg_get_signal_desc(xseg, port);
223         if (!psd)
224                 return -1;
225         pid_t cue = (pid_t)psd->waitcue;
226         if (!cue)
227                 //HACKY!
228                 return -2;
229
230         /* FIXME: Make calls to xseg_signal() check for errors */
231         return syscall(SYS_tkill, cue, SIGIO);
232 }
233
234 static void *posix_malloc(uint64_t size)
235 {
236         return malloc((size_t)size);
237 }
238
239 static void *posix_realloc(void *mem, uint64_t size)
240 {
241         return realloc(mem, (size_t)size);
242 }
243
244 static void posix_mfree(void *mem)
245 {
246         free(mem);
247 }
248
249
250 int posix_init_signal_desc(struct xseg *xseg, void *sd)
251 {
252         struct posix_signal_desc *psd = sd;
253         if (!psd)
254                 return -1;
255         psd->waitcue = 0;
256         return 0;
257 }
258
259 void posix_quit_signal_desc(struct xseg *xseg, void *sd)
260 {
261         return;
262 }
263
264 void * posix_alloc_data(struct xseg *xseg)
265 {
266         struct xobject_h *sd_h = xseg_get_objh(xseg, MAGIC_POSIX_SD,
267                         sizeof(struct posix_signal_desc));
268         return sd_h;
269 }
270
271 void posix_free_data(struct xseg *xseg, void *data)
272 {
273         if (data)
274                 xseg_put_objh(xseg, (struct xobject_h *)data);
275 }
276
277 void *posix_alloc_signal_desc(struct xseg *xseg, void *data)
278 {
279         struct xobject_h *sd_h = (struct xobject_h *) data;
280         if (!sd_h)
281                 return NULL;
282         struct posix_signal_desc *psd = xobj_get_obj(sd_h, X_ALLOC);
283         if (!psd)
284                 return NULL;
285         psd->waitcue = 0;
286         return psd;
287
288 }
289
290 void posix_free_signal_desc(struct xseg *xseg, void *data, void *sd)
291 {
292         struct xobject_h *sd_h = (struct xobject_h *) data;
293         if (!sd_h)
294                 return;
295         if (sd)
296                 xobj_put_obj(sd_h, sd);
297         return;
298 }
299
300 static struct xseg_type xseg_posix = {
301         /* xseg_operations */
302         {
303                 .mfree          = posix_mfree,
304                 .allocate       = posix_allocate,
305                 .deallocate     = posix_deallocate,
306                 .map            = posix_map,
307                 .unmap          = posix_unmap,
308         },
309         /* name */
310         "posix"
311 };
312
313 static struct xseg_peer xseg_peer_posix = {
314         /* xseg_peer_operations */
315         {
316                 .init_signal_desc   = posix_init_signal_desc,
317                 .quit_signal_desc   = posix_quit_signal_desc,
318                 .alloc_data         = posix_alloc_data,
319                 .free_data          = posix_free_data,
320                 .alloc_signal_desc  = posix_alloc_signal_desc,
321                 .free_signal_desc   = posix_free_signal_desc,
322                 .local_signal_init  = posix_local_signal_init,
323                 .local_signal_quit  = posix_local_signal_quit,
324                 .remote_signal_init = posix_remote_signal_init,
325                 .remote_signal_quit = posix_remote_signal_quit,
326                 .prepare_wait       = posix_prepare_wait,
327                 .cancel_wait        = posix_cancel_wait,
328                 .wait_signal        = posix_wait_signal,
329                 .signal             = posix_signal,
330                 .malloc             = posix_malloc,
331                 .realloc            = posix_realloc,
332                 .mfree              = posix_mfree,
333         },
334         /* name */
335         "posix"
336 };
337
338 void xseg_posix_init(void)
339 {
340         xseg_register_type(&xseg_posix);
341         xseg_register_peer(&xseg_peer_posix);
342 }
343