2 * Copyright 2012 GRNET S.A. All rights reserved.
4 * Redistribution and use in source and binary forms, with or
5 * without modification, are permitted provided that the following
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
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.
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.
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.
39 #include <sys/types.h>
42 #include <sys/syscall.h>
48 #include <xseg/xseg.h>
50 #include <drivers/xseg_pthread.h>
54 static void *pthread_malloc(uint64_t size);
55 static void pthread_mfree(void *mem);
57 static long pthread_allocate(const char *name, uint64_t size)
60 fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0770);
62 XSEGLOG("Cannot create shared segment: %s\n",
63 strerror_r(errno, errbuf, ERRSIZE));
67 r = lseek(fd, size -1, SEEK_SET);
70 XSEGLOG("Cannot seek into segment file: %s\n",
71 strerror_r(errno, errbuf, ERRSIZE));
76 r = write(fd, errbuf, 1);
79 XSEGLOG("Failed to set segment size: %s\n",
80 strerror_r(errno, errbuf, ERRSIZE));
88 static long pthread_deallocate(const char *name)
90 return shm_unlink(name);
93 static void *pthread_map(const char *name, uint64_t size, struct xseg *seg)
99 XSEGLOG("struct xseg * is not NULL. Ignoring...\n");
101 fd = shm_open(name, O_RDWR, 0000);
103 XSEGLOG("Failed to open '%s' for mapping: %s\n",
104 name, strerror_r(errno, errbuf, ERRSIZE));
108 xseg = mmap ( XSEG_BASE_AS_PTR,
110 PROT_READ | PROT_WRITE,
111 MAP_SHARED | MAP_FIXED /* | MAP_LOCKED */,
114 if (xseg == MAP_FAILED) {
115 XSEGLOG("Could not map segment: %s\n",
116 strerror_r(errno, errbuf, ERRSIZE));
124 static void pthread_unmap(void *ptr, uint64_t size)
126 struct xseg *xseg = ptr;
127 (void)munmap(xseg, xseg->segment_size);
131 static void handler(int signum)
133 static unsigned long counter;
134 printf("%lu: signal %d: this shouldn't have happened.\n", counter, signum);
138 static pthread_key_t pid_key, xpidx_key;
139 static pthread_key_t mask_key, act_key;
140 static pthread_key_t id_key;
141 static pthread_once_t once_init = PTHREAD_ONCE_INIT;
142 static pthread_once_t once_quit = PTHREAD_ONCE_INIT;
144 static volatile int id = 0;
146 static void keys_init(void)
150 r = pthread_key_create(&pid_key, NULL);
156 r = pthread_key_create(&xpidx_key, NULL);
161 r = pthread_key_create(&mask_key, NULL);
167 r = pthread_key_create(&act_key, NULL);
172 r = pthread_key_create(&id_key, NULL);
178 once_quit = PTHREAD_ONCE_INIT;
181 #define INT_TO_POINTER(__myptr, __myint) \
183 unsigned long __foo____myptr = (unsigned long) __myint; \
184 __myptr = (void *) __foo____myptr ; \
187 #define POINTER_TO_INT(__myint, __myptr)\
189 unsigned long __foo____myint = (unsigned long) __myptr; \
190 __myint = (int) __foo____myint ; \
193 /* must be called by each thread */
194 static int pthread_local_signal_init(struct xseg *xseg, xport portno)
199 sigset_t *savedset, *set;
200 struct sigaction *act, *old_act;
202 savedset = pthread_malloc(sizeof(sigset_t));
205 set = pthread_malloc(sizeof(sigset_t));
209 act = pthread_malloc(sizeof(struct sigaction));
212 old_act = pthread_malloc(sizeof(struct sigaction));
216 pthread_once(&once_init, keys_init);
221 act->sa_handler = handler;
224 if(sigaction(SIGIO, act, old_act) < 0)
228 sigaddset(set, SIGIO);
230 r = pthread_sigmask(SIG_BLOCK, set, savedset);
235 my_id = *(volatile int *) &id;
236 while (!__sync_bool_compare_and_swap(&id, my_id, my_id+1)){
237 my_id = *(volatile int *) &id;
239 pid = syscall(SYS_gettid);
240 INT_TO_POINTER(tmp, pid);
241 INT_TO_POINTER(tmp2, my_id);
242 if (pthread_setspecific(pid_key, tmp) ||
243 pthread_setspecific(mask_key, savedset) ||
244 pthread_setspecific(act_key, old_act) ||
245 pthread_setspecific(id_key, tmp2))
251 pthread_sigmask(SIG_BLOCK, savedset, NULL);
253 sigaction(SIGIO, old_act, NULL);
255 pthread_mfree(old_act);
261 pthread_mfree(savedset);
266 /* should be called by each thread which had initialized signals */
267 static void pthread_local_signal_quit(struct xseg *xseg, xport portno)
270 struct sigaction *old_act;
272 savedset = pthread_getspecific(act_key);
273 old_act = pthread_getspecific(mask_key);
275 sigaction(SIGIO, old_act, NULL);
277 pthread_sigmask(SIG_SETMASK, savedset, NULL);
280 static int pthread_remote_signal_init(void)
285 static void pthread_remote_signal_quit(void)
290 static int pthread_prepare_wait(struct xseg *xseg, uint32_t portno)
295 struct xseg_port *port = xseg_get_port(xseg, portno);
298 struct pthread_signal_desc *psd = xseg_get_signal_desc(xseg, port);
302 tmp = pthread_getspecific(pid_key);
303 POINTER_TO_INT(pid, tmp);
306 tmp = pthread_getspecific(id_key);
307 POINTER_TO_INT(my_id, tmp);
308 psd->pids[my_id] = pid;
312 static int pthread_cancel_wait(struct xseg *xseg, uint32_t portno)
317 struct xseg_port *port = xseg_get_port(xseg, portno);
320 struct pthread_signal_desc *psd = xseg_get_signal_desc(xseg, port);
324 tmp = pthread_getspecific(pid_key);
325 POINTER_TO_INT(pid, tmp);
329 tmp = pthread_getspecific(id_key);
330 POINTER_TO_INT(my_id, tmp);
331 psd->pids[my_id] = 0;
336 static int pthread_wait_signal(struct xseg *xseg, uint32_t usec_timeout)
343 sigaddset(&set, SIGIO);
345 ts.tv_sec = usec_timeout / 1000000;
346 ts.tv_nsec = 1000 * (usec_timeout - ts.tv_sec * 1000000);
348 r = sigtimedwait(&set, &siginfo, &ts);
352 return siginfo.si_signo;
355 static int pthread_signal(struct xseg *xseg, uint32_t portno)
359 struct xseg_port *port = xseg_get_port(xseg, portno);
362 struct pthread_signal_desc *psd = xseg_get_signal_desc(xseg, port);
367 for (i = 0; i < MAX_WAITERS; i++) {
370 return syscall(SYS_tkill, cue, SIGIO);
373 /* no waiter found */
377 static void *pthread_malloc(uint64_t size)
379 return malloc((size_t)size);
382 static void *pthread_realloc(void *mem, uint64_t size)
384 return realloc(mem, (size_t)size);
387 static void pthread_mfree(void *mem)
392 static struct xseg_type xseg_pthread = {
393 /* xseg_operations */
395 .mfree = pthread_mfree,
396 .allocate = pthread_allocate,
397 .deallocate = pthread_deallocate,
399 .unmap = pthread_unmap,
405 int pthread_init_signal_desc(struct xseg *xseg, void *sd)
408 struct pthread_signal_desc *psd = (struct pthread_signal_desc *)sd;
409 for (i = 0; i < MAX_WAITERS; i++) {
415 void pthread_quit_signal_desc(struct xseg *xseg, void *sd)
418 struct pthread_signal_desc *psd = (struct pthread_signal_desc *)sd;
419 for (i = 0; i < MAX_WAITERS; i++) {
425 void * pthread_alloc_data(struct xseg *xseg)
427 struct xobject_h *sd_h = xseg_get_objh(xseg, MAGIC_PTHREAD_SD,
428 sizeof(struct pthread_signal_desc));
432 void pthread_free_data(struct xseg *xseg, void *data)
435 xseg_put_objh(xseg, (struct xobject_h *)data);
438 void *pthread_alloc_signal_desc(struct xseg *xseg, void *data)
440 struct xobject_h *sd_h = (struct xobject_h *) data;
443 struct pthread_signal_desc *psd = xobj_get_obj(sd_h, X_ALLOC);
450 void pthread_free_signal_desc(struct xseg *xseg, void *data, void *sd)
452 struct xobject_h *sd_h = (struct xobject_h *) data;
456 xobj_put_obj(sd_h, sd);
461 static struct xseg_peer xseg_peer_pthread = {
462 /* xseg_peer_operations */
464 .init_signal_desc = pthread_init_signal_desc,
465 .quit_signal_desc = pthread_quit_signal_desc,
466 .alloc_data = pthread_alloc_data,
467 .free_data = pthread_free_data,
468 .alloc_signal_desc = pthread_alloc_signal_desc,
469 .free_signal_desc = pthread_free_signal_desc,
470 .local_signal_init = pthread_local_signal_init,
471 .local_signal_quit = pthread_local_signal_quit,
472 .remote_signal_init = pthread_remote_signal_init,
473 .remote_signal_quit = pthread_remote_signal_quit,
474 .prepare_wait = pthread_prepare_wait,
475 .cancel_wait = pthread_cancel_wait,
476 .wait_signal = pthread_wait_signal,
477 .signal = pthread_signal,
478 .malloc = pthread_malloc,
479 .realloc = pthread_realloc,
480 .mfree = pthread_mfree,
486 void xseg_pthread_init(void)
488 xseg_register_type(&xseg_pthread);
489 xseg_register_peer(&xseg_peer_pthread);