NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/50094: not all threads woken up when multiple threads waiting with keven on same kqueue
>Number: 50094
>Category: kern
>Synopsis: not all threads woken up when multiple threads waiting with keven on same kqueue
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sun Jul 26 19:10:00 +0000 2015
>Originator: Christof Meerwald
>Release: netbsd-7
>Organization:
>Environment:
NetBSD droid 7.0_RC1 NetBSD 7.0_RC1 (ODROID-C1.201507211940Z) evbarm
>Description:
as reported in http://mail-index.netbsd.org/tech-userlevel/2015/07/26/msg009262.html
I have got multiple threads waiting on a single kqueue and want to
wake up all these threads at some point (before exiting). I believe
the way to do it is to have a dummy socket/pipe added to the kqueue
and close the other end (I have also found
http://thread.gmane.org/gmane.os.netbsd.devel.kernel/28051 which seems
to agree on that approach).
But when I am actually testing this approach, some threads don't seem
to be woken up and keep waiting in the kevent syscall. Source code for
a test case is available from
http://svn.cmeerw.net/src/nginetd/trunk/test/kqtest-wakeup.cc
I have tested on my ODROID-C1 (quad core ARMv7) with netbsd-7 (build
from a few days ago) and seen the problem occur with 3 or more
threads.
This has also been confirmed in netbsd-6 on x86 in http://mail-index.netbsd.org/tech-userlevel/2015/07/26/msg009257.html
>How-To-Repeat:
compile with g++ -pthread and run specifying the number of threads (e.g. 16) as the argument. Test case should consistently terminate after a 1 second sleep.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/event.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <pthread.h>
namespace
{
extern "C" void *worker(void *arg)
{
const int kqid = *static_cast<int *>(arg);
struct kevent events[16];
bool done = false;
while (!done)
{
int rc_kevent = kevent(kqid, NULL, 0,
events, sizeof(events)/sizeof(*events),
NULL);
done = rc_kevent != 0;
}
}
}
int main(int argc, const char * const argv[])
{
const int nr_threads = (argc > 1) ? atoi(argv[1]) : 1;
int kqid(kqueue());
int syncsockets[2];
socketpair(AF_UNIX, SOCK_STREAM, 0, syncsockets);
{
struct kevent const events[] = {
{ syncsockets[1], EVFILT_READ, EV_ADD, 0, 0, 0 },
};
kevent(kqid, events, 1, NULL, 0, NULL);
}
pthread_t *threads = new pthread_t[nr_threads];
for (int i = 0; i < nr_threads; ++i)
{
pthread_create(threads + i, NULL, worker, &kqid);
}
sleep(1);
close(syncsockets[0]);
for (int i = 0; i < nr_threads; ++i)
{
pthread_join(threads[i], NULL);
}
close(syncsockets[1]);
close(kqid);
delete [] threads;
return 0;
}
>Fix:
Home |
Main Index |
Thread Index |
Old Index