eshi: EVL shim library
The EVL shim library mimics the behavior of the original EVL API based on plain POSIX calls from the native *libc, which does not require the EVL core to be enabled in the host kernel. It is useful when the real-time guarantees delivered by the EVL core are not required for quick prototyping or debugging application code.
This commit is contained in:
parent
ec669471c0
commit
f052b6d31c
2
Makefile
2
Makefile
|
@ -2,7 +2,7 @@
|
|||
|
||||
include config.mk
|
||||
|
||||
TARGETS := include lib tests benchmarks utils
|
||||
TARGETS := include lib benchmarks utils eshi tests
|
||||
|
||||
$(MAIN_GOALS): output-Makefile
|
||||
@for target in $(TARGETS); do \
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
|
||||
include ../config.mk
|
||||
include ../libversion.mk
|
||||
|
||||
SONAME := libeshi.so
|
||||
DTSONAME := $(SONAME).$(EVL_IVERSION)
|
||||
SOLIBNAME := libeshi-$(EVL_SERIAL).so.$(EVL_IVERSION)
|
||||
ARLIBNAME := libeshi-$(EVL_SERIAL).a
|
||||
TARGETS := $(O_DIR)/$(SOLIBNAME) $(O_DIR)/$(ARLIBNAME)
|
||||
|
||||
SRCFILES := $(wildcard *.c)
|
||||
PIC_OBJFILES = $(SRCFILES:%.c=$(O_DIR)/%-pic.o)
|
||||
OBJFILES = $(SRCFILES:%.c=$(O_DIR)/%.o)
|
||||
DEPFILES = $(SRCFILES:%.c=$(O_DIR)/%.d)
|
||||
|
||||
LIB_CPPFLAGS := $(BASE_CPPFLAGS) \
|
||||
-I. \
|
||||
-I../include/eshi \
|
||||
-I../include
|
||||
|
||||
LIB_CFLAGS := $(LIB_CPPFLAGS) $(BASE_CFLAGS)
|
||||
|
||||
override CFLAGS := $(LIB_CFLAGS) $(CFLAGS)
|
||||
|
||||
override LDFLAGS := $(LDFLAGS) -lpthread -lrt
|
||||
|
||||
all: output-Makefile $(TARGETS)
|
||||
|
||||
install: all
|
||||
$(call inst-cmd,$(SOLIBNAME),$(INSTALL) -D $(O_DIR)/$(SOLIBNAME) $(DESTDIR)/$(libdir)/$(SOLIBNAME))
|
||||
@$(LN_S) $(SOLIBNAME) $(DESTDIR)/$(libdir)/$(DTSONAME)
|
||||
@$(LN_S) $(DTSONAME) $(DESTDIR)/$(libdir)/$(SONAME)
|
||||
$(call inst-cmd,$(ARLIBNAME),$(INSTALL) -D $(O_DIR)/$(ARLIBNAME) $(DESTDIR)/$(libdir)/$(ARLIBNAME))
|
||||
|
||||
clean clobber mrproper: output-Makefile
|
||||
$(Q)$(RM) -f $(PIC_OBJFILES) $(OBJFILES) $(TARGETS) $(O_DIR)/$(DTSONAME) $(DEPFILES)
|
||||
|
||||
$(O_DIR)/$(SOLIBNAME): $(PIC_OBJFILES)
|
||||
$(call ld-cmd,$@,$(CC) -shared -Wl$(comma)-soname$(comma)$(DTSONAME) -o $(@) \
|
||||
$(PIC_OBJFILES) $(LDFLAGS) -Wl$(comma)-rpath=$(libdir) -Wl$(comma)--export-dynamic)
|
||||
$(Q)$(LN_S) $(SOLIBNAME) $(O_DIR)/$(DTSONAME)
|
||||
|
||||
$(O_DIR)/$(ARLIBNAME): $(OBJFILES)
|
||||
$(call ar-cmd,$@,$(AR) ru $@ $(OBJFILES))
|
||||
|
||||
$(O_DIR)/%-pic.o: %.c
|
||||
$(call cc-pic-cmd,$@,$(CC) $(CFLAGS) -fPIC -c -o $@ $<)
|
||||
|
||||
$(O_DIR)/%.o: %.c
|
||||
$(call cc-cmd,$@,$(CC) $(CFLAGS) -c -o $@ $<)
|
||||
|
||||
-include $(DEPFILES)
|
|
@ -0,0 +1,47 @@
|
|||
|
||||
== PURPOSE of libeshi
|
||||
|
||||
The EVL shim library mimics the behavior of the original EVL API based
|
||||
on plain POSIX calls from the native *libc, which does not require the
|
||||
EVL core to be enabled in the host kernel. It is useful when the
|
||||
real-time guarantees delivered by the EVL core are not required for
|
||||
quick prototyping or debugging application code.
|
||||
|
||||
== USAGE
|
||||
|
||||
To build against the EVL shim library, you need to update a couple of
|
||||
settings from the Makefile building your application as follows (*):
|
||||
|
||||
CPPFLAGS/CFLAGS:
|
||||
- Replace -I$(prefix)/include by -I$(prefix)/include/eshi
|
||||
|
||||
LDFLAGS:
|
||||
- Replace -levl by -leshi
|
||||
|
||||
For instance:
|
||||
|
||||
$(CC) -o app app.c -I$(prefix)/include/eshi -L$(prefix)/lib -leshi -lpthread -lrt
|
||||
|
||||
(*) $(prefix) is the installation root of libevl (e.g. /usr/evl).
|
||||
|
||||
== LIMITATIONS
|
||||
|
||||
This API supports process-local services only. The resources/objects
|
||||
it creates cannot be shared between processes.
|
||||
|
||||
The following calls are not supported:
|
||||
|
||||
evl_peek_flags
|
||||
evl_peek_sem
|
||||
evl_new_xbuf
|
||||
evl_open_mutex
|
||||
evl_open_event
|
||||
evl_open_flags
|
||||
evl_open_sem
|
||||
|
||||
== VARIATION(S)
|
||||
|
||||
evl_poll: POLLOUT is always set for evl_flags. Unlike with the native
|
||||
libevl API, this condition cannot be monitored for detecting event
|
||||
consumption by the receiver side, i.e. waiting for the value to be
|
||||
cleared upon a successful call to evl_wait*_flags.
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <evl/clock.h>
|
||||
|
||||
int evl_set_clock(int clockfd, const struct timespec *tp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (clockfd) {
|
||||
case EVL_CLOCK_MONOTONIC:
|
||||
case EVL_CLOCK_REALTIME:
|
||||
ret = clock_settime(-clockfd, tp);
|
||||
if (ret)
|
||||
return -errno;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int evl_get_clock_resolution(int clockfd, struct timespec *res)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (clockfd) {
|
||||
case EVL_CLOCK_MONOTONIC:
|
||||
case EVL_CLOCK_REALTIME:
|
||||
ret = clock_getres(-clockfd, res);
|
||||
if (ret)
|
||||
return -errno;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int evl_sleep(int clockfd, const struct timespec *timeout)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (clockfd) {
|
||||
case EVL_CLOCK_MONOTONIC:
|
||||
case EVL_CLOCK_REALTIME:
|
||||
ret = clock_nanosleep(-clockfd, TIMER_ABSTIME, timeout, NULL);
|
||||
if (ret)
|
||||
return -errno;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int evl_udelay(unsigned int usecs)
|
||||
{
|
||||
struct timespec delay;
|
||||
int ret;
|
||||
|
||||
delay.tv_sec = usecs / 1000000U;
|
||||
delay.tv_nsec = (usecs % 1000000U) * 1000U;
|
||||
ret = clock_nanosleep(CLOCK_MONOTONIC, 0, &delay, NULL);
|
||||
if (ret)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <evl/event.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include "internal.h"
|
||||
|
||||
#define __EVENT_ACTIVE_MAGIC 0xef55ef55
|
||||
#define __EVENT_DEAD_MAGIC 0
|
||||
|
||||
int evl_new_event(struct evl_event *evt, int clockfd,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
pthread_condattr_t attr;
|
||||
int ret, fd;
|
||||
|
||||
if (!eshi_is_initialized())
|
||||
return -ENXIO;
|
||||
|
||||
if (clockfd != EVL_CLOCK_MONOTONIC &&
|
||||
clockfd != EVL_CLOCK_REALTIME)
|
||||
return -EINVAL;
|
||||
|
||||
fd = eventfd(0, EFD_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
pthread_condattr_init(&attr);
|
||||
pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE);
|
||||
pthread_condattr_setclock(&attr, -clockfd);
|
||||
ret = pthread_cond_init(&evt->active.cond, &attr);
|
||||
pthread_condattr_destroy(&attr);
|
||||
if (ret) {
|
||||
close(fd);
|
||||
return -ret;
|
||||
}
|
||||
|
||||
evt->active.fd = fd;
|
||||
evt->magic = __EVENT_ACTIVE_MAGIC;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int check_sanity(struct evl_event *evt)
|
||||
{
|
||||
int ret = 0, fd;
|
||||
|
||||
if (evt->magic == __EVENT_UNINIT_MAGIC) {
|
||||
fd = evl_new_event(evt,
|
||||
evt->uninit.clockfd,
|
||||
evt->uninit.name);
|
||||
return fd < 0 ? fd : 0;
|
||||
} else if (evt->magic != __EVENT_ACTIVE_MAGIC)
|
||||
return -EINVAL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int evl_wait_event(struct evl_event *evt, struct evl_mutex *mutex)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (mutex->magic != __MUTEX_ACTIVE_MAGIC)
|
||||
return -EINVAL;
|
||||
|
||||
ret = check_sanity(evt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return -pthread_cond_wait(&evt->active.cond,
|
||||
&mutex->active.mutex);
|
||||
}
|
||||
|
||||
int evl_timedwait_event(struct evl_event *evt,
|
||||
struct evl_mutex *mutex,
|
||||
const struct timespec *timeout)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (mutex->magic != __MUTEX_ACTIVE_MAGIC)
|
||||
return -EINVAL;
|
||||
|
||||
ret = check_sanity(evt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return -pthread_cond_timedwait(&evt->active.cond,
|
||||
&mutex->active.mutex, timeout);
|
||||
}
|
||||
|
||||
int evl_signal_event(struct evl_event *evt)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = check_sanity(evt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return -pthread_cond_signal(&evt->active.cond);
|
||||
}
|
||||
|
||||
int evl_broadcast_event(struct evl_event *evt)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = check_sanity(evt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return -pthread_cond_broadcast(&evt->active.cond);
|
||||
}
|
||||
|
||||
int evl_close_event(struct evl_event *evt)
|
||||
{
|
||||
if (evt->magic == __EVENT_UNINIT_MAGIC)
|
||||
return 0;
|
||||
|
||||
if (evt->magic != __EVENT_ACTIVE_MAGIC)
|
||||
return -EINVAL;
|
||||
|
||||
close(evt->active.fd);
|
||||
evt->magic = __EVENT_DEAD_MAGIC;
|
||||
|
||||
return -pthread_cond_destroy(&evt->active.cond);
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <poll.h>
|
||||
#include <fcntl.h>
|
||||
#include <evl/flags.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include "internal.h"
|
||||
|
||||
#define __FLAGS_ACTIVE_MAGIC 0xb42bb42b
|
||||
#define __FLAGS_DEAD_MAGIC 0
|
||||
|
||||
int evl_new_flags(struct evl_flags *flg, int clockfd, int initval,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (!eshi_is_initialized())
|
||||
return -ENXIO;
|
||||
|
||||
switch (clockfd) {
|
||||
case EVL_CLOCK_MONOTONIC:
|
||||
flg->active.clock = CLOCK_MONOTONIC;
|
||||
break;
|
||||
case EVL_CLOCK_REALTIME:
|
||||
flg->active.clock = CLOCK_REALTIME;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fd = eventfd(initval, EFD_CLOEXEC | EFD_NONBLOCK);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
flg->active.fd = fd;
|
||||
flg->magic = __FLAGS_ACTIVE_MAGIC;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int evl_close_flags(struct evl_flags *flg)
|
||||
{
|
||||
if (flg->magic == __FLAGS_UNINIT_MAGIC)
|
||||
return 0;
|
||||
|
||||
if (flg->magic != __FLAGS_ACTIVE_MAGIC)
|
||||
return -EINVAL;
|
||||
|
||||
close(flg->active.fd);
|
||||
flg->magic = __FLAGS_DEAD_MAGIC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_sanity(struct evl_flags *flg)
|
||||
{
|
||||
int efd;
|
||||
|
||||
if (flg->magic == __FLAGS_UNINIT_MAGIC) {
|
||||
efd = evl_new_flags(flg,
|
||||
flg->uninit.clockfd,
|
||||
flg->uninit.initval,
|
||||
flg->uninit.name);
|
||||
return efd < 0 ? efd : 0;
|
||||
}
|
||||
|
||||
return flg->magic != __FLAGS_ACTIVE_MAGIC ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
static int timedwait_flags(struct evl_flags *flg,
|
||||
const struct timespec *timeout,
|
||||
int *r_bits)
|
||||
{
|
||||
const struct timespec *tp = timeout;
|
||||
struct timespec ts, now;
|
||||
struct pollfd pollfd;
|
||||
uint64_t val;
|
||||
int ret;
|
||||
|
||||
if (!tp || (tp->tv_sec == 0 && tp->tv_nsec == 0))
|
||||
goto poll;
|
||||
|
||||
for (;;) {
|
||||
if (tp) {
|
||||
clock_gettime(flg->active.clock, &now);
|
||||
ts = *timeout;
|
||||
timespec_sub(&ts, &now);
|
||||
if (ts.tv_sec < 0) {
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
}
|
||||
tp = &ts;
|
||||
}
|
||||
poll:
|
||||
pollfd.fd = flg->active.fd;
|
||||
pollfd.events = POLLIN;
|
||||
pollfd.revents = 0;
|
||||
ret = ppoll(&pollfd, 1, tp, NULL);
|
||||
if (ret < 0)
|
||||
return -errno;
|
||||
|
||||
if (ret == 0)
|
||||
break;
|
||||
|
||||
if (!(pollfd.revents & POLLIN))
|
||||
return -EINVAL;
|
||||
|
||||
ret = read(flg->active.fd, &val, sizeof(val));
|
||||
if (ret > 0) {
|
||||
*r_bits = (unsigned int)(val & ~0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (errno != -EAGAIN)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
int evl_timedwait_flags(struct evl_flags *flg,
|
||||
const struct timespec *timeout,
|
||||
int *r_bits)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (timeout == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (timeout->tv_sec < 0 || timeout->tv_nsec >= 1000000000L)
|
||||
return -EINVAL;
|
||||
|
||||
ret = check_sanity(flg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return timedwait_flags(flg, timeout, r_bits);
|
||||
}
|
||||
|
||||
int evl_wait_flags(struct evl_flags *flg, int *r_bits)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = check_sanity(flg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return timedwait_flags(flg, NULL, r_bits);
|
||||
}
|
||||
|
||||
int evl_trywait_flags(struct evl_flags *flg, int *r_bits)
|
||||
{
|
||||
struct timespec zerotime = { .tv_sec = 0, .tv_nsec = 0};
|
||||
int ret;
|
||||
|
||||
ret = check_sanity(flg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = timedwait_flags(flg, &zerotime, r_bits);
|
||||
if (ret == -ETIMEDOUT)
|
||||
return -EAGAIN;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int evl_post_flags(struct evl_flags *flg, int bits)
|
||||
{
|
||||
uint64_t val = (uint64_t)(unsigned int)bits;
|
||||
int ret;
|
||||
|
||||
ret = check_sanity(flg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = write(flg->active.fd, &val, sizeof(val));
|
||||
if (ret != sizeof(val))
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#include "../lib/heap.c"
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <evl/evl.h>
|
||||
#include "internal.h"
|
||||
|
||||
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
static int init_status = -ENXIO;
|
||||
|
||||
static void atfork_handler(void)
|
||||
{
|
||||
init_once = PTHREAD_ONCE_INIT;
|
||||
init_status = 0;
|
||||
}
|
||||
|
||||
static inline int do_init(void)
|
||||
{
|
||||
pthread_atfork(NULL, NULL, atfork_handler);
|
||||
|
||||
return eshi_init_threads();
|
||||
}
|
||||
|
||||
static void do_init_once(void)
|
||||
{
|
||||
init_status = do_init();
|
||||
}
|
||||
|
||||
int evl_init(void)
|
||||
{
|
||||
pthread_once(&init_once, do_init_once);
|
||||
|
||||
return init_status;
|
||||
}
|
||||
|
||||
bool eshi_is_initialized(void)
|
||||
{
|
||||
return init_status == 0;
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#ifndef _EVL_ESHI_INTERNAL_H
|
||||
#define _EVL_ESHI_INTERNAL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static inline
|
||||
void timespec_add(struct timespec *r, const struct timespec *t)
|
||||
{
|
||||
r->tv_sec += t->tv_sec;
|
||||
r->tv_nsec += t->tv_nsec;
|
||||
if (r->tv_nsec >= 1000000000) {
|
||||
r->tv_sec++;
|
||||
r->tv_nsec -= 1000000000;
|
||||
}
|
||||
}
|
||||
|
||||
static inline
|
||||
void timespec_sub(struct timespec *r, const struct timespec *t)
|
||||
{
|
||||
r->tv_sec -= t->tv_sec;
|
||||
r->tv_nsec -= t->tv_nsec;
|
||||
if (r->tv_nsec < 0) {
|
||||
r->tv_sec--;
|
||||
r->tv_nsec += 1000000000;
|
||||
}
|
||||
}
|
||||
|
||||
static inline
|
||||
void timespec_mono_to_real(struct timespec *r, const struct timespec *t)
|
||||
{
|
||||
struct timespec now;
|
||||
|
||||
*r = *t;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
timespec_sub(r, &now);
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
timespec_add(r, &now);
|
||||
}
|
||||
|
||||
pthread_t eshi_find_thread_by_fd(int fd);
|
||||
|
||||
int eshi_init_threads(void);
|
||||
|
||||
bool eshi_is_initialized(void);
|
||||
|
||||
#endif /* _EVL_ESHI_INTERNAL_H */
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <evl/mutex.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include "internal.h"
|
||||
|
||||
#define __MUTEX_ACTIVE_MAGIC 0xab12ab12
|
||||
#define __MUTEX_DEAD_MAGIC 0
|
||||
|
||||
static int create_mutex(struct evl_mutex *mutex, int clockfd, int ceiling)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
int ret, fd, protocol;
|
||||
|
||||
if (!eshi_is_initialized())
|
||||
return -ENXIO;
|
||||
|
||||
switch (clockfd) {
|
||||
case EVL_CLOCK_MONOTONIC:
|
||||
mutex->active.clock = CLOCK_MONOTONIC;
|
||||
break;
|
||||
case EVL_CLOCK_REALTIME:
|
||||
mutex->active.clock = CLOCK_REALTIME;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fd = eventfd(1, EFD_CLOEXEC); /* Set to always readable. */
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
|
||||
protocol = PTHREAD_PRIO_INHERIT;
|
||||
if (ceiling) {
|
||||
protocol = PTHREAD_PRIO_PROTECT;
|
||||
pthread_mutexattr_setprioceiling(&attr, ceiling);
|
||||
}
|
||||
pthread_mutexattr_setprotocol(&attr, protocol);
|
||||
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE);
|
||||
ret = pthread_mutex_init(&mutex->active.mutex, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
if (ret) {
|
||||
close(fd);
|
||||
return -ret;
|
||||
}
|
||||
|
||||
mutex->active.fd = fd;
|
||||
mutex->magic = __MUTEX_ACTIVE_MAGIC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int evl_new_mutex(struct evl_mutex *mutex,
|
||||
int clockfd, const char *fmt, ...)
|
||||
{
|
||||
return create_mutex(mutex, clockfd, 0) ?:
|
||||
mutex->active.fd;
|
||||
}
|
||||
|
||||
int evl_new_mutex_ceiling(struct evl_mutex *mutex,
|
||||
int clockfd, unsigned int ceiling,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
return create_mutex(mutex, clockfd, ceiling) ?:
|
||||
mutex->active.fd;
|
||||
}
|
||||
|
||||
static int check_sanity(struct evl_mutex *mutex)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (mutex->magic == __MUTEX_UNINIT_MAGIC)
|
||||
ret = create_mutex(mutex,
|
||||
mutex->uninit.clockfd,
|
||||
mutex->uninit.ceiling);
|
||||
else if (mutex->magic != __MUTEX_ACTIVE_MAGIC)
|
||||
return -EINVAL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int evl_lock_mutex(struct evl_mutex *mutex)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = check_sanity(mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return -pthread_mutex_lock(&mutex->active.mutex);
|
||||
}
|
||||
|
||||
int evl_timedlock_mutex(struct evl_mutex *mutex,
|
||||
const struct timespec *timeout)
|
||||
{
|
||||
const struct timespec *tp = timeout;
|
||||
struct timespec ts;
|
||||
int ret;
|
||||
|
||||
ret = check_sanity(mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (timeout->tv_sec < 0 || timeout->tv_nsec >= 1000000000L)
|
||||
return -EINVAL;
|
||||
|
||||
if (mutex->active.clock == CLOCK_MONOTONIC) {
|
||||
timespec_mono_to_real(&ts, timeout);
|
||||
tp = &ts;
|
||||
}
|
||||
|
||||
return -pthread_mutex_timedlock(&mutex->active.mutex, tp);
|
||||
}
|
||||
|
||||
int evl_trylock_mutex(struct evl_mutex *mutex)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = check_sanity(mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return -pthread_mutex_trylock(&mutex->active.mutex);
|
||||
}
|
||||
|
||||
int evl_unlock_mutex(struct evl_mutex *mutex)
|
||||
{
|
||||
if (mutex->magic != __MUTEX_ACTIVE_MAGIC)
|
||||
return -EINVAL;
|
||||
|
||||
return -pthread_mutex_unlock(&mutex->active.mutex);
|
||||
}
|
||||
|
||||
int evl_set_mutex_ceiling(struct evl_mutex *mutex,
|
||||
unsigned int ceiling)
|
||||
{
|
||||
int old;
|
||||
|
||||
if (ceiling == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (mutex->magic == __MUTEX_UNINIT_MAGIC) {
|
||||
if (mutex->uninit.ceiling == 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex->uninit.ceiling = ceiling;
|
||||
}
|
||||
|
||||
if (mutex->magic != __MUTEX_ACTIVE_MAGIC)
|
||||
return -EINVAL;
|
||||
|
||||
return -pthread_mutex_setprioceiling(&mutex->active.mutex,
|
||||
ceiling, &old);
|
||||
}
|
||||
|
||||
int evl_get_mutex_ceiling(struct evl_mutex *mutex)
|
||||
{
|
||||
int ret, ceiling;
|
||||
|
||||
if (mutex->magic == __MUTEX_UNINIT_MAGIC) {
|
||||
if (mutex->uninit.ceiling == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return mutex->uninit.ceiling;
|
||||
}
|
||||
|
||||
if (mutex->magic != __MUTEX_ACTIVE_MAGIC)
|
||||
return -EINVAL;
|
||||
|
||||
ret = pthread_mutex_getprioceiling(&mutex->active.mutex, &ceiling);
|
||||
if (ret)
|
||||
return -ret;
|
||||
|
||||
return ceiling;
|
||||
}
|
||||
|
||||
int evl_close_mutex(struct evl_mutex *mutex)
|
||||
{
|
||||
if (mutex->magic == __MUTEX_UNINIT_MAGIC)
|
||||
return 0;
|
||||
|
||||
if (mutex->magic != __MUTEX_ACTIVE_MAGIC)
|
||||
return -EINVAL;
|
||||
|
||||
close(mutex->active.fd);
|
||||
mutex->magic = __MUTEX_DEAD_MAGIC;
|
||||
|
||||
return -pthread_mutex_destroy(&mutex->active.mutex);
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <evl/poll.h>
|
||||
#include "internal.h"
|
||||
|
||||
int evl_new_poll(void)
|
||||
{
|
||||
return epoll_create1(EPOLL_CLOEXEC);
|
||||
}
|
||||
|
||||
int evl_add_pollfd(int efd, int newfd, unsigned int events)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
int ret;
|
||||
|
||||
if (efd == newfd)
|
||||
return -ELOOP;
|
||||
|
||||
ev.events = events;
|
||||
ev.data.fd = newfd;
|
||||
|
||||
ret = epoll_ctl(efd, EPOLL_CTL_ADD, newfd, &ev);
|
||||
if (ret)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int evl_del_pollfd(int efd, int delfd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = epoll_ctl(efd, EPOLL_CTL_DEL, delfd, NULL);
|
||||
if (ret)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int evl_mod_pollfd(int efd, int modfd, unsigned int events)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
int ret;
|
||||
|
||||
ev.events = events;
|
||||
ev.data.fd = modfd;
|
||||
|
||||
ret = epoll_ctl(efd, EPOLL_CTL_MOD, modfd, &ev);
|
||||
if (ret)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use a fast stack-based array for monitoring a small number of
|
||||
* events.
|
||||
*/
|
||||
#define FAST_EVENT_NR 8
|
||||
|
||||
static int do_timedpoll(int efd, struct evl_poll_event *pollset,
|
||||
int nrset, int msecs)
|
||||
{
|
||||
struct epoll_event fast_evs[FAST_EVENT_NR], *evs = fast_evs;
|
||||
int ret, n;
|
||||
|
||||
if (nrset == 0)
|
||||
return 0;
|
||||
|
||||
if (nrset < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (nrset > FAST_EVENT_NR) {
|
||||
evs = malloc(sizeof(*evs) * nrset);
|
||||
if (evs == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = epoll_wait(efd, evs, nrset, msecs);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
ret = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (n = 0; n < nrset; n++) {
|
||||
pollset[n].fd = evs[n].data.fd;
|
||||
pollset[n].events = evs[n].events;
|
||||
}
|
||||
out:
|
||||
if (evs != fast_evs)
|
||||
free(evs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int evl_timedpoll(int efd, struct evl_poll_event *pollset,
|
||||
int nrset, struct timespec *timeout)
|
||||
{
|
||||
int msecs;
|
||||
|
||||
if (timeout->tv_sec < 0 || timeout->tv_nsec >= 1000000000L)
|
||||
return -EINVAL;
|
||||
|
||||
msecs = timeout->tv_sec * 1000 + timeout->tv_nsec / 1000000;
|
||||
|
||||
return do_timedpoll(efd, pollset, nrset, msecs);
|
||||
}
|
||||
|
||||
int evl_poll(int efd, struct evl_poll_event *pollset, int nrset)
|
||||
{
|
||||
return do_timedpoll(efd, pollset, nrset, -1);
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <evl/thread.h>
|
||||
#include <evl/proxy.h>
|
||||
|
||||
static __thread __attribute__ ((tls_model (EVL_TLS_MODEL)))
|
||||
char fmt_buf[1024];
|
||||
|
||||
int evl_vprint_proxy(int proxyfd, const char *fmt, va_list ap)
|
||||
{
|
||||
ssize_t len = vsnprintf(fmt_buf, sizeof(fmt_buf), fmt, ap);
|
||||
|
||||
return write(proxyfd, fmt_buf, len);
|
||||
}
|
||||
|
||||
int evl_print_proxy(int proxyfd, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = evl_vprint_proxy(proxyfd, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
#include <evl/sched.h>
|
||||
#include "internal.h"
|
||||
|
||||
int evl_set_schedattr(int efd, const struct evl_sched_attrs *attrs)
|
||||
{
|
||||
int policy = attrs->sched_policy;
|
||||
struct sched_param param;
|
||||
pthread_t thread;
|
||||
|
||||
if (policy != SCHED_OTHER && policy != SCHED_FIFO)
|
||||
return -EINVAL;
|
||||
|
||||
thread = eshi_find_thread_by_fd(efd);
|
||||
if (!thread)
|
||||
return -EBADF;
|
||||
|
||||
param.sched_priority = attrs->sched_priority;
|
||||
|
||||
return -pthread_setschedparam(thread, policy, ¶m);
|
||||
}
|
||||
|
||||
int evl_get_schedattr(int efd, struct evl_sched_attrs *attrs)
|
||||
{
|
||||
int policy = attrs->sched_policy;
|
||||
struct sched_param param;
|
||||
pthread_t thread;
|
||||
int ret;
|
||||
|
||||
thread = eshi_find_thread_by_fd(efd);
|
||||
if (!thread)
|
||||
return -EBADF;
|
||||
|
||||
ret = pthread_getschedparam(thread, &policy, ¶m);
|
||||
if (ret)
|
||||
return -ret;
|
||||
|
||||
attrs->sched_policy = policy;
|
||||
attrs->sched_priority = param.sched_priority;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
#include <fcntl.h>
|
||||
#include <evl/sem.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include "internal.h"
|
||||
|
||||
#define __SEM_ACTIVE_MAGIC 0xcb13cb13
|
||||
#define __SEM_DEAD_MAGIC 0
|
||||
|
||||
int evl_new_sem(struct evl_sem *sem, int clockfd, int initval,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
int fd;
|
||||
|
||||
/*
|
||||
* evl_init() must have run: exclusively for proper emulation
|
||||
* of libevl.
|
||||
*/
|
||||
if (!eshi_is_initialized())
|
||||
return -ENXIO;
|
||||
|
||||
switch (clockfd) {
|
||||
case EVL_CLOCK_MONOTONIC:
|
||||
sem->active.clock = CLOCK_MONOTONIC;
|
||||
break;
|
||||
case EVL_CLOCK_REALTIME:
|
||||
sem->active.clock = CLOCK_REALTIME;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fd = eventfd(initval, EFD_SEMAPHORE | EFD_NONBLOCK | EFD_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
sem->active.fd = fd;
|
||||
sem->magic = __SEM_ACTIVE_MAGIC;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int evl_close_sem(struct evl_sem *sem)
|
||||
{
|
||||
if (sem->magic == __SEM_UNINIT_MAGIC)
|
||||
return 0;
|
||||
|
||||
if (sem->magic != __SEM_ACTIVE_MAGIC)
|
||||
return -EINVAL;
|
||||
|
||||
close(sem->active.fd);
|
||||
sem->magic = __SEM_DEAD_MAGIC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_sanity(struct evl_sem *sem)
|
||||
{
|
||||
int efd;
|
||||
|
||||
if (sem->magic == __SEM_UNINIT_MAGIC) {
|
||||
efd = evl_new_sem(sem,
|
||||
sem->uninit.clockfd,
|
||||
sem->uninit.initval,
|
||||
sem->uninit.name);
|
||||
return efd < 0 ? efd : 0;
|
||||
}
|
||||
|
||||
return sem->magic != __SEM_ACTIVE_MAGIC ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
static int timedget_sem(struct evl_sem *sem,
|
||||
const struct timespec *timeout)
|
||||
{
|
||||
const struct timespec *tp = timeout;
|
||||
struct timespec ts, now;
|
||||
struct pollfd pollfd;
|
||||
uint64_t val;
|
||||
int ret;
|
||||
|
||||
if (!tp || (tp->tv_sec == 0 && tp->tv_nsec == 0))
|
||||
goto poll;
|
||||
|
||||
for (;;) {
|
||||
if (tp) {
|
||||
clock_gettime(sem->active.clock, &now);
|
||||
ts = *timeout;
|
||||
timespec_sub(&ts, &now);
|
||||
if (ts.tv_sec < 0) {
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
}
|
||||
tp = &ts;
|
||||
}
|
||||
poll:
|
||||
pollfd.fd = sem->active.fd;
|
||||
pollfd.events = POLLIN;
|
||||
pollfd.revents = 0;
|
||||
ret = ppoll(&pollfd, 1, tp, NULL);
|
||||
if (ret < 0)
|
||||
return -errno;
|
||||
|
||||
if (ret == 0)
|
||||
break;
|
||||
|
||||
if (!(pollfd.revents & POLLIN))
|
||||
return -EINVAL;
|
||||
|
||||
ret = read(sem->active.fd, &val, sizeof(val));
|
||||
if (ret > 0)
|
||||
return 0;
|
||||
|
||||
if (errno != -EAGAIN)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
int evl_timedget_sem(struct evl_sem *sem,
|
||||
const struct timespec *timeout)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (timeout == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
ret = check_sanity(sem);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return timedget_sem(sem, timeout);
|
||||
}
|
||||
|
||||
int evl_get_sem(struct evl_sem *sem)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = check_sanity(sem);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return timedget_sem(sem, NULL);
|
||||
}
|
||||
|
||||
int evl_tryget_sem(struct evl_sem *sem)
|
||||
{
|
||||
struct timespec zerotime = { .tv_sec = 0, .tv_nsec = 0 };
|
||||
int ret;
|
||||
|
||||
ret = check_sanity(sem);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = timedget_sem(sem, &zerotime);
|
||||
if (ret == -ETIMEDOUT)
|
||||
return -EAGAIN;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int evl_put_sem(struct evl_sem *sem)
|
||||
{
|
||||
uint64_t val = (uint64_t)1U;
|
||||
int ret;
|
||||
|
||||
ret = check_sanity(sem);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = write(sem->active.fd, &val, sizeof(val));
|
||||
if (ret != sizeof(val))
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* 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_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();
|
||||
node = (struct evl_tsd **)tsearch(&evl_tsd, &fdtree_root, compare_nodes);
|
||||
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);
|
||||
tdelete(&evl_tsd, &fdtree_root, compare_nodes);
|
||||
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;
|
||||
|
||||
node = tsearch(&tsd, &fdtree_root, compare_nodes);
|
||||
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);
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <evl/clock.h>
|
||||
#include <evl/timer.h>
|
||||
|
||||
int evl_new_timer(int clockfd)
|
||||
{
|
||||
clockid_t clk;
|
||||
int fd;
|
||||
|
||||
switch (clockfd) {
|
||||
case EVL_CLOCK_MONOTONIC:
|
||||
clk = CLOCK_MONOTONIC;
|
||||
break;
|
||||
case EVL_CLOCK_REALTIME:
|
||||
clk = CLOCK_REALTIME;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fd = timerfd_create(clk, TFD_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int evl_set_timer(int efd,
|
||||
struct itimerspec *value,
|
||||
struct itimerspec *ovalue)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = timerfd_settime(efd, TFD_TIMER_ABSTIME, value, ovalue);
|
||||
if (ret)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int evl_get_timer(int efd, struct itimerspec *value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = timerfd_gettime(efd, value);
|
||||
if (ret)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -33,3 +33,5 @@ install: all
|
|||
$(Q)$(MKDIR_P) $(DESTDIR)/$(includedir)/uapi
|
||||
$(call inst-cmd,uapi-headers,cd $(O_UAPI) && find -L evl \! \( -name '*~' \) -type f | $(CPIO) -Lpdum --quiet $(DESTDIR)/$(includedir)/uapi)
|
||||
$(call inst-cmd,interface-headers,find evl \! \( -name '*~' \) -type f | $(CPIO) -Lpdum --quiet $(DESTDIR)/$(includedir))
|
||||
$(call inst-cmd,eshi-headers,find eshi \! \( -name '*~' \) -type f | $(CPIO) -Lpdum --quiet $(DESTDIR)/$(includedir))
|
||||
$(call inst-cmd,eshi-headers,$(CP) evl/atomic.h evl/list.h evl/heap.h $(DESTDIR)/$(includedir)/eshi/evl)
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#ifndef _EVL_ESHI_CLOCK_H
|
||||
#define _EVL_ESHI_CLOCK_H
|
||||
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <evl/syscall.h>
|
||||
|
||||
#define EVL_CLOCK_MONOTONIC (-CLOCK_MONOTONIC)
|
||||
#define EVL_CLOCK_REALTIME (-CLOCK_REALTIME)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline
|
||||
int evl_read_clock(int clockfd, struct timespec *tp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (clockfd) {
|
||||
case EVL_CLOCK_MONOTONIC:
|
||||
case EVL_CLOCK_REALTIME:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = clock_gettime(-clockfd, tp);
|
||||
if (ret)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int evl_set_clock(int clockfd, const struct timespec *tp);
|
||||
|
||||
int evl_get_clock_resolution(int clockfd, struct timespec *tp);
|
||||
|
||||
int evl_sleep(int clockfd, const struct timespec *timeout);
|
||||
|
||||
int evl_udelay(unsigned int usecs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVL_ESHI_CLOCK_H */
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#ifndef _EVL_ESHI_EVENT_H
|
||||
#define _EVL_ESHI_EVENT_H
|
||||
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <evl/atomic.h>
|
||||
#include <evl/mutex.h>
|
||||
|
||||
struct evl_event {
|
||||
unsigned int magic;
|
||||
union {
|
||||
struct {
|
||||
int fd;
|
||||
pthread_cond_t cond;
|
||||
} active;
|
||||
struct {
|
||||
const char *name;
|
||||
int clockfd;
|
||||
} uninit;
|
||||
};
|
||||
};
|
||||
|
||||
#define __EVENT_UNINIT_MAGIC 0x01770177
|
||||
|
||||
#define EVL_EVENT_INITIALIZER(__name, __clockfd) { \
|
||||
.magic = __EVENT_UNINIT_MAGIC, \
|
||||
.uninit = { \
|
||||
.name = (__name), \
|
||||
.clockfd = (__clockfd), \
|
||||
} \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int evl_new_event(struct evl_event *evt,
|
||||
int clockfd,
|
||||
const char *fmt, ...);
|
||||
|
||||
int evl_open_event(struct evl_event *evt,
|
||||
const char *fmt, ...);
|
||||
|
||||
int evl_wait_event(struct evl_event *evt,
|
||||
struct evl_mutex *mutex);
|
||||
|
||||
int evl_timedwait_event(struct evl_event *evt,
|
||||
struct evl_mutex *mutex,
|
||||
const struct timespec *timeout);
|
||||
|
||||
int evl_signal_event(struct evl_event *evt);
|
||||
|
||||
int evl_broadcast_event(struct evl_event *evt);
|
||||
|
||||
int evl_close_event(struct evl_event *evt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVL_ESHI_EVENT_H */
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#ifndef _EVL_ESHI_EVL_H
|
||||
#define _EVL_ESHI_EVL_H
|
||||
|
||||
#include <evl/syscall.h>
|
||||
|
||||
#define __EVL__ 5 /* API revision */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int evl_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVL_ESHI_EVL_H */
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#ifndef _EVL_ESHI_FLAGS_H
|
||||
#define _EVL_ESHI_FLAGS_H
|
||||
|
||||
#include <time.h>
|
||||
#include <evl/clock.h>
|
||||
|
||||
struct evl_flags {
|
||||
unsigned int magic;
|
||||
union {
|
||||
struct {
|
||||
clockid_t clock;
|
||||
int fd;
|
||||
} active;
|
||||
struct {
|
||||
const char *name;
|
||||
int clockfd;
|
||||
int initval;
|
||||
} uninit;
|
||||
};
|
||||
};
|
||||
|
||||
#define __FLAGS_UNINIT_MAGIC 0xfebcfebc
|
||||
|
||||
#define EVL_FLAGS_INITIALIZER(__name, __clockfd, __initval) { \
|
||||
.magic = __FLAGS_UNINIT_MAGIC, \
|
||||
.uninit = { \
|
||||
.name = (__name), \
|
||||
.clockfd = (__clockfd), \
|
||||
.initval = (__initval), \
|
||||
} \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int evl_new_flags(struct evl_flags *flg,
|
||||
int clockfd, int initval,
|
||||
const char *fmt, ...);
|
||||
|
||||
int evl_open_flags(struct evl_flags *flg,
|
||||
const char *fmt, ...);
|
||||
|
||||
int evl_close_flags(struct evl_flags *flg);
|
||||
|
||||
int evl_wait_flags(struct evl_flags *flg,
|
||||
int *r_bits);
|
||||
|
||||
int evl_timedwait_flags(struct evl_flags *flg,
|
||||
const struct timespec *timeout,
|
||||
int *r_bits);
|
||||
|
||||
int evl_post_flags(struct evl_flags *flg,
|
||||
int bits);
|
||||
|
||||
int evl_trywait_flags(struct evl_flags *flg,
|
||||
int *r_bits);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVL_FLAGS_H */
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#ifndef _EVL_ESHI_MUTEX_H
|
||||
#define _EVL_ESHI_MUTEX_H
|
||||
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <evl/clock.h>
|
||||
|
||||
struct evl_mutex {
|
||||
unsigned int magic;
|
||||
union {
|
||||
struct {
|
||||
pthread_mutex_t mutex;
|
||||
clockid_t clock;
|
||||
int fd;
|
||||
} active;
|
||||
struct {
|
||||
const char *name;
|
||||
int clockfd;
|
||||
unsigned int ceiling;
|
||||
} uninit;
|
||||
};
|
||||
};
|
||||
|
||||
#define __MUTEX_ACTIVE_MAGIC 0xab12ab12
|
||||
#define __MUTEX_UNINIT_MAGIC 0xfe11fe11
|
||||
|
||||
#define EVL_MUTEX_INITIALIZER(__name, __clockfd) { \
|
||||
.magic = __MUTEX_UNINIT_MAGIC, \
|
||||
.uninit = { \
|
||||
.name = (__name), \
|
||||
.clockfd = (__clockfd), \
|
||||
.ceiling = 0, \
|
||||
} \
|
||||
}
|
||||
|
||||
#define EVL_MUTEX_CEILING_INITIALIZER(__name, __clockfd, __ceiling) { \
|
||||
.magic = __MUTEX_UNINIT_MAGIC, \
|
||||
.uninit = { \
|
||||
.name = (__name), \
|
||||
.clockfd = (__clockfd), \
|
||||
.ceiling = (__ceiling), \
|
||||
} \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int evl_new_mutex(struct evl_mutex *mutex,
|
||||
int clockfd, const char *fmt, ...);
|
||||
|
||||
int evl_new_mutex_ceiling(struct evl_mutex *mutex,
|
||||
int clockfd, unsigned int ceiling,
|
||||
const char *fmt, ...);
|
||||
|
||||
int evl_lock_mutex(struct evl_mutex *mutex);
|
||||
|
||||
int evl_timedlock_mutex(struct evl_mutex *mutex,
|
||||
const struct timespec *timeout);
|
||||
|
||||
int evl_trylock_mutex(struct evl_mutex *mutex);
|
||||
|
||||
int evl_unlock_mutex(struct evl_mutex *mutex);
|
||||
|
||||
int evl_set_mutex_ceiling(struct evl_mutex *mutex,
|
||||
unsigned int ceiling);
|
||||
|
||||
int evl_get_mutex_ceiling(struct evl_mutex *mutex);
|
||||
|
||||
int evl_close_mutex(struct evl_mutex *mutex);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVL_ESHI_MUTEX_H */
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#ifndef _EVL_ESHI_POLL_H
|
||||
#define _EVL_ESHI_POLL_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <sys/poll.h>
|
||||
#include <evl/uapi.h>
|
||||
|
||||
struct evl_poll_event {
|
||||
__u32 fd;
|
||||
__u32 events;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int evl_new_poll(void);
|
||||
|
||||
int evl_add_pollfd(int efd, int newfd,
|
||||
unsigned int events);
|
||||
|
||||
int evl_del_pollfd(int efd, int delfd);
|
||||
|
||||
int evl_mod_pollfd(int efd, int modfd,
|
||||
unsigned int events);
|
||||
|
||||
int evl_timedpoll(int efd, struct evl_poll_event *pollset,
|
||||
int nrset, struct timespec *timeout);
|
||||
|
||||
int evl_poll(int efd, struct evl_poll_event *pollset,
|
||||
int nrset);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVL_ESHI_POLL_H */
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#ifndef _EVL_ESHI_PROXY_H
|
||||
#define _EVL_ESHI_PROXY_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <evl/uapi.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline
|
||||
int evl_new_proxy(int fd, size_t bufsz, size_t granularity,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
return fd;
|
||||
}
|
||||
|
||||
static inline
|
||||
ssize_t evl_send_proxy(int proxyfd, const void *buf, size_t len)
|
||||
{
|
||||
return write(proxyfd, buf, len);
|
||||
}
|
||||
|
||||
int evl_vprint_proxy(int proxyfd,
|
||||
const char *fmt, va_list ap);
|
||||
|
||||
int evl_print_proxy(int proxyfd,
|
||||
const char *fmt, ...);
|
||||
|
||||
#define evl_printf(__fmt, __args...) printf(__fmt, ##__args)
|
||||
|
||||
#define proxy_outfd fileno(stdout)
|
||||
#define proxy_errfd fileno(stderr)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVL_ESHI_PROXY_H */
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#ifndef _EVL_ESHI_SCHED_H
|
||||
#define _EVL_ESHI_SCHED_H
|
||||
|
||||
struct evl_sched_attrs {
|
||||
int sched_policy;
|
||||
int sched_priority;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int evl_set_schedattr(int efd, const struct evl_sched_attrs *attrs);
|
||||
|
||||
int evl_get_schedattr(int efd, struct evl_sched_attrs *attrs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVL_ESHI_SCHED_H */
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#ifndef _EVL_ESHI_SEM_H
|
||||
#define _EVL_ESHI_SEM_H
|
||||
|
||||
#include <time.h>
|
||||
#include <evl/clock.h>
|
||||
|
||||
struct evl_sem {
|
||||
unsigned int magic;
|
||||
union {
|
||||
struct {
|
||||
clockid_t clock;
|
||||
int fd;
|
||||
} active;
|
||||
struct {
|
||||
const char *name;
|
||||
int clockfd;
|
||||
int initval;
|
||||
} uninit;
|
||||
};
|
||||
};
|
||||
|
||||
#define __SEM_UNINIT_MAGIC 0xed15ed15
|
||||
|
||||
#define EVL_SEM_INITIALIZER(__name, __clockfd, __initval) { \
|
||||
.magic = __SEM_UNINIT_MAGIC, \
|
||||
.uninit = { \
|
||||
.name = (__name), \
|
||||
.clockfd = (__clockfd), \
|
||||
.initval = (__initval), \
|
||||
} \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int evl_new_sem(struct evl_sem *sem,
|
||||
int clockfd, int initval,
|
||||
const char *fmt, ...);
|
||||
|
||||
int evl_close_sem(struct evl_sem *sem);
|
||||
|
||||
int evl_get_sem(struct evl_sem *sem);
|
||||
|
||||
int evl_timedget_sem(struct evl_sem *sem,
|
||||
const struct timespec *timeout);
|
||||
|
||||
int evl_put_sem(struct evl_sem *sem);
|
||||
|
||||
int evl_tryget_sem(struct evl_sem *sem);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVL_ESHI_SEM_H */
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#ifndef _EVL_ESHI_SYSCALL_H
|
||||
#define _EVL_ESHI_SYSCALL_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <evl/uapi.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline ssize_t oob_read(int efd, void *buf, size_t count)
|
||||
{
|
||||
return read(efd, buf, count);
|
||||
}
|
||||
|
||||
static inline ssize_t oob_write(int efd, const void *buf, size_t count)
|
||||
{
|
||||
return write(efd, buf, count);
|
||||
}
|
||||
|
||||
#define oob_ioctl(__efd, __request, __args...) \
|
||||
ioctl(__efd, __request, ##__args)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVL_ESHI_SYSCALL_H */
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#ifndef _EVL_ESHI_THREAD_H
|
||||
#define _EVL_ESHI_THREAD_H
|
||||
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <evl/syscall.h>
|
||||
|
||||
/* Enable dlopen() on libeshi.so. */
|
||||
#define EVL_TLS_MODEL "global-dynamic"
|
||||
|
||||
#define EVL_STACK_DEFAULT \
|
||||
({ \
|
||||
int __ret = PTHREAD_STACK_MIN; \
|
||||
if (__ret < 65536) \
|
||||
__ret = 65536; \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline bool evl_is_inband(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline int evl_switch_oob(void)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int evl_switch_inband(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int evl_attach_self(const char *fmt, ...);
|
||||
|
||||
int evl_detach_self(void);
|
||||
|
||||
int evl_get_self(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVL_ESHI_THREAD_H */
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#ifndef _EVL_ESHI_TIMER_H
|
||||
#define _EVL_ESHI_TIMER_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int evl_new_timer(int clockfd);
|
||||
|
||||
int evl_set_timer(int efd,
|
||||
struct itimerspec *value,
|
||||
struct itimerspec *ovalue);
|
||||
|
||||
int evl_get_timer(int efd,
|
||||
struct itimerspec *value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVL_ESHI_TIMER_H */
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
|
||||
*/
|
||||
|
||||
#ifndef _EVL_ESHI_UAPI_H
|
||||
#define _EVL_ESHI_UAPI_H
|
||||
|
||||
#define EVL_CLOCK_MONOTONIC_DEV "monotonic"
|
||||
#define EVL_CLOCK_REALTIME_DEV "realtime"
|
||||
#define EVL_CLOCK_DEV "clock"
|
||||
#define EVL_MONITOR_DEV "monitor"
|
||||
#define EVL_POLL_DEV "poll"
|
||||
#define EVL_PROXY_DEV "proxy"
|
||||
#define EVL_THREAD_DEV "thread"
|
||||
#define EVL_XBUF_DEV "xbuf"
|
||||
|
||||
#endif /* _EVL_ESHI_UAPI_H */
|
|
@ -8,7 +8,8 @@ HELPSRC := helpers.c
|
|||
HELPOBJ := $(O_DIR)/helpers.o
|
||||
TESTSRC := $(filter-out $(HELPSRC),$(ALLSRC))
|
||||
FPSRC := fault.c
|
||||
TARGETS = $(TESTSRC:%.c=$(O_DIR)/%)
|
||||
ESHISRC := $(shell cat eshi.list)
|
||||
TARGETS = $(TESTSRC:%.c=$(O_DIR)/%) $(ESHISRC:%.c=$(O_DIR)/%.eshi)
|
||||
NEEDLIBM = $(FPSRC:%.c=$(O_DIR)/%)
|
||||
DEPFILES = $(ALLSRC:%.c=$(O_DIR)/%.d)
|
||||
|
||||
|
@ -16,22 +17,32 @@ TEST_CPPFLAGS := $(BASE_CPPFLAGS) \
|
|||
-I. \
|
||||
-I../include \
|
||||
-I$(O_DIR)/../include
|
||||
|
||||
TEST_CFLAGS := $(TEST_CPPFLAGS) $(BASE_CFLAGS)
|
||||
override CFLAGS := $(TEST_CFLAGS) $(CFLAGS)
|
||||
|
||||
TEST_LDFLAGS := $(O_DIR)/../lib/libevl.so.$(EVL_IVERSION) -lpthread -lrt
|
||||
override LDFLAGS := $(TEST_LDFLAGS) $(LDFLAGS)
|
||||
$(NEEDLIBM): override LDFLAGS += -lm
|
||||
TEST_LDFLAGS := $(O_DIR)/../lib/libevl.so.$(EVL_IVERSION) -lpthread -lrt $(LDFLAGS)
|
||||
$(NEEDLIBM): override TEST_LDFLAGS += -lm
|
||||
ESHI_LDFLAGS := $(O_DIR)/../eshi/libeshi.so.$(EVL_IVERSION) -lpthread -lrt $(LDFLAGS)
|
||||
|
||||
ESHI_CPPFLAGS := $(BASE_CPPFLAGS) \
|
||||
-D__ESHI__ \
|
||||
-I. \
|
||||
-I../include/eshi \
|
||||
-I../include \
|
||||
-I$(O_DIR)/../include
|
||||
ESHI_CFLAGS := $(ESHI_CPPFLAGS) $(BASE_CFLAGS)
|
||||
|
||||
all: output-Makefile $(TARGETS)
|
||||
|
||||
$(TARGETS): $(HELPOBJ)
|
||||
|
||||
install: all
|
||||
$(Q)for bin in $(TESTSRC:%.c=%); do \
|
||||
$(call inst-cmd,tests,$(Q)for bin in $(TESTSRC:%.c=%); do \
|
||||
$(INSTALL) -D $(O_DIR)/$$bin $(DESTDIR)/$(testdir)/$$bin; \
|
||||
done
|
||||
done)
|
||||
$(call inst-cmd,tests-eshi,$(Q)for bin in $(ESHISRC:%.c=%.eshi); do \
|
||||
$(INSTALL) -D $(O_DIR)/$$bin $(DESTDIR)/$(testdir)/eshi/$$bin; \
|
||||
done)
|
||||
|
||||
clean clobber mrproper:
|
||||
$(Q)$(RM) -f $(TARGETS) $(DEPFILES) $(HELPOBJ)
|
||||
|
@ -40,6 +51,9 @@ $(O_DIR)/%.o: %.c
|
|||
$(call cc-cmd,$@,$(Q)$(CC) -o $(@) $< -c $(CFLAGS))
|
||||
|
||||
$(O_DIR)/%: %.c
|
||||
$(call ccld-cmd,$@,$(Q)$(CC) -o $(@) $< $(HELPOBJ) $(CFLAGS) $(LDFLAGS))
|
||||
$(call ccld-cmd,$@,$(Q)$(CC) -o $(@) $< $(HELPOBJ) $(TEST_CFLAGS) $(TEST_LDFLAGS))
|
||||
|
||||
$(O_DIR)/%.eshi: %.c
|
||||
$(call ccld-cmd,$@,$(Q)$(CC) -o $(@) $< $(HELPOBJ) $(ESHI_CFLAGS) $(ESHI_LDFLAGS))
|
||||
|
||||
-include $(DEPFILES)
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
clock-timer-periodic.c
|
||||
detach-self.c
|
||||
heap-torture.c
|
||||
monitor-event.c
|
||||
monitor-flags.c
|
||||
poll-nested.c
|
||||
poll-sem.c
|
||||
proxy-eventfd.c
|
||||
proxy-pipe.c
|
||||
sem-timedwait.c
|
||||
sem-wait.c
|
|
@ -136,7 +136,11 @@ int main(int argc, char *argv[])
|
|||
|
||||
__Tcall_assert(ret, evl_lock_mutex(&c.lock));
|
||||
c.condition = 3;
|
||||
#ifdef __ESHI__
|
||||
__Tcall_assert(ret, evl_signal_event(&c.event));
|
||||
#else
|
||||
__Tcall_assert(ret, evl_signal_thread(&c.event, receiverfd));
|
||||
#endif
|
||||
__Tcall_assert(ret, evl_unlock_mutex(&c.lock));
|
||||
|
||||
__Texpr_assert(pthread_join(receiver, &status) == 0);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <evl/compiler.h>
|
||||
#include <evl/thread.h>
|
||||
#include <evl/flags.h>
|
||||
#include <evl/sem.h>
|
||||
|
@ -50,12 +51,14 @@ static void *flags_receiver(void *arg)
|
|||
if (!__Texpr(bits == 0x12121212))
|
||||
goto fail;
|
||||
|
||||
#ifndef __ESHI__
|
||||
/* Flag group should be cleared. */
|
||||
if (!__Tcall(ret, evl_peek_flags(&p->flags, &bits)))
|
||||
goto fail;
|
||||
|
||||
if (!__Texpr(bits == 0))
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
/* Trywait should fail with -EAGAIN. */
|
||||
if (!__Fcall(ret, evl_trywait_flags(&p->flags, &bits)))
|
||||
|
@ -82,7 +85,7 @@ fail:
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int tfd, ffd, sfd, ret, bits;
|
||||
int tfd, ffd, sfd, ret, bits __maybe_unused;
|
||||
struct sched_param param;
|
||||
struct test_context c;
|
||||
void *status = NULL;
|
||||
|
@ -111,8 +114,10 @@ int main(int argc, char *argv[])
|
|||
__Tcall_assert(ret, evl_put_sem(&c.start));
|
||||
__Tcall_assert(ret, evl_get_sem(&c.sem));
|
||||
__Tcall_assert(ret, evl_post_flags(&c.flags, 0x12121212));
|
||||
#ifndef __ESHI__
|
||||
__Tcall_assert(ret, evl_peek_flags(&c.flags, &bits));
|
||||
__Texpr_assert(bits == 0x12121212);
|
||||
#endif
|
||||
__Tcall_assert(ret, evl_get_sem(&c.sem));
|
||||
__Tcall_assert(ret, evl_udelay(1000));
|
||||
__Tcall_assert(ret, evl_post_flags(&c.flags, 0x76767676));
|
||||
|
|
Loading…
Reference in New Issue