116 lines
2.0 KiB
C
116 lines
2.0 KiB
C
/*
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <search.h>
|
|
#include <pthread.h>
|
|
#include <evl/evl.h>
|
|
#include <evl/thread.h>
|
|
#include <sys/eventfd.h>
|
|
#include "internal.h"
|
|
|
|
static __thread __attribute__ ((tls_model (EVL_TLS_MODEL)))
|
|
int evl_efd = -1;
|
|
|
|
static __thread __attribute__ ((tls_model (EVL_TLS_MODEL)))
|
|
struct evl_tsd {
|
|
int fd;
|
|
pthread_t thread;
|
|
} evl_tsd;
|
|
|
|
static pthread_mutex_t evl_tsd_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
static pthread_key_t tsd_key;
|
|
|
|
static void *fdtree_root;
|
|
|
|
static int compare_nodes(const void *l, const void *r)
|
|
{
|
|
const struct evl_tsd *lt = l, *rt = r;
|
|
|
|
return lt->fd - rt->fd;
|
|
}
|
|
|
|
int evl_attach_self(const char *fmt, ...)
|
|
{
|
|
struct evl_tsd **node;
|
|
int ret, fd;
|
|
|
|
if (evl_efd != -1)
|
|
return -EBUSY;
|
|
|
|
ret = evl_init();
|
|
if (ret)
|
|
return ret;
|
|
|
|
fd = eventfd(0, EFD_CLOEXEC);
|
|
if (fd < 0)
|
|
return -errno;
|
|
|
|
evl_tsd.fd = fd;
|
|
evl_tsd.thread = pthread_self();
|
|
pthread_mutex_lock(&evl_tsd_lock);
|
|
node = (struct evl_tsd **)tsearch(&evl_tsd, &fdtree_root, compare_nodes);
|
|
pthread_mutex_unlock(&evl_tsd_lock);
|
|
if (!node) {
|
|
close(fd);
|
|
return -ENOMEM;
|
|
}
|
|
if ((*node)->fd != fd)
|
|
return -EBUSY; /* Weird. */
|
|
|
|
pthread_setspecific(tsd_key, &evl_tsd);
|
|
evl_efd = fd;
|
|
|
|
return fd;
|
|
}
|
|
|
|
int evl_detach_self(void)
|
|
{
|
|
if (evl_efd < 0)
|
|
return -EPERM;
|
|
|
|
pthread_setspecific(tsd_key, NULL);
|
|
pthread_mutex_lock(&evl_tsd_lock);
|
|
tdelete(&evl_tsd, &fdtree_root, compare_nodes);
|
|
pthread_mutex_unlock(&evl_tsd_lock);
|
|
close(evl_efd);
|
|
evl_efd = -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int evl_get_self(void)
|
|
{
|
|
return evl_efd;
|
|
}
|
|
|
|
pthread_t eshi_find_thread_by_fd(int fd)
|
|
{
|
|
struct evl_tsd tsd = {
|
|
.fd = fd,
|
|
}, **node;
|
|
|
|
pthread_mutex_lock(&evl_tsd_lock);
|
|
node = tsearch(&tsd, &fdtree_root, compare_nodes);
|
|
pthread_mutex_unlock(&evl_tsd_lock);
|
|
if (!node)
|
|
return (pthread_t)NULL;
|
|
|
|
return (*node)->thread;
|
|
}
|
|
|
|
static void unregister_thread(void *p)
|
|
{
|
|
evl_detach_self();
|
|
}
|
|
|
|
int eshi_init_threads(void)
|
|
{
|
|
return -pthread_key_create(&tsd_key, unregister_thread);
|
|
}
|