All of lore.kernel.org
 help / color / mirror / Atom feed
* evl. event and mutex
@ 2026-02-17 20:28 Giulio Moro
  2026-02-18  8:50 ` Philippe Gerum
  0 siblings, 1 reply; 3+ messages in thread
From: Giulio Moro @ 2026-02-17 20:28 UTC (permalink / raw)
  To: Xenomai

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;
}

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-02-19 13:28 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-17 20:28 evl. event and mutex Giulio Moro
2026-02-18  8:50 ` Philippe Gerum
2026-02-19 13:28   ` Giulio Moro

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.