xref: /dflybsd-src/lib/libthread_xu/thread/thr_sig.c (revision 940be950819fa932cd401a01f1182bf686a2e61e)
171b3fa15SDavid Xu /*
2d3b15642Szrj  * Copyright (c) 2005, David Xu <davidxu@freebsd.org>
371b3fa15SDavid Xu  * All rights reserved.
471b3fa15SDavid Xu  *
571b3fa15SDavid Xu  * Redistribution and use in source and binary forms, with or without
671b3fa15SDavid Xu  * modification, are permitted provided that the following conditions
771b3fa15SDavid Xu  * are met:
871b3fa15SDavid Xu  * 1. Redistributions of source code must retain the above copyright
971b3fa15SDavid Xu  *    notice, this list of conditions and the following disclaimer.
1071b3fa15SDavid Xu  * 2. Redistributions in binary form must reproduce the above copyright
1171b3fa15SDavid Xu  *    notice, this list of conditions and the following disclaimer in the
1271b3fa15SDavid Xu  *    documentation and/or other materials provided with the distribution.
1371b3fa15SDavid Xu  *
14d3b15642Szrj  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15d3b15642Szrj  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16d3b15642Szrj  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17d3b15642Szrj  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18d3b15642Szrj  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19d3b15642Szrj  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20d3b15642Szrj  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21d3b15642Szrj  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22d3b15642Szrj  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23d3b15642Szrj  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2471b3fa15SDavid Xu  *
2571b3fa15SDavid Xu  */
2671b3fa15SDavid Xu 
27fc71f871SDavid Xu #include "namespace.h"
2871b3fa15SDavid Xu #include <sys/signalvar.h>
299e2ee207SJoerg Sonnenberger #include <machine/tls.h>
3071b3fa15SDavid Xu #include <signal.h>
3171b3fa15SDavid Xu #include <errno.h>
3271b3fa15SDavid Xu #include <string.h>
3371b3fa15SDavid Xu #include <pthread.h>
34fc71f871SDavid Xu #include "un-namespace.h"
3571b3fa15SDavid Xu 
3671b3fa15SDavid Xu #include "thr_private.h"
3771b3fa15SDavid Xu 
38fcaa7a3aSMatthew Dillon #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2)
39fcaa7a3aSMatthew Dillon #include <sys/file.h>
40fcaa7a3aSMatthew Dillon #include <stdio.h>
41fcaa7a3aSMatthew Dillon #endif
42fcaa7a3aSMatthew Dillon 
4371b3fa15SDavid Xu /* #define DEBUG_SIGNAL */
4471b3fa15SDavid Xu #ifdef DEBUG_SIGNAL
4571b3fa15SDavid Xu #define DBG_MSG		stdout_debug
4671b3fa15SDavid Xu #else
4771b3fa15SDavid Xu #define DBG_MSG(x...)
4871b3fa15SDavid Xu #endif
4971b3fa15SDavid Xu 
50fc71f871SDavid Xu int	__sigwait(const sigset_t *set, int *sig);
51fc71f871SDavid Xu int	__sigwaitinfo(const sigset_t *set, siginfo_t *info);
52fc71f871SDavid Xu int	__sigtimedwait(const sigset_t *set, siginfo_t *info,
53fc71f871SDavid Xu 		const struct timespec * timeout);
54fc71f871SDavid Xu 
55fcaa7a3aSMatthew Dillon #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2)
56fcaa7a3aSMatthew Dillon static void _thr_debug_sig(int signo);
57fcaa7a3aSMatthew Dillon #endif
58fcaa7a3aSMatthew Dillon 
5971b3fa15SDavid Xu static void
sigcancel_handler(int sig __unused,siginfo_t * info __unused,ucontext_t * ucp __unused)60fc71f871SDavid Xu sigcancel_handler(int sig __unused, siginfo_t *info __unused,
61fc71f871SDavid Xu 	ucontext_t *ucp __unused)
6271b3fa15SDavid Xu {
63*940be950Szrj 	pthread_t curthread = tls_get_curthread();
6471b3fa15SDavid Xu 
6571b3fa15SDavid Xu 	if (curthread->cancelflags & THR_CANCEL_AT_POINT)
66fc71f871SDavid Xu 		_pthread_testcancel();
67fd4288bdSDavid Xu 	_thr_ast(curthread);
68fd4288bdSDavid Xu }
69fd4288bdSDavid Xu 
70fd4288bdSDavid Xu void
_thr_ast(pthread_t curthread)71*940be950Szrj _thr_ast(pthread_t curthread)
72fd4288bdSDavid Xu {
73fd4288bdSDavid Xu 	if (!THR_IN_CRITICAL(curthread)) {
74fd4288bdSDavid Xu 		if (__predict_false((curthread->flags &
75fd4288bdSDavid Xu 		    (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED))
76fd4288bdSDavid Xu 			== THR_FLAGS_NEED_SUSPEND))
7771b3fa15SDavid Xu 			_thr_suspend_check(curthread);
7871b3fa15SDavid Xu 	}
7971b3fa15SDavid Xu }
8071b3fa15SDavid Xu 
8171b3fa15SDavid Xu void
_thr_suspend_check(pthread_t curthread)82*940be950Szrj _thr_suspend_check(pthread_t curthread)
8371b3fa15SDavid Xu {
84fd4288bdSDavid Xu 	umtx_t cycle;
8571b3fa15SDavid Xu 
86fd4288bdSDavid Xu 	/*
87fd4288bdSDavid Xu 	 * Blocks SIGCANCEL which other threads must send.
88fd4288bdSDavid Xu 	 */
8971b3fa15SDavid Xu 	_thr_signal_block(curthread);
90fd4288bdSDavid Xu 
91fd4288bdSDavid Xu 	/*
92fd4288bdSDavid Xu 	 * Increase critical_count, here we don't use THR_LOCK/UNLOCK
93fd4288bdSDavid Xu 	 * because we are leaf code, we don't want to recursively call
94fd4288bdSDavid Xu 	 * ourself.
95fd4288bdSDavid Xu 	 */
96fd4288bdSDavid Xu 	curthread->critical_count++;
97fd4288bdSDavid Xu 	THR_UMTX_LOCK(curthread, &(curthread)->lock);
98fd4288bdSDavid Xu 	while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND |
99fd4288bdSDavid Xu 		THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) {
100fd4288bdSDavid Xu 		curthread->cycle++;
10171b3fa15SDavid Xu 		cycle = curthread->cycle;
102fd4288bdSDavid Xu 
103fd4288bdSDavid Xu 		/* Wake the thread suspending us. */
10498247283SMatthew Dillon 		_thr_umtx_wake(&curthread->cycle, 0);
105fd4288bdSDavid Xu 
106fd4288bdSDavid Xu 		/*
107fd4288bdSDavid Xu 		 * if we are from pthread_exit, we don't want to
108fd4288bdSDavid Xu 		 * suspend, just go and die.
109fd4288bdSDavid Xu 		 */
110fd4288bdSDavid Xu 		if (curthread->state == PS_DEAD)
111fd4288bdSDavid Xu 			break;
112fd4288bdSDavid Xu 		curthread->flags |= THR_FLAGS_SUSPENDED;
113fd4288bdSDavid Xu 		THR_UMTX_UNLOCK(curthread, &(curthread)->lock);
1149219c44cSDavid Xu 		_thr_umtx_wait(&curthread->cycle, cycle, NULL, 0);
115fd4288bdSDavid Xu 		THR_UMTX_LOCK(curthread, &(curthread)->lock);
11671b3fa15SDavid Xu 		curthread->flags &= ~THR_FLAGS_SUSPENDED;
11771b3fa15SDavid Xu 	}
118fd4288bdSDavid Xu 	THR_UMTX_UNLOCK(curthread, &(curthread)->lock);
119fd4288bdSDavid Xu 	curthread->critical_count--;
120fd4288bdSDavid Xu 
12171b3fa15SDavid Xu 	_thr_signal_unblock(curthread);
12271b3fa15SDavid Xu }
12371b3fa15SDavid Xu 
12471b3fa15SDavid Xu void
_thr_signal_init(void)12571b3fa15SDavid Xu _thr_signal_init(void)
12671b3fa15SDavid Xu {
12771b3fa15SDavid Xu 	struct sigaction act;
12871b3fa15SDavid Xu 
12971b3fa15SDavid Xu 	/* Install cancel handler. */
13071b3fa15SDavid Xu 	SIGEMPTYSET(act.sa_mask);
13171b3fa15SDavid Xu 	act.sa_flags = SA_SIGINFO | SA_RESTART;
13271b3fa15SDavid Xu 	act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler;
13371b3fa15SDavid Xu 	__sys_sigaction(SIGCANCEL, &act, NULL);
134fcaa7a3aSMatthew Dillon 
135fcaa7a3aSMatthew Dillon #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2)
136fcaa7a3aSMatthew Dillon 	/*
137fcaa7a3aSMatthew Dillon 	 * If enabled, rwlock, mutex, and condition variable operations
138fcaa7a3aSMatthew Dillon 	 * are recorded in a text buffer and signal 63 dumps the buffer
139fcaa7a3aSMatthew Dillon 	 * to /tmp/cond${pid}.log.
140fcaa7a3aSMatthew Dillon 	 */
141fcaa7a3aSMatthew Dillon 	act.sa_flags = SA_RESTART;
142fcaa7a3aSMatthew Dillon 	act.sa_handler = _thr_debug_sig;
143fcaa7a3aSMatthew Dillon 	__sys_sigaction(63, &act, NULL);
144fcaa7a3aSMatthew Dillon #endif
14571b3fa15SDavid Xu }
14671b3fa15SDavid Xu 
14771b3fa15SDavid Xu void
_thr_signal_deinit(void)14871b3fa15SDavid Xu _thr_signal_deinit(void)
14971b3fa15SDavid Xu {
15071b3fa15SDavid Xu }
15171b3fa15SDavid Xu 
15271b3fa15SDavid Xu int
_sigaction(int sig,const struct sigaction * act,struct sigaction * oact)15371b3fa15SDavid Xu _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
15471b3fa15SDavid Xu {
15571b3fa15SDavid Xu 	/* Check if the signal number is out of range: */
15671b3fa15SDavid Xu 	if (sig < 1 || sig > _SIG_MAXSIG || sig == SIGCANCEL) {
15771b3fa15SDavid Xu 		/* Return an invalid argument: */
15871b3fa15SDavid Xu 		errno = EINVAL;
15971b3fa15SDavid Xu 		return (-1);
16071b3fa15SDavid Xu 	}
16171b3fa15SDavid Xu 
16271b3fa15SDavid Xu 	return __sys_sigaction(sig, act, oact);
16371b3fa15SDavid Xu }
16471b3fa15SDavid Xu 
1655a1048c8SDavid Xu __strong_reference(_sigaction, sigaction);
16671b3fa15SDavid Xu 
16771b3fa15SDavid Xu int
_sigprocmask(int how,const sigset_t * set,sigset_t * oset)16871b3fa15SDavid Xu _sigprocmask(int how, const sigset_t *set, sigset_t *oset)
16971b3fa15SDavid Xu {
17071b3fa15SDavid Xu 	const sigset_t *p = set;
17171b3fa15SDavid Xu 	sigset_t newset;
17271b3fa15SDavid Xu 
17371b3fa15SDavid Xu 	if (how != SIG_UNBLOCK) {
17471b3fa15SDavid Xu 		if (set != NULL) {
17571b3fa15SDavid Xu 			newset = *set;
17671b3fa15SDavid Xu 			SIGDELSET(newset, SIGCANCEL);
17771b3fa15SDavid Xu 			p = &newset;
17871b3fa15SDavid Xu 		}
17971b3fa15SDavid Xu 	}
18071b3fa15SDavid Xu 	return (__sys_sigprocmask(how, p, oset));
18171b3fa15SDavid Xu }
18271b3fa15SDavid Xu 
1835a1048c8SDavid Xu __strong_reference(_sigprocmask, sigprocmask);
18471b3fa15SDavid Xu 
18571b3fa15SDavid Xu int
_pthread_sigmask(int how,const sigset_t * set,sigset_t * oset)18671b3fa15SDavid Xu _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
18771b3fa15SDavid Xu {
18871b3fa15SDavid Xu 	if (_sigprocmask(how, set, oset))
18971b3fa15SDavid Xu 		return (errno);
19071b3fa15SDavid Xu 	return (0);
19171b3fa15SDavid Xu }
19271b3fa15SDavid Xu 
1935a1048c8SDavid Xu __strong_reference(_pthread_sigmask, pthread_sigmask);
19471b3fa15SDavid Xu 
19571b3fa15SDavid Xu int
_sigsuspend(const sigset_t * set)19671b3fa15SDavid Xu _sigsuspend(const sigset_t * set)
19771b3fa15SDavid Xu {
198*940be950Szrj 	pthread_t curthread = tls_get_curthread();
19971b3fa15SDavid Xu 	sigset_t newset;
20071b3fa15SDavid Xu 	const sigset_t *pset;
20171b3fa15SDavid Xu 	int oldcancel;
20271b3fa15SDavid Xu 	int ret;
20371b3fa15SDavid Xu 
20471b3fa15SDavid Xu 	if (SIGISMEMBER(*set, SIGCANCEL)) {
20571b3fa15SDavid Xu 		newset = *set;
20671b3fa15SDavid Xu 		SIGDELSET(newset, SIGCANCEL);
20771b3fa15SDavid Xu 		pset = &newset;
20871b3fa15SDavid Xu 	} else
20971b3fa15SDavid Xu 		pset = set;
21071b3fa15SDavid Xu 
21171b3fa15SDavid Xu 	oldcancel = _thr_cancel_enter(curthread);
21271b3fa15SDavid Xu 	ret = __sys_sigsuspend(pset);
21371b3fa15SDavid Xu 	_thr_cancel_leave(curthread, oldcancel);
21471b3fa15SDavid Xu 
21571b3fa15SDavid Xu 	return (ret);
21671b3fa15SDavid Xu }
21771b3fa15SDavid Xu 
2185a1048c8SDavid Xu __strong_reference(_sigsuspend, sigsuspend);
21971b3fa15SDavid Xu 
22071b3fa15SDavid Xu int
__sigtimedwait(const sigset_t * set,siginfo_t * info,const struct timespec * timeout)22171b3fa15SDavid Xu __sigtimedwait(const sigset_t *set, siginfo_t *info,
22271b3fa15SDavid Xu 	const struct timespec * timeout)
22371b3fa15SDavid Xu {
224*940be950Szrj 	pthread_t curthread = tls_get_curthread();
22571b3fa15SDavid Xu 	sigset_t newset;
22671b3fa15SDavid Xu 	const sigset_t *pset;
22771b3fa15SDavid Xu 	int oldcancel;
22871b3fa15SDavid Xu 	int ret;
22971b3fa15SDavid Xu 
23071b3fa15SDavid Xu 	if (SIGISMEMBER(*set, SIGCANCEL)) {
23171b3fa15SDavid Xu 		newset = *set;
23271b3fa15SDavid Xu 		SIGDELSET(newset, SIGCANCEL);
23371b3fa15SDavid Xu 		pset = &newset;
23471b3fa15SDavid Xu 	} else
23571b3fa15SDavid Xu 		pset = set;
23671b3fa15SDavid Xu 	oldcancel = _thr_cancel_enter(curthread);
23771b3fa15SDavid Xu 	ret = __sys_sigtimedwait(pset, info, timeout);
23871b3fa15SDavid Xu 	_thr_cancel_leave(curthread, oldcancel);
23971b3fa15SDavid Xu 	return (ret);
24071b3fa15SDavid Xu }
24171b3fa15SDavid Xu 
2425a1048c8SDavid Xu __strong_reference(__sigtimedwait, sigtimedwait);
2435a1048c8SDavid Xu 
24471b3fa15SDavid Xu int
__sigwaitinfo(const sigset_t * set,siginfo_t * info)24571b3fa15SDavid Xu __sigwaitinfo(const sigset_t *set, siginfo_t *info)
24671b3fa15SDavid Xu {
247*940be950Szrj 	pthread_t curthread = tls_get_curthread();
24871b3fa15SDavid Xu 	sigset_t newset;
24971b3fa15SDavid Xu 	const sigset_t *pset;
25071b3fa15SDavid Xu 	int oldcancel;
25171b3fa15SDavid Xu 	int ret;
25271b3fa15SDavid Xu 
25371b3fa15SDavid Xu 	if (SIGISMEMBER(*set, SIGCANCEL)) {
25471b3fa15SDavid Xu 		newset = *set;
25571b3fa15SDavid Xu 		SIGDELSET(newset, SIGCANCEL);
25671b3fa15SDavid Xu 		pset = &newset;
25771b3fa15SDavid Xu 	} else
25871b3fa15SDavid Xu 		pset = set;
25971b3fa15SDavid Xu 
26071b3fa15SDavid Xu 	oldcancel = _thr_cancel_enter(curthread);
26171b3fa15SDavid Xu 	ret = __sys_sigwaitinfo(pset, info);
26271b3fa15SDavid Xu 	_thr_cancel_leave(curthread, oldcancel);
26371b3fa15SDavid Xu 	return (ret);
26471b3fa15SDavid Xu }
26571b3fa15SDavid Xu 
2665a1048c8SDavid Xu __strong_reference(__sigwaitinfo, sigwaitinfo);
2675a1048c8SDavid Xu 
26871b3fa15SDavid Xu int
__sigwait(const sigset_t * set,int * sig)26971b3fa15SDavid Xu __sigwait(const sigset_t *set, int *sig)
27071b3fa15SDavid Xu {
2717aca7007SDavid Xu 	int s;
27271b3fa15SDavid Xu 
2737aca7007SDavid Xu 	s = __sigwaitinfo(set, NULL);
2747aca7007SDavid Xu 	if (s > 0) {
2757aca7007SDavid Xu 		*sig = s;
2767aca7007SDavid Xu 		return (0);
27771b3fa15SDavid Xu 	}
2787aca7007SDavid Xu 	return (errno);
2797aca7007SDavid Xu }
2805a1048c8SDavid Xu 
2815a1048c8SDavid Xu __strong_reference(__sigwait, sigwait);
282fcaa7a3aSMatthew Dillon 
283fcaa7a3aSMatthew Dillon #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2)
284fcaa7a3aSMatthew Dillon 
285fcaa7a3aSMatthew Dillon #define LOGBUF_SIZE	(4 * 1024 * 1024)
286fcaa7a3aSMatthew Dillon #define LOGBUF_MASK	(LOGBUF_SIZE - 1)
287fcaa7a3aSMatthew Dillon 
288fcaa7a3aSMatthew Dillon char LogBuf[LOGBUF_SIZE];
289fcaa7a3aSMatthew Dillon unsigned long LogWIndex;
290fcaa7a3aSMatthew Dillon 
291fcaa7a3aSMatthew Dillon void
_thr_log(const char * buf,size_t bytes)292fcaa7a3aSMatthew Dillon _thr_log(const char *buf, size_t bytes)
293fcaa7a3aSMatthew Dillon {
294*940be950Szrj 	pthread_t curthread;
295fcaa7a3aSMatthew Dillon 	unsigned long i;
296fcaa7a3aSMatthew Dillon 	char prefix[32];
297fcaa7a3aSMatthew Dillon 	size_t plen;
298fcaa7a3aSMatthew Dillon 
299fcaa7a3aSMatthew Dillon 	curthread = tls_get_curthread();
300fcaa7a3aSMatthew Dillon 	if (curthread) {
301fcaa7a3aSMatthew Dillon 		plen = snprintf(prefix, sizeof(prefix), "%d.%d: ",
302fcaa7a3aSMatthew Dillon 				(int)__sys_getpid(),
303fcaa7a3aSMatthew Dillon 				curthread->tid);
304fcaa7a3aSMatthew Dillon 	} else {
305fcaa7a3aSMatthew Dillon 		plen = snprintf(prefix, sizeof(prefix), "unknown: ");
306fcaa7a3aSMatthew Dillon 	}
307fcaa7a3aSMatthew Dillon 
308fcaa7a3aSMatthew Dillon 	if (bytes == 0)
309fcaa7a3aSMatthew Dillon 		bytes = strlen(buf);
310fcaa7a3aSMatthew Dillon 	i = atomic_fetchadd_long(&LogWIndex, plen + bytes);
311fcaa7a3aSMatthew Dillon 	i = i & LOGBUF_MASK;
312fcaa7a3aSMatthew Dillon 	if (plen <= (size_t)(LOGBUF_SIZE - i)) {
313fcaa7a3aSMatthew Dillon 		bcopy(prefix, LogBuf + i, plen);
314fcaa7a3aSMatthew Dillon 	} else {
315fcaa7a3aSMatthew Dillon 		bcopy(prefix, LogBuf + i, LOGBUF_SIZE - i);
316fcaa7a3aSMatthew Dillon 		plen -= LOGBUF_SIZE - i;
317fcaa7a3aSMatthew Dillon 		bcopy(prefix, LogBuf, plen);
318fcaa7a3aSMatthew Dillon 	}
319fcaa7a3aSMatthew Dillon 
320fcaa7a3aSMatthew Dillon 	i += plen;
321fcaa7a3aSMatthew Dillon 	i = i & LOGBUF_MASK;
322fcaa7a3aSMatthew Dillon 	if (bytes <= (size_t)(LOGBUF_SIZE - i)) {
323fcaa7a3aSMatthew Dillon 		bcopy(buf, LogBuf + i, bytes);
324fcaa7a3aSMatthew Dillon 	} else {
325fcaa7a3aSMatthew Dillon 		bcopy(buf, LogBuf + i, LOGBUF_SIZE - i);
326fcaa7a3aSMatthew Dillon 		bytes -= LOGBUF_SIZE - i;
327fcaa7a3aSMatthew Dillon 		bcopy(buf, LogBuf, bytes);
328fcaa7a3aSMatthew Dillon 	}
329fcaa7a3aSMatthew Dillon }
330fcaa7a3aSMatthew Dillon 
331fcaa7a3aSMatthew Dillon static void
_thr_debug_sig(int signo __unused)332fcaa7a3aSMatthew Dillon _thr_debug_sig(int signo __unused)
333fcaa7a3aSMatthew Dillon {
334fcaa7a3aSMatthew Dillon         char buf[256];
335fcaa7a3aSMatthew Dillon 	int fd;
336fcaa7a3aSMatthew Dillon 	unsigned long i;
337fcaa7a3aSMatthew Dillon 
338fcaa7a3aSMatthew Dillon 	snprintf(buf, sizeof(buf), "/tmp/cond%d.log", (int)__sys_getpid());
339fcaa7a3aSMatthew Dillon 	fd = open(buf, O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0666);
340fcaa7a3aSMatthew Dillon 	if (fd >= 0) {
341fcaa7a3aSMatthew Dillon 		i = LogWIndex;
342fcaa7a3aSMatthew Dillon 		if (i < LOGBUF_SIZE) {
343fcaa7a3aSMatthew Dillon 			write(fd, LogBuf, i);
344fcaa7a3aSMatthew Dillon 		} else {
345fcaa7a3aSMatthew Dillon 			i &= LOGBUF_MASK;
346fcaa7a3aSMatthew Dillon 			write(fd, LogBuf + i, LOGBUF_SIZE - i);
347fcaa7a3aSMatthew Dillon 			write(fd, LogBuf, i);
348fcaa7a3aSMatthew Dillon 		}
349fcaa7a3aSMatthew Dillon 		close(fd);
350fcaa7a3aSMatthew Dillon 	}
351fcaa7a3aSMatthew Dillon }
352fcaa7a3aSMatthew Dillon 
353fcaa7a3aSMatthew Dillon #endif
354