evl. event and mutex

Giulio Moro <[email protected]>
Newsgroups dev.linux.lists.xenomai
Message-ID <[email protected]>
Hi everyone,
I am trying to use evl_event and evl_mutex so that two threads can signal each other when either needs work from the other, so they each need to call evl_signal_event() and evl_wait_event(). The first thread to call evl_wait_event() seems to correctly drop the mutex, thus unlocking the second thread. When the second thread signals the condition variable (while holding the mutex) and then calls evl_wait_event(), thus implicitly dropping the mutex, the first thread is, unexpectedly, not restarted. I noticed that if a third thread acquires and then releases the lock (without touching the condition variable), then the first thread is restarted. This sounds like a bug?

I am running this on ARM64 (PocketBeagle 2)
evl.0.55 -- #98a8b88 (2025-10-08 22:41:39 +0000) [requires ABI 42]
Linux bela 6.12.49-arm64-ti-evl #4 SMP EVL Sun Nov  2 19:24:32 UTC 2025 aarch64 GNU/Linux

Below is a demo program to reproduce the issue.
If I run the program it prints the following when executed:

main: evl_lock_mutex
main: evl mutex locked
main: evl_signal_event cond
main: evl_wait_event cond, should drop mutex
thread: evl_lock_mutex
thread: evl mutex locked
thread: evl_signal_event cond
thread: evl_wait_event cond, should drop mutex
[HANGS]

If I #define AUXTHREAD (thus enabling the auxiliary thread that periodically locks and unlocks the mutex without touching the condition variable), I get:

main: evl_lock_mutex
main: evl mutex locked
main: evl_signal_event cond
main: evl_wait_event cond, should drop mutex
thread: evl_lock_mutex
thread: evl mutex locked
thread: evl_signal_event cond
thread: evl_wait_event cond, should drop mutex
[wait]
auxthread: evl_lock_mutex()
auxthread: evl locked mutex
auxthread: evl_unlock_mutex()
auxthread: evl mutex unlocked()
main: sleeps
main: evl_lock_mutex
main: evl mutex locked
main: evl_signal_event cond
main: evl_wait_event cond, should drop mutex
[wait]
auxthread: evl_lock_mutex()
auxthread: evl locked mutex
auxthread: evl_unlock_mutex()
auxthread: evl mutex unlocked()
thread: sleeps
thread: evl_lock_mutex
thread: evl mutex locked
thread: evl_signal_event cond
thread: evl_wait_event cond, should drop mutex
[wait]
auxthread: evl_lock_mutex()
auxthread: evl locked mutex
auxthread: evl_unlock_mutex()
main: sleeps
auxthread: evl mutex unlocked()
main: evl_lock_mutex
main: evl mutex locked
main: evl_signal_event cond
main: evl_wait_event cond, should drop mutex

Demo program:

#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

#include <evl/evl.h>

// #define AUXTHREAD

struct evl_event cond;
struct evl_mutex mtx;

void allCores() {
	cpu_set_t set;
	CPU_ZERO(&set);
	for(unsigned int n = 0; n < 64; ++n)
		CPU_SET(n, &set);

	if(sched_setaffinity(gettid(), sizeof(set), &set) == -1) {
		fprintf(stderr, "sched_setaffinity error\n");
		abort();
	}
}

void loop(const char* id) {
	while(1) {
		printf("%s: evl_lock_mutex\n", id);
		int ret = evl_lock_mutex(&mtx);
		if(ret) {
			fprintf(stderr, "%s: evl_signal_event returned %d %s\n", id, ret, strerrorname_np(-ret));
			abort();
		}
		printf("%s: evl mutex locked\n", id);
		printf("%s: evl_signal_event cond\n", id);
		ret = evl_signal_event(&cond);
		if(ret) {
			fprintf(stderr, "thread: evl_signal_event returned %d %s\n", ret, strerrorname_np(-ret));
			abort();
		}
		printf("%s: evl_wait_event cond, should drop mutex\n", id);
		ret = evl_wait_event(&cond, &mtx);
		if(ret) {
			fprintf(stderr, "%s: evl_wait_event returned %d %s\n", id, ret, strerrorname_np(-ret));
			abort();
		}
		evl_unlock_mutex(&mtx);
		printf("%s: sleeps\n", id);
		usleep(10000);
	}
}

void* thread(void* arg) {
	int ret = evl_attach_thread(EVL_CLONE_PRIVATE, "thread:%d:%u", getpid(), pthread_self());
	if(ret <= 0) {
		fprintf(stderr, "evl_attach_thread returned %d %s\n", ret, strerrorname_np(-ret));
		abort();
	}
	allCores();
	loop("thread");
}

void* auxthread(void*) {
	int ret = evl_attach_thread(EVL_CLONE_PRIVATE, "auxthread:%d:%u", getpid(), pthread_self());
	if(ret <= 0) {
		fprintf(stderr, "evl_attach_thread returned %d %s\n", ret, strerrorname_np(-ret));
		abort();
	}
	while(1) {
		usleep(1000000); // long wait
		printf("auxthread: evl_lock_mutex()\n");
		ret = evl_lock_mutex(&mtx);
		if(ret) {
			fprintf(stderr, "auxthread: evl_mutex_lock returned %d %s\n", ret, strerrorname_np(ret));
			abort();
		}
		printf("auxthread: evl locked mutex\n");
		printf("auxthread: evl_unlock_mutex()\n");
		ret = evl_unlock_mutex(&mtx);
		if(ret) {
			fprintf(stderr, "auxthread: evl_mutex_unlock returned %d %s\n", ret, strerrorname_np(ret));
			abort();
		}
		printf("auxthread: evl mutex unlocked()\n");
	}
	return NULL;
}

int main()
{
	int ret = 0;
	ret = evl_init();
	if(ret) {
		fprintf(stderr, "evl_init() returned %d\n", ret);
		abort();
	}
	ret = evl_attach_self("%s:%d:%u", "main", gettid(), rand());
	if(ret < 0) {
		fprintf(stderr, "evl_attach_self() returned %d\n", ret);
		abort();
	}
	allCores();
	ret = evl_create_mutex(&mtx, EVL_CLOCK_MONOTONIC, 0, EVL_MUTEX_NORMAL, "mutex:%d:%p", getpid(), &mtx) < 0;
	ret |= evl_create_event(&cond, EVL_CLOCK_MONOTONIC, EVL_CLONE_PRIVATE, "cond:%d:%p", getpid(), &cond) < 0;
	pthread_t t;
	ret |= pthread_create(&t, 0, thread, 0);
#ifdef AUXTHREAD
	pthread_t at;
	ret |= pthread_create(&at, 0, auxthread, 0);
#endif // AUXTHREAD
	if(ret) {
		fprintf(stderr, "Initialisation error\n");
		return ret;
	}
	loop("main");
	return 0;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.