#include <sys/util.h>
#include <xseg/xseg.h>
#include <pthread.h>
-
+#include <drivers/xseg_pthread.h>
#define ERRSIZE 512
char errbuf[ERRSIZE];
+static void *pthread_malloc(uint64_t size);
+static void pthread_mfree(void *mem);
+
static long pthread_allocate(const char *name, uint64_t size)
{
int fd, r;
counter ++;
}
-static sigset_t savedset, set;
-static pthread_key_t key;
+static pthread_key_t pid_key, xpidx_key;
+static pthread_key_t mask_key, act_key;
static pthread_once_t once_init = PTHREAD_ONCE_INIT;
static pthread_once_t once_quit = PTHREAD_ONCE_INIT;
static int isInit;
-static void signal_init(void)
+static void keys_init(void)
{
- void (*h)(int);
int r;
- h = signal(SIGIO, handler);
- if (h == SIG_ERR){
+
+ r = pthread_key_create(&pid_key, NULL);
+ if (r < 0) {
isInit = 0;
return;
}
-
- sigemptyset(&set);
- sigaddset(&set, SIGIO);
-
- r = pthread_sigmask(SIG_BLOCK, &set, &savedset);
+
+ r = pthread_key_create(&xpidx_key, NULL);
+ if (r < 0) {
+ isInit = 0;
+ return;
+ }
+ r = pthread_key_create(&mask_key, NULL);
if (r < 0) {
isInit = 0;
return;
}
- r = pthread_key_create(&key, NULL);
+ r = pthread_key_create(&act_key, NULL);
if (r < 0) {
isInit = 0;
return;
once_quit = PTHREAD_ONCE_INIT;
}
-static void signal_quit(void)
-{
- pthread_key_delete(key);
- signal(SIGIO, SIG_DFL);
- pthread_sigmask(SIG_SETMASK, &savedset, NULL);
- isInit = 0;
- once_init = PTHREAD_ONCE_INIT;
-}
-
#define INT_TO_POINTER(__myptr, __myint) \
do {\
unsigned long __foo__ = (unsigned long) __myint; \
} while (0)
/* must be called by each thread */
-static int pthread_signal_init(void)
+static int pthread_local_signal_init(struct xseg *xseg, xport portno)
{
int r;
pid_t pid;
void *tmp;
- pthread_once(&once_init, signal_init);
+ sigset_t *savedset, *set;
+ struct sigaction *act, *old_act;
+
+ savedset = pthread_malloc(sizeof(sigset_t));
+ if (!savedset)
+ goto err1;
+ set = pthread_malloc(sizeof(sigset_t));
+ if (!set)
+ goto err2;
+
+ act = pthread_malloc(sizeof(struct sigaction));
+ if (!act)
+ goto err3;
+ old_act = pthread_malloc(sizeof(struct sigaction));
+ if (!old_act)
+ goto err4;
+
+ pthread_once(&once_init, keys_init);
if (!isInit)
- return -1;
+ goto err5;
+
+ sigemptyset(set);
+ act->sa_handler = handler;
+ act->sa_mask = *set;
+ act->sa_flags = 0;
+ if(sigaction(SIGIO, act, old_act) < 0)
+ goto err5;
+
+
+ sigaddset(set, SIGIO);
+
+ r = pthread_sigmask(SIG_BLOCK, set, savedset);
+ if (r < 0)
+ goto err6;
+
+
pid = syscall(SYS_gettid);
INT_TO_POINTER(tmp, pid);
- r = pthread_setspecific(key, tmp);
- return r;
+ if (!pthread_setspecific(pid_key, tmp) ||
+ pthread_setspecific(mask_key, savedset) ||
+ pthread_setspecific(act_key, old_act))
+ goto err7;
+
+ return 0;
+
+err7:
+ pthread_sigmask(SIG_BLOCK, savedset, NULL);
+err6:
+ sigaction(SIGIO, old_act, NULL);
+err5:
+ pthread_mfree(old_act);
+err4:
+ pthread_mfree(act);
+err3:
+ pthread_mfree(set);
+err2:
+ pthread_mfree(savedset);
+err1:
+ return -1;
+}
+
+/* should be called by each thread which had initialized signals */
+static void pthread_local_signal_quit(struct xseg *xseg, xport portno)
+{
+ sigset_t *savedset;
+ struct sigaction *old_act;
+
+ savedset = pthread_getspecific(act_key);
+ old_act = pthread_getspecific(mask_key);
+ if (old_act)
+ sigaction(SIGIO, old_act, NULL);
+ if (savedset)
+ pthread_sigmask(SIG_SETMASK, savedset, NULL);
+}
+
+static int pthread_remote_signal_init(void)
+{
+ return 0;
}
-/* can be called by each thread */
-static void pthread_signal_quit(void)
+static void pthread_remote_signal_quit(void)
{
- pthread_once(&once_quit, signal_quit);
+ return;
}
static int pthread_prepare_wait(struct xseg *xseg, uint32_t portno)
{
void * tmp;
pid_t pid;
+ xpool_index r;
struct xseg_port *port = xseg_get_port(xseg, portno);
if (!port)
return -1;
+ struct pthread_signal_desc *psd = xseg_get_signal_desc(xseg, port);
+ if (!psd)
+ return -1;
- tmp = pthread_getspecific(key);
+ tmp = pthread_getspecific(pid_key);
POINTER_TO_INT(pid, tmp);
if (!pid)
return -1;
- xpool_add(&port->waiters, (xpool_index) pid, portno);
+ r = xpool_add(&psd->waiters, (xpool_index) pid, portno);
+ if (r == NoIndex)
+ return -1;
+ pthread_setspecific(xpidx_key, (void *)r);
return 0;
}
void * tmp;
pid_t pid;
xpool_data data;
+ xpool_index xpidx, r;
struct xseg_port *port = xseg_get_port(xseg, portno);
if (!port)
return -1;
+ struct pthread_signal_desc *psd = xseg_get_signal_desc(xseg, port);
+ if (!psd)
+ return -1;
- tmp = pthread_getspecific(key);
+ tmp = pthread_getspecific(pid_key);
POINTER_TO_INT(pid, tmp);
if (!pid)
return -1;
- xpool_remove(&port->waiters, (xpool_index) pid, &data, portno);
+ xpidx = (xpool_index) pthread_getspecific(xpidx_key);
+
+ r = xpool_remove(&psd->waiters, xpidx, &data, portno);
+ if (r == NoIndex)
+ return -1;
+
return 0;
}
int r;
siginfo_t siginfo;
struct timespec ts;
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, SIGIO);
ts.tv_sec = usec_timeout / 1000000;
ts.tv_nsec = 1000 * (usec_timeout - ts.tv_sec * 1000000);
- /* FIXME: Now that pthread signaling is fixed, we could get rid of the timeout
- * and use a NULL timespec linux-specific)
- */
r = sigtimedwait(&set, &siginfo, &ts);
if (r < 0)
return r;
struct xseg_port *port = xseg_get_port(xseg, portno);
if (!port)
return -1;
+ struct pthread_signal_desc *psd = xseg_get_signal_desc(xseg, port);
+ if (!psd)
+ return -1;
- idx = xpool_peek(&port->waiters, &data, portno); //FIXME portno is not the caller but the callee
+ idx = xpool_peek(&psd->waiters, &data, portno); //FIXME portno is not the caller but the callee
if (idx == NoIndex)
- return -1;
+ return 0;
pid_t cue = (pid_t) data;
if (!cue)
"pthread"
};
+int pthread_init_signal_desc(struct xseg *xseg, void *sd)
+{
+ struct pthread_signal_desc *psd = (struct pthread_signal_desc *)sd;
+ xpool_init(&psd->waiters, MAX_WAITERS, &psd->bufs);
+ xpool_clear(&psd->waiters, 1);
+ return 0;
+}
+
+void pthread_quit_signal_desc(struct xseg *xseg, void *sd)
+{
+ struct pthread_signal_desc *psd = (struct pthread_signal_desc *)sd;
+ xpool_clear(&psd->waiters, 1);
+ return;
+}
+
+void * pthread_alloc_data(struct xseg *xseg)
+{
+ struct xobject_h *sd_h = xseg_get_objh(xseg, MAGIC_PTHREAD_SD,
+ sizeof(struct pthread_signal_desc));
+ return sd_h;
+}
+
+void pthread_free_data(struct xseg *xseg, void *data)
+{
+ if (data)
+ xseg_put_objh(xseg, (struct xobject_h *)data);
+}
+
+void *pthread_alloc_signal_desc(struct xseg *xseg, void *data)
+{
+ struct xobject_h *sd_h = (struct xobject_h *) data;
+ if (!sd_h)
+ return NULL;
+ struct pthread_signal_desc *psd = xobj_get_obj(sd_h, X_ALLOC);
+ if (!psd)
+ return NULL;
+ return psd;
+
+}
+
+void pthread_free_signal_desc(struct xseg *xseg, void *data, void *sd)
+{
+ struct xobject_h *sd_h = (struct xobject_h *) data;
+ if (!sd_h)
+ return;
+ if (sd)
+ xobj_put_obj(sd_h, sd);
+ return;
+}
+
+
static struct xseg_peer xseg_peer_pthread = {
/* xseg_peer_operations */
{
- .signal_init = pthread_signal_init,
- .signal_quit = pthread_signal_quit,
+ .init_signal_desc = pthread_init_signal_desc,
+ .quit_signal_desc = pthread_quit_signal_desc,
+ .alloc_data = pthread_alloc_data,
+ .free_data = pthread_free_data,
+ .alloc_signal_desc = pthread_alloc_signal_desc,
+ .free_signal_desc = pthread_free_signal_desc,
+ .local_signal_init = pthread_local_signal_init,
+ .local_signal_quit = pthread_local_signal_quit,
+ .remote_signal_init = pthread_remote_signal_init,
+ .remote_signal_quit = pthread_remote_signal_quit,
.prepare_wait = pthread_prepare_wait,
.cancel_wait = pthread_cancel_wait,
.wait_signal = pthread_wait_signal,