initialization from my own repository
[archipelago] / xseg / drivers / xseg_posix.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <sys/mman.h>
8 #include <sys/syscall.h>
9 #include <fcntl.h>
10 #include <errno.h>
11 #include <string.h>
12 #include <signal.h>
13 #include <xseg/xseg.h>
14 #include <sys/util.h>
15
16 #define ERRSIZE 512
17 char errbuf[ERRSIZE];
18
19 static long posix_allocate(const char *name, uint64_t size)
20 {
21         int fd, r;
22         fd = shm_open(name, O_RDWR | O_CREAT, 0770);
23         if (fd < 0) {
24                 LOGMSG("Cannot create shared segment: %s\n",
25                         strerror_r(errno, errbuf, ERRSIZE));
26                 return fd;
27         }
28
29         r = lseek(fd, size -1, SEEK_SET);
30         if (r < 0) {
31                 close(fd);
32                 LOGMSG("Cannot seek into segment file: %s\n",
33                         strerror_r(errno, errbuf, ERRSIZE));
34                 return r;
35         }
36
37         errbuf[0] = 0;
38         r = write(fd, errbuf, 1);
39         if (r != 1) {
40                 close(fd);
41                 LOGMSG("Failed to set segment size: %s\n",
42                         strerror_r(errno, errbuf, ERRSIZE));
43                 return r;
44         }
45
46         close(fd);
47         return 0;
48 }
49
50 static long posix_deallocate(const char *name)
51 {
52         return shm_unlink(name);
53 }
54
55 static void *posix_map(const char *name, uint64_t size)
56 {
57         struct xseg *xseg;
58         int fd;
59         fd = shm_open(name, O_RDWR, 0000);
60         if (fd < 0) {
61                 LOGMSG("Failed to open '%s' for mapping: %s\n",
62                         name, strerror_r(errno, errbuf, ERRSIZE));
63                 return NULL;
64         }
65
66         xseg = mmap (   XSEG_BASE_AS_PTR,
67                         size,
68                         PROT_READ | PROT_WRITE,
69                         MAP_SHARED | MAP_FIXED /* | MAP_LOCKED */,
70                         fd, 0   );
71
72         if (xseg == MAP_FAILED) {
73                 LOGMSG("Could not map segment: %s\n",
74                         strerror_r(errno, errbuf, ERRSIZE));
75                 return NULL;
76         }
77
78         close(fd);
79         return xseg;
80 }
81
82 static void posix_unmap(void *ptr, uint64_t size)
83 {
84         struct xseg *xseg = ptr;
85         (void)munmap(xseg, xseg->segment_size);
86 }
87
88
89 static void handler(int signum)
90 {
91         static unsigned long counter;
92         printf("%lu: signal %d: this shouldn't have happend.\n", counter, signum);
93         counter ++;
94 }
95
96 static sigset_t savedset, set;
97 static pid_t pid;
98
99 static int posix_signal_init(void)
100 {
101         void (*h)(int);
102         int r;
103         h = signal(SIGIO, handler);
104         if (h == SIG_ERR)
105                 return -1;
106
107         sigemptyset(&set);
108         sigaddset(&set, SIGIO);
109
110         r = sigprocmask(SIG_BLOCK, &set, &savedset);
111         if (r < 0)
112                 return -1;
113
114         pid = syscall(SYS_gettid);
115         return 0;
116 }
117
118 static void posix_signal_quit(void)
119 {
120         signal(SIGIO, SIG_DFL);
121         sigprocmask(SIG_SETMASK, &savedset, NULL);
122 }
123
124 static int posix_prepare_wait(struct xseg_port *port)
125 {
126         port->waitcue = pid;
127         return 0;
128 }
129
130 static int posix_cancel_wait(struct xseg_port *port)
131 {
132         port->waitcue = 0;
133         return 0;
134 }
135
136 static int posix_wait_signal(struct xseg_port *port, uint32_t usec_timeout)
137 {
138         int r;
139         siginfo_t siginfo;
140         struct timespec ts;
141
142         ts.tv_sec = usec_timeout / 1000000;
143         ts.tv_nsec = 1000 * (usec_timeout - ts.tv_sec * 1000000);
144
145         r = sigtimedwait(&set, &siginfo, &ts);
146         if (r < 0)
147                 return r;
148
149         return siginfo.si_signo;
150 }
151
152 static int posix_signal(struct xseg_port *port)
153 {
154         union sigval sigval = {0};
155         pid_t cue = (pid_t)port->waitcue;
156         if (!cue)
157                 return -1;
158         sigqueue(cue, SIGIO, sigval);
159         /* XXX: on error what? */
160         return 0;
161 }
162
163 static void *posix_malloc(uint64_t size)
164 {
165         return malloc((size_t)size);
166 }
167
168 static void *posix_realloc(void *mem, uint64_t size)
169 {
170         return realloc(mem, (size_t)size);
171 }
172
173 static void posix_mfree(void *mem)
174 {
175         free(mem);
176 }
177
178 static struct xseg_type xseg_posix = {
179         /* xseg_operations */
180         {
181                 .malloc         = posix_malloc,
182                 .realloc        = posix_realloc,
183                 .mfree          = posix_mfree,
184                 .allocate       = posix_allocate,
185                 .deallocate     = posix_deallocate,
186                 .map            = posix_map,
187                 .unmap          = posix_unmap,
188         },
189         /* name */
190         "posix"
191 };
192
193 static struct xseg_peer xseg_peer_posix = {
194         /* xseg_peer_operations */
195         {
196                 .signal_init    = posix_signal_init,
197                 .signal_quit    = posix_signal_quit,
198                 .prepare_wait   = posix_prepare_wait,
199                 .cancel_wait    = posix_cancel_wait,
200                 .wait_signal    = posix_wait_signal,
201                 .signal         = posix_signal,
202                 .malloc         = posix_malloc,
203                 .realloc        = posix_realloc,
204                 .mfree          = posix_mfree,
205         },
206         /* name */
207         "posix"
208 };
209
210 void xseg_posix_init(void)
211 {
212         xseg_register_type(&xseg_posix);
213         xseg_register_peer(&xseg_peer_posix);
214 }
215