sigev_thread.c revision 156383
1156136Sdavidxu/*
2156136Sdavidxu * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
3156136Sdavidxu * All rights reserved.
4156136Sdavidxu *
5156136Sdavidxu * Redistribution and use in source and binary forms, with or without
6156136Sdavidxu * modification, are permitted provided that the following conditions
7156136Sdavidxu * are met:
8156136Sdavidxu * 1. Redistributions of source code must retain the above copyright
9156136Sdavidxu *    notice unmodified, this list of conditions, and the following
10156136Sdavidxu *    disclaimer.
11156136Sdavidxu * 2. Redistributions in binary form must reproduce the above copyright
12156136Sdavidxu *    notice, this list of conditions and the following disclaimer in the
13156136Sdavidxu *    documentation and/or other materials provided with the distribution.
14156136Sdavidxu *
15156136Sdavidxu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16156136Sdavidxu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17156136Sdavidxu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18156136Sdavidxu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19156136Sdavidxu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20156136Sdavidxu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21156136Sdavidxu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22156136Sdavidxu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23156136Sdavidxu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24156136Sdavidxu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25156136Sdavidxu *
26156136Sdavidxu * $FreeBSD: head/lib/librt/sigev_thread.c 156383 2006-03-07 08:28:07Z davidxu $
27156136Sdavidxu *
28156136Sdavidxu */
29156136Sdavidxu
30156136Sdavidxu#include <sys/types.h>
31156136Sdavidxu#include <machine/atomic.h>
32156136Sdavidxu
33156136Sdavidxu#include "namespace.h"
34156136Sdavidxu#include <err.h>
35156267Sdavidxu#include <errno.h>
36156136Sdavidxu#include <ucontext.h>
37156136Sdavidxu#include <sys/thr.h>
38156136Sdavidxu#include <stdio.h>
39156136Sdavidxu#include <stdlib.h>
40156136Sdavidxu#include <string.h>
41156136Sdavidxu#include <signal.h>
42156136Sdavidxu#include <pthread.h>
43156136Sdavidxu#include "un-namespace.h"
44156136Sdavidxu
45156136Sdavidxu#include "sigev_thread.h"
46156136Sdavidxu
47156136SdavidxuLIST_HEAD(sigev_list_head, sigev_node);
48156136Sdavidxu#define HASH_QUEUES		17
49156136Sdavidxu#define	HASH(t, id)		((((id) << 3) + (t)) % HASH_QUEUES)
50156267Sdavidxu
51156136Sdavidxustatic struct sigev_list_head	sigev_hash[HASH_QUEUES];
52156136Sdavidxustatic struct sigev_list_head	sigev_all;
53156383Sdavidxustatic LIST_HEAD(,sigev_thread)	sigev_threads;
54156136Sdavidxustatic int			sigev_generation;
55156136Sdavidxustatic pthread_mutex_t		*sigev_list_mtx;
56156267Sdavidxustatic pthread_once_t		sigev_once = PTHREAD_ONCE_INIT;
57156267Sdavidxustatic pthread_once_t		sigev_once_default = PTHREAD_ONCE_INIT;
58156383Sdavidxustatic struct sigev_thread	*sigev_default_thread;
59156136Sdavidxustatic pthread_attr_t		sigev_default_attr;
60156267Sdavidxustatic int			atfork_registered;
61156136Sdavidxu
62156383Sdavidxustatic void	__sigev_fork_prepare(void);
63156383Sdavidxustatic void	__sigev_fork_parent(void);
64156383Sdavidxustatic void	__sigev_fork_child(void);
65156383Sdavidxustatic struct sigev_thread	*sigev_thread_create(int);
66156383Sdavidxustatic void	*sigev_service_loop(void *);
67156383Sdavidxustatic void	*worker_routine(void *);
68156383Sdavidxustatic void	worker_cleanup(void *);
69156136Sdavidxu
70156136Sdavidxu#pragma weak pthread_create
71156136Sdavidxu
72156383Sdavidxustatic void
73156383Sdavidxuattrcopy(pthread_attr_t *src, pthread_attr_t *dst)
74156136Sdavidxu{
75156383Sdavidxu	struct sched_param sched;
76156383Sdavidxu	void *a;
77156383Sdavidxu	size_t u;
78156383Sdavidxu	int v;
79156136Sdavidxu
80156383Sdavidxu	_pthread_attr_getschedpolicy(src, &v);
81156383Sdavidxu	_pthread_attr_setschedpolicy(dst, v);
82156136Sdavidxu
83156383Sdavidxu	_pthread_attr_getinheritsched(src, &v);
84156383Sdavidxu	_pthread_attr_setinheritsched(dst, v);
85156383Sdavidxu
86156383Sdavidxu	_pthread_attr_getschedparam(src, &sched);
87156383Sdavidxu	_pthread_attr_setschedparam(dst, &sched);
88156383Sdavidxu
89156383Sdavidxu	_pthread_attr_getscope(src, &v);
90156383Sdavidxu	_pthread_attr_setscope(dst, v);
91156383Sdavidxu
92156383Sdavidxu	_pthread_attr_getstacksize(src, &u);
93156383Sdavidxu	_pthread_attr_setstacksize(dst, u);
94156383Sdavidxu
95156383Sdavidxu	_pthread_attr_getstackaddr(src, &a);
96156383Sdavidxu	_pthread_attr_setstackaddr(src, a);
97156383Sdavidxu
98156383Sdavidxu	_pthread_attr_getguardsize(src, &u);
99156383Sdavidxu	_pthread_attr_setguardsize(dst, u);
100156136Sdavidxu}
101156136Sdavidxu
102156136Sdavidxustatic __inline int
103156136Sdavidxuhave_threads(void)
104156136Sdavidxu{
105156267Sdavidxu	return (&pthread_create != NULL);
106156136Sdavidxu}
107156136Sdavidxu
108156136Sdavidxuvoid
109156136Sdavidxu__sigev_thread_init(void)
110156136Sdavidxu{
111156267Sdavidxu	static int inited = 0;
112156383Sdavidxu	pthread_mutexattr_t mattr;
113156136Sdavidxu	int i;
114156136Sdavidxu
115156383Sdavidxu	_pthread_mutexattr_init(&mattr);
116156383Sdavidxu	_pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_NORMAL);
117156136Sdavidxu	sigev_list_mtx = malloc(sizeof(pthread_mutex_t));
118156383Sdavidxu	_pthread_mutex_init(sigev_list_mtx, &mattr);
119156383Sdavidxu	_pthread_mutexattr_destroy(&mattr);
120156383Sdavidxu
121156136Sdavidxu	for (i = 0; i < HASH_QUEUES; ++i)
122156136Sdavidxu		LIST_INIT(&sigev_hash[i]);
123156136Sdavidxu	LIST_INIT(&sigev_all);
124156383Sdavidxu	LIST_INIT(&sigev_threads);
125156267Sdavidxu	sigev_default_thread = NULL;
126156267Sdavidxu	if (atfork_registered == 0) {
127156383Sdavidxu		_pthread_atfork(
128156267Sdavidxu			__sigev_fork_prepare,
129156267Sdavidxu			__sigev_fork_parent,
130156267Sdavidxu			__sigev_fork_child);
131156267Sdavidxu		atfork_registered = 1;
132156267Sdavidxu	}
133156267Sdavidxu	if (!inited) {
134156383Sdavidxu		_pthread_attr_init(&sigev_default_attr);
135156383Sdavidxu		_pthread_attr_setscope(&sigev_default_attr,
136156267Sdavidxu			PTHREAD_SCOPE_SYSTEM);
137156383Sdavidxu		_pthread_attr_setdetachstate(&sigev_default_attr,
138156136Sdavidxu			PTHREAD_CREATE_DETACHED);
139156267Sdavidxu		inited = 1;
140156136Sdavidxu	}
141156383Sdavidxu	sigev_default_thread = sigev_thread_create(0);
142156136Sdavidxu}
143156136Sdavidxu
144156136Sdavidxuint
145156136Sdavidxu__sigev_check_init(void)
146156136Sdavidxu{
147156136Sdavidxu	if (!have_threads())
148156136Sdavidxu		return (-1);
149156136Sdavidxu
150156136Sdavidxu	_pthread_once(&sigev_once, __sigev_thread_init);
151156267Sdavidxu	return (sigev_default_thread != NULL) ? 0 : -1;
152156136Sdavidxu}
153156136Sdavidxu
154156267Sdavidxustatic void
155156136Sdavidxu__sigev_fork_prepare(void)
156156136Sdavidxu{
157156136Sdavidxu}
158156136Sdavidxu
159156267Sdavidxustatic void
160156136Sdavidxu__sigev_fork_parent(void)
161156136Sdavidxu{
162156136Sdavidxu}
163156136Sdavidxu
164156267Sdavidxustatic void
165156136Sdavidxu__sigev_fork_child(void)
166156136Sdavidxu{
167156267Sdavidxu	/*
168156267Sdavidxu	 * This is a hack, the thread libraries really should
169156267Sdavidxu	 * check if the handlers were already registered in
170156267Sdavidxu	 * pthread_atfork().
171156267Sdavidxu	 */
172156267Sdavidxu	atfork_registered = 1;
173156267Sdavidxu	memcpy(&sigev_once, &sigev_once_default, sizeof(sigev_once));
174156136Sdavidxu	__sigev_thread_init();
175156136Sdavidxu}
176156136Sdavidxu
177156383Sdavidxuvoid
178156136Sdavidxu__sigev_list_lock(void)
179156136Sdavidxu{
180156383Sdavidxu	_pthread_mutex_lock(sigev_list_mtx);
181156136Sdavidxu}
182156136Sdavidxu
183156383Sdavidxuvoid
184156136Sdavidxu__sigev_list_unlock(void)
185156136Sdavidxu{
186156383Sdavidxu	_pthread_mutex_unlock(sigev_list_mtx);
187156136Sdavidxu}
188156136Sdavidxu
189156136Sdavidxustruct sigev_node *
190156267Sdavidxu__sigev_alloc(int type, const struct sigevent *evp, struct sigev_node *prev,
191156383Sdavidxu	int usedefault)
192156136Sdavidxu{
193156136Sdavidxu	struct sigev_node *sn;
194156136Sdavidxu
195156136Sdavidxu	sn = calloc(1, sizeof(*sn));
196156136Sdavidxu	if (sn != NULL) {
197156136Sdavidxu		sn->sn_value = evp->sigev_value;
198156383Sdavidxu		sn->sn_func  = evp->sigev_notify_function;
199156383Sdavidxu		sn->sn_gen   = atomic_fetchadd_int(&sigev_generation, 1);
200156383Sdavidxu		sn->sn_type  = type;
201156383Sdavidxu		_pthread_attr_init(&sn->sn_attr);
202156383Sdavidxu		_pthread_attr_setdetachstate(&sn->sn_attr, PTHREAD_CREATE_DETACHED);
203156383Sdavidxu		if (evp->sigev_notify_attributes)
204156383Sdavidxu			attrcopy(evp->sigev_notify_attributes, &sn->sn_attr);
205156383Sdavidxu		if (prev) {
206156383Sdavidxu			__sigev_list_lock();
207156383Sdavidxu			prev->sn_tn->tn_refcount++;
208156383Sdavidxu			__sigev_list_unlock();
209156383Sdavidxu			sn->sn_tn = prev->sn_tn;
210156383Sdavidxu		} else {
211156383Sdavidxu			sn->sn_tn = sigev_thread_create(usedefault);
212156383Sdavidxu			if (sn->sn_tn == NULL) {
213156383Sdavidxu				_pthread_attr_destroy(&sn->sn_attr);
214156383Sdavidxu				free(sn);
215156383Sdavidxu				sn = NULL;
216156383Sdavidxu			}
217156136Sdavidxu		}
218156136Sdavidxu	}
219156136Sdavidxu	return (sn);
220156136Sdavidxu}
221156136Sdavidxu
222156136Sdavidxuvoid
223156136Sdavidxu__sigev_get_sigevent(struct sigev_node *sn, struct sigevent *newevp,
224156136Sdavidxu	sigev_id_t id)
225156136Sdavidxu{
226156136Sdavidxu	/*
227156383Sdavidxu	 * Build a new sigevent, and tell kernel to deliver SIGSERVICE
228156136Sdavidxu	 * signal to the new thread.
229156136Sdavidxu	 */
230156136Sdavidxu	newevp->sigev_notify = SIGEV_THREAD_ID;
231156383Sdavidxu	newevp->sigev_signo  = SIGSERVICE;
232156136Sdavidxu	newevp->sigev_notify_thread_id = (lwpid_t)sn->sn_tn->tn_lwpid;
233156136Sdavidxu	newevp->sigev_value.sival_ptr = (void *)id;
234156136Sdavidxu}
235156136Sdavidxu
236156136Sdavidxuvoid
237156136Sdavidxu__sigev_free(struct sigev_node *sn)
238156136Sdavidxu{
239156383Sdavidxu	_pthread_attr_destroy(&sn->sn_attr);
240156136Sdavidxu	free(sn);
241156136Sdavidxu}
242156136Sdavidxu
243156136Sdavidxustruct sigev_node *
244156136Sdavidxu__sigev_find(int type, sigev_id_t id)
245156136Sdavidxu{
246156136Sdavidxu	struct sigev_node *sn;
247156136Sdavidxu	int chain = HASH(type, id);
248156136Sdavidxu
249156136Sdavidxu	LIST_FOREACH(sn, &sigev_hash[chain], sn_link) {
250156136Sdavidxu		if (sn->sn_type == type && sn->sn_id == id)
251156136Sdavidxu			break;
252156136Sdavidxu	}
253156136Sdavidxu	return (sn);
254156136Sdavidxu}
255156136Sdavidxu
256156136Sdavidxuint
257156136Sdavidxu__sigev_register(struct sigev_node *sn)
258156136Sdavidxu{
259156136Sdavidxu	int chain = HASH(sn->sn_type, sn->sn_id);
260156136Sdavidxu
261156136Sdavidxu	LIST_INSERT_HEAD(&sigev_hash[chain], sn, sn_link);
262156136Sdavidxu	return (0);
263156136Sdavidxu}
264156136Sdavidxu
265156136Sdavidxuint
266156136Sdavidxu__sigev_delete(int type, sigev_id_t id)
267156136Sdavidxu{
268156136Sdavidxu	struct sigev_node *sn;
269156136Sdavidxu
270156136Sdavidxu	sn = __sigev_find(type, id);
271156136Sdavidxu	if (sn != NULL)
272156136Sdavidxu		return (__sigev_delete_node(sn));
273156136Sdavidxu	return (0);
274156136Sdavidxu}
275156136Sdavidxu
276156136Sdavidxuint
277156136Sdavidxu__sigev_delete_node(struct sigev_node *sn)
278156136Sdavidxu{
279156136Sdavidxu	LIST_REMOVE(sn, sn_link);
280156136Sdavidxu
281156267Sdavidxu	if (--sn->sn_tn->tn_refcount == 0)
282156383Sdavidxu		_pthread_kill(sn->sn_tn->tn_thread, SIGSERVICE);
283156136Sdavidxu	if (sn->sn_flags & SNF_WORKING)
284156136Sdavidxu		sn->sn_flags |= SNF_REMOVED;
285156383Sdavidxu	else
286156136Sdavidxu		__sigev_free(sn);
287156136Sdavidxu	return (0);
288156136Sdavidxu}
289156136Sdavidxu
290156383Sdavidxustatic sigev_id_t
291156136Sdavidxusigev_get_id(siginfo_t *si)
292156136Sdavidxu{
293156136Sdavidxu	switch(si->si_code) {
294156136Sdavidxu	case SI_TIMER:
295156136Sdavidxu		return (si->si_timerid);
296156136Sdavidxu	case SI_MESGQ:
297156136Sdavidxu		return (si->si_mqd);
298156136Sdavidxu	case SI_ASYNCIO:
299156136Sdavidxu		return (sigev_id_t)si->si_value.sival_ptr;
300156136Sdavidxu	}
301156136Sdavidxu	return (-1);
302156136Sdavidxu}
303156136Sdavidxu
304156383Sdavidxustatic struct sigev_thread *
305156383Sdavidxusigev_thread_create(int usedefault)
306156136Sdavidxu{
307156383Sdavidxu	struct sigev_thread *tn;
308156136Sdavidxu	sigset_t set;
309156136Sdavidxu	int ret;
310156136Sdavidxu
311156383Sdavidxu	if (usedefault && sigev_default_thread) {
312156383Sdavidxu		__sigev_list_lock();
313156267Sdavidxu		sigev_default_thread->tn_refcount++;
314156383Sdavidxu		__sigev_list_unlock();
315156383Sdavidxu		return (sigev_default_thread);
316156267Sdavidxu	}
317156267Sdavidxu
318156136Sdavidxu	tn = malloc(sizeof(*tn));
319156136Sdavidxu	tn->tn_cur = NULL;
320156267Sdavidxu	tn->tn_lwpid = -1;
321156267Sdavidxu	tn->tn_refcount = 1;
322156383Sdavidxu	_pthread_cond_init(&tn->tn_cv, NULL);
323156383Sdavidxu
324156383Sdavidxu	/* for debug */
325156383Sdavidxu	__sigev_list_lock();
326156383Sdavidxu	LIST_INSERT_HEAD(&sigev_threads, tn, tn_link);
327156383Sdavidxu	__sigev_list_unlock();
328156383Sdavidxu
329156136Sdavidxu	sigemptyset(&set);
330156383Sdavidxu	sigaddset(&set, SIGSERVICE);
331156383Sdavidxu
332156136Sdavidxu	_sigprocmask(SIG_BLOCK, &set, NULL);
333156383Sdavidxu	ret = pthread_create(&tn->tn_thread, &sigev_default_attr,
334156383Sdavidxu		 sigev_service_loop, tn);
335156136Sdavidxu	_sigprocmask(SIG_UNBLOCK, &set, NULL);
336156383Sdavidxu
337156136Sdavidxu	if (ret != 0) {
338156383Sdavidxu		__sigev_list_lock();
339156383Sdavidxu		LIST_REMOVE(tn, tn_link);
340156383Sdavidxu		__sigev_list_unlock();
341156136Sdavidxu		free(tn);
342156136Sdavidxu		tn = NULL;
343156136Sdavidxu	} else {
344156136Sdavidxu		/* wait the thread to get its lwpid */
345156136Sdavidxu
346156136Sdavidxu		__sigev_list_lock();
347156383Sdavidxu		while (tn->tn_lwpid == -1)
348156383Sdavidxu			_pthread_cond_wait(&tn->tn_cv, sigev_list_mtx);
349156136Sdavidxu		__sigev_list_unlock();
350156136Sdavidxu	}
351156383Sdavidxu	return (tn);
352156136Sdavidxu}
353156136Sdavidxu
354156136Sdavidxu/*
355156383Sdavidxu * The thread receives notification from kernel and creates
356156383Sdavidxu * a thread to call user callback function.
357156136Sdavidxu */
358156136Sdavidxustatic void *
359156136Sdavidxusigev_service_loop(void *arg)
360156136Sdavidxu{
361156383Sdavidxu	static int failure;
362156383Sdavidxu
363156136Sdavidxu	siginfo_t si;
364156136Sdavidxu	sigset_t set;
365156383Sdavidxu	struct sigev_thread *tn;
366156136Sdavidxu	struct sigev_node *sn;
367156136Sdavidxu	sigev_id_t id;
368156383Sdavidxu	pthread_t td;
369156267Sdavidxu	int ret;
370156136Sdavidxu
371156136Sdavidxu	tn = arg;
372156136Sdavidxu	thr_self(&tn->tn_lwpid);
373156383Sdavidxu	__sigev_list_lock();
374156383Sdavidxu	_pthread_cond_broadcast(&tn->tn_cv);
375156383Sdavidxu	__sigev_list_unlock();
376156136Sdavidxu
377156136Sdavidxu	/*
378156136Sdavidxu	 * Service thread should not be killed by callback, if user
379156136Sdavidxu	 * attempts to do so, the thread will be restarted.
380156136Sdavidxu	 */
381156136Sdavidxu	sigemptyset(&set);
382156383Sdavidxu	sigaddset(&set, SIGSERVICE);
383156136Sdavidxu	for (;;) {
384156267Sdavidxu		ret = sigwaitinfo(&set, &si);
385156383Sdavidxu
386156383Sdavidxu		__sigev_list_lock();
387156267Sdavidxu		if (tn->tn_refcount == 0) {
388156383Sdavidxu			LIST_REMOVE(tn, tn_link);
389156383Sdavidxu			__sigev_list_unlock();
390156267Sdavidxu			free(tn);
391156267Sdavidxu			break;
392156267Sdavidxu		}
393156383Sdavidxu
394156383Sdavidxu		if (ret == -1) {
395156383Sdavidxu			__sigev_list_unlock();
396156136Sdavidxu			continue;
397156383Sdavidxu		}
398156383Sdavidxu
399156136Sdavidxu		id = sigev_get_id(&si);
400156136Sdavidxu		sn = __sigev_find(si.si_code, id);
401156383Sdavidxu		if (sn == NULL) {
402156192Sdavidxu			__sigev_list_unlock();
403156383Sdavidxu			continue;
404156192Sdavidxu		}
405156383Sdavidxu
406156383Sdavidxu		sn->sn_info = si;
407156383Sdavidxu		if (sn->sn_flags & SNF_SYNC)
408156383Sdavidxu			tn->tn_cur = sn;
409156383Sdavidxu		else
410156383Sdavidxu			tn->tn_cur = NULL;
411156383Sdavidxu		sn->sn_flags |= SNF_WORKING;
412156383Sdavidxu		__sigev_list_unlock();
413156267Sdavidxu
414156383Sdavidxu		ret = pthread_create(&td, &sn->sn_attr, worker_routine, sn);
415156383Sdavidxu		if (ret != 0) {
416156383Sdavidxu			if (failure++ < 5)
417156383Sdavidxu				warnc(ret, "%s:%s failed to create thread.\n",
418156383Sdavidxu					__FILE__, __func__);
419156267Sdavidxu
420156267Sdavidxu			__sigev_list_lock();
421156383Sdavidxu			sn->sn_flags &= ~SNF_WORKING;
422156383Sdavidxu			if (sn->sn_flags & SNF_REMOVED)
423156383Sdavidxu				__sigev_free(sn);
424156267Sdavidxu			__sigev_list_unlock();
425156383Sdavidxu		} else if (tn->tn_cur) {
426156267Sdavidxu			__sigev_list_lock();
427156383Sdavidxu			while (tn->tn_cur)
428156383Sdavidxu				_pthread_cond_wait(&tn->tn_cv, sigev_list_mtx);
429156267Sdavidxu			__sigev_list_unlock();
430156267Sdavidxu		}
431156267Sdavidxu	}
432156383Sdavidxu	return (0);
433156267Sdavidxu}
434156267Sdavidxu
435156267Sdavidxu/*
436156383Sdavidxu * newly created worker thread to call user callback function.
437156267Sdavidxu */
438156267Sdavidxustatic void *
439156383Sdavidxuworker_routine(void *arg)
440156267Sdavidxu{
441156383Sdavidxu	struct sigev_node *sn = arg;
442156267Sdavidxu
443156383Sdavidxu	_pthread_cleanup_push(worker_cleanup, sn);
444156383Sdavidxu	sn->sn_dispatch(sn);
445156383Sdavidxu	_pthread_cleanup_pop(1);
446156267Sdavidxu
447156267Sdavidxu	return (0);
448156267Sdavidxu}
449156267Sdavidxu
450156383Sdavidxu/* clean up a notification after dispatch. */
451156267Sdavidxustatic void
452156267Sdavidxuworker_cleanup(void *arg)
453156267Sdavidxu{
454156383Sdavidxu	struct sigev_node *sn = arg;
455156267Sdavidxu
456156267Sdavidxu	__sigev_list_lock();
457156383Sdavidxu	if (sn->sn_flags & SNF_SYNC) {
458156383Sdavidxu		sn->sn_tn->tn_cur = NULL;
459156383Sdavidxu		_pthread_cond_broadcast(&sn->sn_tn->tn_cv);
460156383Sdavidxu	}
461156267Sdavidxu	if (sn->sn_flags & SNF_REMOVED)
462156267Sdavidxu		__sigev_free(sn);
463156383Sdavidxu	else
464156383Sdavidxu		sn->sn_flags &= ~SNF_WORKING;
465156267Sdavidxu	__sigev_list_unlock();
466156267Sdavidxu}
467