xref: /openbsd-src/usr.bin/sndiod/file.c (revision 7b6392009e6e5a7f8e494c162a4d259ea5e13a62)
1*7b639200Sratchov /*	$OpenBSD: file.c,v 1.28 2024/12/20 07:35:56 ratchov Exp $	*/
287bc9f6aSratchov /*
387bc9f6aSratchov  * Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
487bc9f6aSratchov  *
587bc9f6aSratchov  * Permission to use, copy, modify, and distribute this software for any
687bc9f6aSratchov  * purpose with or without fee is hereby granted, provided that the above
787bc9f6aSratchov  * copyright notice and this permission notice appear in all copies.
887bc9f6aSratchov  *
987bc9f6aSratchov  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1087bc9f6aSratchov  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1187bc9f6aSratchov  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1287bc9f6aSratchov  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1387bc9f6aSratchov  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1487bc9f6aSratchov  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1587bc9f6aSratchov  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1687bc9f6aSratchov  */
1787bc9f6aSratchov /*
1887bc9f6aSratchov  * non-blocking file i/o module: each file can be read or written (or
1987bc9f6aSratchov  * both). To achieve non-blocking io, we simply use the poll() syscall
2087bc9f6aSratchov  * in an event loop and dispatch events to sub-modules.
2187bc9f6aSratchov  *
2287bc9f6aSratchov  * the module also provides trivial timeout implementation,
2387bc9f6aSratchov  * derived from:
2487bc9f6aSratchov  *
2587bc9f6aSratchov  * 	anoncvs@moule.caoua.org:/midish
2687bc9f6aSratchov  *
2787bc9f6aSratchov  *		midish/timo.c rev 1.18
2887bc9f6aSratchov  * 		midish/mdep.c rev 1.71
2987bc9f6aSratchov  *
3087bc9f6aSratchov  * A timeout is used to schedule the call of a routine (the callback)
3187bc9f6aSratchov  * there is a global list of timeouts that is processed inside the
3287bc9f6aSratchov  * event loop. Timeouts work as follows:
3387bc9f6aSratchov  *
3487bc9f6aSratchov  *	first the timo structure must be initialized with timo_set()
3587bc9f6aSratchov  *
3687bc9f6aSratchov  *	then the timeout is scheduled (only once) with timo_add()
3787bc9f6aSratchov  *
3887bc9f6aSratchov  *	if the timeout expires, the call-back is called; then it can
3987bc9f6aSratchov  *	be scheduled again if needed. It's OK to reschedule it again
4087bc9f6aSratchov  *	from the callback
4187bc9f6aSratchov  *
4287bc9f6aSratchov  *	the timeout can be aborted with timo_del(), it is OK to try to
43d9a51c35Sjmc  *	abort a timeout that has expired
4487bc9f6aSratchov  *
4587bc9f6aSratchov  */
4687bc9f6aSratchov 
4787bc9f6aSratchov #include <sys/types.h>
4887bc9f6aSratchov 
4987bc9f6aSratchov #include <errno.h>
5087bc9f6aSratchov #include <fcntl.h>
5187bc9f6aSratchov #include <poll.h>
5287bc9f6aSratchov #include <signal.h>
5387bc9f6aSratchov #include <stdio.h>
5487bc9f6aSratchov #include <stdlib.h>
5587bc9f6aSratchov #include <time.h>
5687bc9f6aSratchov 
5787bc9f6aSratchov #include "file.h"
5887bc9f6aSratchov #include "utils.h"
5987bc9f6aSratchov 
6087bc9f6aSratchov #define MAXFDS 100
61df956371Sratchov #define TIMER_MSEC 5
6287bc9f6aSratchov 
63fcda7a7eSratchov void timo_update(unsigned int);
64fcda7a7eSratchov void timo_init(void);
65fcda7a7eSratchov void timo_done(void);
6660ba7eecSratchov int file_process(struct file *, struct pollfd *);
67fcda7a7eSratchov 
6887bc9f6aSratchov struct timespec file_ts;
6987bc9f6aSratchov struct file *file_list;
7087bc9f6aSratchov struct timo *timo_queue;
7187bc9f6aSratchov unsigned int timo_abstime;
7287bc9f6aSratchov int file_slowaccept = 0, file_nfds;
7387bc9f6aSratchov #ifdef DEBUG
7487bc9f6aSratchov long long file_wtime, file_utime;
7587bc9f6aSratchov #endif
7687bc9f6aSratchov 
7787bc9f6aSratchov /*
7887bc9f6aSratchov  * initialise a timeout structure, arguments are callback and argument
7987bc9f6aSratchov  * that will be passed to the callback
8087bc9f6aSratchov  */
8187bc9f6aSratchov void
8287bc9f6aSratchov timo_set(struct timo *o, void (*cb)(void *), void *arg)
8387bc9f6aSratchov {
8487bc9f6aSratchov 	o->cb = cb;
8587bc9f6aSratchov 	o->arg = arg;
8687bc9f6aSratchov 	o->set = 0;
8787bc9f6aSratchov }
8887bc9f6aSratchov 
8987bc9f6aSratchov /*
9087bc9f6aSratchov  * schedule the callback in 'delta' 24-th of microseconds. The timeout
9187bc9f6aSratchov  * must not be already scheduled
9287bc9f6aSratchov  */
9387bc9f6aSratchov void
9487bc9f6aSratchov timo_add(struct timo *o, unsigned int delta)
9587bc9f6aSratchov {
9687bc9f6aSratchov 	struct timo **i;
9787bc9f6aSratchov 	unsigned int val;
9887bc9f6aSratchov 	int diff;
9987bc9f6aSratchov 
10087bc9f6aSratchov #ifdef DEBUG
10187bc9f6aSratchov 	if (o->set) {
102*7b639200Sratchov 		logx(0, "timo_add: already set");
10387bc9f6aSratchov 		panic();
10487bc9f6aSratchov 	}
10587bc9f6aSratchov 	if (delta == 0) {
106*7b639200Sratchov 		logx(0, "timo_add: zero timeout is evil");
10787bc9f6aSratchov 		panic();
10887bc9f6aSratchov 	}
10987bc9f6aSratchov #endif
11087bc9f6aSratchov 	val = timo_abstime + delta;
11187bc9f6aSratchov 	for (i = &timo_queue; *i != NULL; i = &(*i)->next) {
11287bc9f6aSratchov 		diff = (*i)->val - val;
11387bc9f6aSratchov 		if (diff > 0) {
11487bc9f6aSratchov 			break;
11587bc9f6aSratchov 		}
11687bc9f6aSratchov 	}
11787bc9f6aSratchov 	o->set = 1;
11887bc9f6aSratchov 	o->val = val;
11987bc9f6aSratchov 	o->next = *i;
12087bc9f6aSratchov 	*i = o;
12187bc9f6aSratchov }
12287bc9f6aSratchov 
12387bc9f6aSratchov /*
12487bc9f6aSratchov  * abort a scheduled timeout
12587bc9f6aSratchov  */
12687bc9f6aSratchov void
12787bc9f6aSratchov timo_del(struct timo *o)
12887bc9f6aSratchov {
12987bc9f6aSratchov 	struct timo **i;
13087bc9f6aSratchov 
13187bc9f6aSratchov 	for (i = &timo_queue; *i != NULL; i = &(*i)->next) {
13287bc9f6aSratchov 		if (*i == o) {
13387bc9f6aSratchov 			*i = o->next;
13487bc9f6aSratchov 			o->set = 0;
13587bc9f6aSratchov 			return;
13687bc9f6aSratchov 		}
13787bc9f6aSratchov 	}
13887bc9f6aSratchov #ifdef DEBUG
139*7b639200Sratchov 	logx(4, "timo_del: not found");
14087bc9f6aSratchov #endif
14187bc9f6aSratchov }
14287bc9f6aSratchov 
14387bc9f6aSratchov /*
14487bc9f6aSratchov  * routine to be called by the timer when 'delta' 24-th of microsecond
145d9a51c35Sjmc  * elapsed. This routine updates time reference used by timeouts and
14687bc9f6aSratchov  * calls expired timeouts
14787bc9f6aSratchov  */
14887bc9f6aSratchov void
14987bc9f6aSratchov timo_update(unsigned int delta)
15087bc9f6aSratchov {
15187bc9f6aSratchov 	struct timo *to;
15287bc9f6aSratchov 	int diff;
15387bc9f6aSratchov 
15487bc9f6aSratchov 	/*
15587bc9f6aSratchov 	 * update time reference
15687bc9f6aSratchov 	 */
15787bc9f6aSratchov 	timo_abstime += delta;
15887bc9f6aSratchov 
15987bc9f6aSratchov 	/*
16087bc9f6aSratchov 	 * remove from the queue and run expired timeouts
16187bc9f6aSratchov 	 */
16287bc9f6aSratchov 	while (timo_queue != NULL) {
16387bc9f6aSratchov 		/*
16487bc9f6aSratchov 		 * there is no overflow here because + and - are
16587bc9f6aSratchov 		 * modulo 2^32, they are the same for both signed and
16687bc9f6aSratchov 		 * unsigned integers
16787bc9f6aSratchov 		 */
16887bc9f6aSratchov 		diff = timo_queue->val - timo_abstime;
16987bc9f6aSratchov 		if (diff > 0)
17087bc9f6aSratchov 			break;
17187bc9f6aSratchov 		to = timo_queue;
17287bc9f6aSratchov 		timo_queue = to->next;
17387bc9f6aSratchov 		to->set = 0;
17487bc9f6aSratchov 		to->cb(to->arg);
17587bc9f6aSratchov 	}
17687bc9f6aSratchov }
17787bc9f6aSratchov 
17887bc9f6aSratchov /*
17987bc9f6aSratchov  * initialize timeout queue
18087bc9f6aSratchov  */
18187bc9f6aSratchov void
18287bc9f6aSratchov timo_init(void)
18387bc9f6aSratchov {
18487bc9f6aSratchov 	timo_queue = NULL;
18587bc9f6aSratchov 	timo_abstime = 0;
18687bc9f6aSratchov }
18787bc9f6aSratchov 
18887bc9f6aSratchov /*
18987bc9f6aSratchov  * destroy timeout queue
19087bc9f6aSratchov  */
19187bc9f6aSratchov void
19287bc9f6aSratchov timo_done(void)
19387bc9f6aSratchov {
19487bc9f6aSratchov #ifdef DEBUG
19587bc9f6aSratchov 	if (timo_queue != NULL) {
196*7b639200Sratchov 		logx(0, "timo_done: timo_queue not empty!");
19787bc9f6aSratchov 		panic();
19887bc9f6aSratchov 	}
19987bc9f6aSratchov #endif
20087bc9f6aSratchov 	timo_queue = (struct timo *)0xdeadbeef;
20187bc9f6aSratchov }
20287bc9f6aSratchov 
20387bc9f6aSratchov struct file *
20487bc9f6aSratchov file_new(struct fileops *ops, void *arg, char *name, unsigned int nfds)
20587bc9f6aSratchov {
20687bc9f6aSratchov 	struct file *f;
20787bc9f6aSratchov 
20887bc9f6aSratchov 	if (file_nfds + nfds > MAXFDS) {
20987bc9f6aSratchov #ifdef DEBUG
210*7b639200Sratchov 		logx(1, "%s: too many polled files", name);
21187bc9f6aSratchov #endif
21287bc9f6aSratchov 		return NULL;
21387bc9f6aSratchov 	}
21487bc9f6aSratchov 	f = xmalloc(sizeof(struct file));
215e4bc365bSratchov 	f->max_nfds = nfds;
2164c0d1d38Sratchov 	f->nfds = 0;
21787bc9f6aSratchov 	f->ops = ops;
21887bc9f6aSratchov 	f->arg = arg;
21987bc9f6aSratchov 	f->name = name;
22087bc9f6aSratchov 	f->state = FILE_INIT;
22187bc9f6aSratchov 	f->next = file_list;
22287bc9f6aSratchov 	file_list = f;
22387bc9f6aSratchov #ifdef DEBUG
224*7b639200Sratchov 	logx(3, "%s: created", f->name);
22587bc9f6aSratchov #endif
226e4bc365bSratchov 	file_nfds += f->max_nfds;
22787bc9f6aSratchov 	return f;
22887bc9f6aSratchov }
22987bc9f6aSratchov 
23087bc9f6aSratchov void
23187bc9f6aSratchov file_del(struct file *f)
23287bc9f6aSratchov {
23387bc9f6aSratchov #ifdef DEBUG
23487bc9f6aSratchov 	if (f->state == FILE_ZOMB) {
235*7b639200Sratchov 		logx(0, "%s: %s: bad state in file_del", __func__, f->name);
23687bc9f6aSratchov 		panic();
23787bc9f6aSratchov 	}
23887bc9f6aSratchov #endif
239e4bc365bSratchov 	file_nfds -= f->max_nfds;
24087bc9f6aSratchov 	f->state = FILE_ZOMB;
24187bc9f6aSratchov #ifdef DEBUG
242*7b639200Sratchov 	logx(3, "%s: destroyed", f->name);
24387bc9f6aSratchov #endif
24487bc9f6aSratchov }
24587bc9f6aSratchov 
24660ba7eecSratchov int
247633fcf5dSratchov file_process(struct file *f, struct pollfd *pfd)
24887bc9f6aSratchov {
24960ba7eecSratchov 	int rc, revents;
25087bc9f6aSratchov #ifdef DEBUG
25187bc9f6aSratchov 	struct timespec ts0, ts1;
25287bc9f6aSratchov 	long us;
25387bc9f6aSratchov #endif
25487bc9f6aSratchov 
25587bc9f6aSratchov #ifdef DEBUG
25608729cdbSratchov 	if (log_level >= 3)
2573471b98aSratchov 		clock_gettime(CLOCK_UPTIME, &ts0);
25887bc9f6aSratchov #endif
25960ba7eecSratchov 	rc = 0;
260d135469bSratchov 	revents = (f->state != FILE_ZOMB) ?
2611e4c42baSratchov 	    f->ops->revents(f->arg, pfd) : 0;
26260ba7eecSratchov 	if ((revents & POLLHUP) && (f->state != FILE_ZOMB)) {
26387bc9f6aSratchov 		f->ops->hup(f->arg);
26460ba7eecSratchov 		rc = 1;
26560ba7eecSratchov 	}
26660ba7eecSratchov 	if ((revents & POLLIN) && (f->state != FILE_ZOMB)) {
26787bc9f6aSratchov 		f->ops->in(f->arg);
26860ba7eecSratchov 		rc = 1;
26960ba7eecSratchov 	}
27060ba7eecSratchov 	if ((revents & POLLOUT) && (f->state != FILE_ZOMB)) {
27187bc9f6aSratchov 		f->ops->out(f->arg);
27260ba7eecSratchov 		rc = 1;
27360ba7eecSratchov 	}
27487bc9f6aSratchov #ifdef DEBUG
27508729cdbSratchov 	if (log_level >= 3) {
2763471b98aSratchov 		clock_gettime(CLOCK_UPTIME, &ts1);
27787bc9f6aSratchov 		us = 1000000L * (ts1.tv_sec - ts0.tv_sec);
27887bc9f6aSratchov 		us += (ts1.tv_nsec - ts0.tv_nsec) / 1000;
279*7b639200Sratchov 		if (us >= 5000)
280*7b639200Sratchov 			logx(4, "%s: processed in %luus", f->name, us);
28108729cdbSratchov 	}
28287bc9f6aSratchov #endif
28360ba7eecSratchov 	return rc;
284633fcf5dSratchov }
285633fcf5dSratchov 
286*7b639200Sratchov #ifdef DEBUG
287*7b639200Sratchov size_t
288*7b639200Sratchov filelist_fmt(char *buf, size_t size, struct pollfd *pfd, int ret)
289*7b639200Sratchov {
290*7b639200Sratchov 	struct file *f;
291*7b639200Sratchov 	char *p = buf, *end = buf + size;
292*7b639200Sratchov 	const char *sep = "";
293*7b639200Sratchov 	int i;
294*7b639200Sratchov 
295*7b639200Sratchov 	for (f = file_list; f != NULL; f = f->next) {
296*7b639200Sratchov 		p += snprintf(p, p < end ? end - p : 0, "%s%s:", sep, f->name);
297*7b639200Sratchov 		for (i = 0; i < f->nfds; i++) {
298*7b639200Sratchov 			p += snprintf(p, p < end ? end - p : 0, " 0x%x",
299*7b639200Sratchov 			    ret ? pfd->revents : pfd->events);
300*7b639200Sratchov 			pfd++;
301*7b639200Sratchov 		}
302*7b639200Sratchov 		sep = ", ";
303*7b639200Sratchov 	}
304*7b639200Sratchov 	return p - buf;
305*7b639200Sratchov }
306*7b639200Sratchov #endif
307*7b639200Sratchov 
308633fcf5dSratchov int
309633fcf5dSratchov file_poll(void)
310633fcf5dSratchov {
311633fcf5dSratchov 	struct pollfd pfds[MAXFDS], *pfd;
312633fcf5dSratchov 	struct file *f, **pf;
313633fcf5dSratchov 	struct timespec ts;
314633fcf5dSratchov #ifdef DEBUG
315633fcf5dSratchov 	struct timespec sleepts;
316*7b639200Sratchov 	char str[128];
317633fcf5dSratchov #endif
318633fcf5dSratchov 	long long delta_nsec;
319de56ec40Sratchov 	int nfds, res, timo;
320633fcf5dSratchov 
321633fcf5dSratchov 	/*
322633fcf5dSratchov 	 * cleanup zombies
323633fcf5dSratchov 	 */
324633fcf5dSratchov 	pf = &file_list;
325633fcf5dSratchov 	while ((f = *pf) != NULL) {
326633fcf5dSratchov 		if (f->state == FILE_ZOMB) {
327633fcf5dSratchov 			*pf = f->next;
328633fcf5dSratchov 			xfree(f);
329633fcf5dSratchov 		} else
330633fcf5dSratchov 			pf = &f->next;
331633fcf5dSratchov 	}
332633fcf5dSratchov 
333633fcf5dSratchov 	if (file_list == NULL && timo_queue == NULL) {
334633fcf5dSratchov #ifdef DEBUG
335*7b639200Sratchov 		logx(3, "nothing to do...");
336633fcf5dSratchov #endif
337633fcf5dSratchov 		return 0;
338633fcf5dSratchov 	}
339633fcf5dSratchov 
340633fcf5dSratchov 	/*
341633fcf5dSratchov 	 * fill pollfd structures
342633fcf5dSratchov 	 */
343633fcf5dSratchov 	nfds = 0;
344633fcf5dSratchov 	for (f = file_list; f != NULL; f = f->next) {
345633fcf5dSratchov 		f->nfds = f->ops->pollfd(f->arg, pfds + nfds);
346633fcf5dSratchov 		if (f->nfds == 0)
347633fcf5dSratchov 			continue;
348633fcf5dSratchov 		nfds += f->nfds;
349633fcf5dSratchov 	}
350633fcf5dSratchov #ifdef DEBUG
351*7b639200Sratchov 	logx(4, "poll [%s]", (filelist_fmt(str, sizeof(str), pfds, 0), str));
352633fcf5dSratchov #endif
353633fcf5dSratchov 
354633fcf5dSratchov 	/*
355633fcf5dSratchov 	 * process files that do not rely on poll
356633fcf5dSratchov 	 */
35760ba7eecSratchov 	res = 0;
358633fcf5dSratchov 	for (f = file_list; f != NULL; f = f->next) {
359633fcf5dSratchov 		if (f->nfds > 0)
360633fcf5dSratchov 			continue;
36160ba7eecSratchov 		res |= file_process(f, NULL);
362633fcf5dSratchov 	}
36360ba7eecSratchov 	/*
36460ba7eecSratchov 	 * The processing may have changed the poll(2) conditions of
36560ba7eecSratchov 	 * other files, so restart the loop to force their poll(2) event
36660ba7eecSratchov 	 * masks to be reevaluated.
36760ba7eecSratchov 	 */
36860ba7eecSratchov 	if (res)
36960ba7eecSratchov 		return 1;
370633fcf5dSratchov 
371633fcf5dSratchov 	/*
3727c71888cSratchov 	 * Sleep. Calculate the number of milliseconds poll(2) must
3737c71888cSratchov 	 * wait before the timo_update() needs to be called. If there are
3744466229bSratchov 	 * no timeouts scheduled, then call poll(2) with infinite
3754466229bSratchov 	 * timeout (i.e -1).
376633fcf5dSratchov 	 */
377633fcf5dSratchov #ifdef DEBUG
3783471b98aSratchov 	clock_gettime(CLOCK_UPTIME, &sleepts);
379633fcf5dSratchov 	file_utime += 1000000000LL * (sleepts.tv_sec - file_ts.tv_sec);
380633fcf5dSratchov 	file_utime += sleepts.tv_nsec - file_ts.tv_nsec;
381633fcf5dSratchov #endif
382de56ec40Sratchov 	if (timo_queue != NULL) {
383de56ec40Sratchov 		timo = ((int)timo_queue->val - (int)timo_abstime) / 1000;
384de56ec40Sratchov 		if (timo < TIMER_MSEC)
385de56ec40Sratchov 			timo = TIMER_MSEC;
386de56ec40Sratchov 	} else
3874466229bSratchov 		timo = -1;
3889c0af79aSratchov 	log_flush();
389de56ec40Sratchov 	res = poll(pfds, nfds, timo);
3903aaa63ebSderaadt 	if (res == -1) {
391babe36e9Sratchov 		if (errno != EINTR) {
392*7b639200Sratchov 			logx(0, "poll failed");
393babe36e9Sratchov 			panic();
394babe36e9Sratchov 		}
395633fcf5dSratchov 		return 1;
396633fcf5dSratchov 	}
397633fcf5dSratchov 
398633fcf5dSratchov 	/*
399633fcf5dSratchov 	 * run timeouts
400633fcf5dSratchov 	 */
4013471b98aSratchov 	clock_gettime(CLOCK_UPTIME, &ts);
402633fcf5dSratchov #ifdef DEBUG
403633fcf5dSratchov 	file_wtime += 1000000000LL * (ts.tv_sec - sleepts.tv_sec);
404633fcf5dSratchov 	file_wtime += ts.tv_nsec - sleepts.tv_nsec;
405633fcf5dSratchov #endif
406753b38d1Sratchov 	if (timo_queue) {
407633fcf5dSratchov 		delta_nsec = 1000000000LL * (ts.tv_sec - file_ts.tv_sec);
408633fcf5dSratchov 		delta_nsec += ts.tv_nsec - file_ts.tv_nsec;
409b8b8f36cSratchov 		if (delta_nsec >= 0 && delta_nsec < 60000000000LL)
410633fcf5dSratchov 			timo_update(delta_nsec / 1000);
411*7b639200Sratchov 		else
412*7b639200Sratchov 			logx(2, "out-of-bounds clock delta");
413753b38d1Sratchov 	}
414753b38d1Sratchov 	file_ts = ts;
415633fcf5dSratchov 
416633fcf5dSratchov 	/*
417633fcf5dSratchov 	 * process files that rely on poll
418633fcf5dSratchov 	 */
419633fcf5dSratchov 	pfd = pfds;
420633fcf5dSratchov 	for (f = file_list; f != NULL; f = f->next) {
421633fcf5dSratchov 		if (f->nfds == 0)
422633fcf5dSratchov 			continue;
423633fcf5dSratchov 		file_process(f, pfd);
4241e4c42baSratchov 		pfd += f->nfds;
42587bc9f6aSratchov 	}
42687bc9f6aSratchov 	return 1;
42787bc9f6aSratchov }
42887bc9f6aSratchov 
42987bc9f6aSratchov void
43087bc9f6aSratchov filelist_init(void)
43187bc9f6aSratchov {
43287bc9f6aSratchov 	sigset_t set;
43387bc9f6aSratchov 
4343aaa63ebSderaadt 	if (clock_gettime(CLOCK_UPTIME, &file_ts) == -1) {
435*7b639200Sratchov 		logx(0, "filelist_init: CLOCK_UPTIME unsupported");
436babe36e9Sratchov 		panic();
43787bc9f6aSratchov 	}
438babe36e9Sratchov 	sigemptyset(&set);
439babe36e9Sratchov 	sigaddset(&set, SIGPIPE);
440babe36e9Sratchov 	sigprocmask(SIG_BLOCK, &set, NULL);
441babe36e9Sratchov 	file_list = NULL;
44287bc9f6aSratchov 	log_sync = 0;
44387bc9f6aSratchov 	timo_init();
44487bc9f6aSratchov }
44587bc9f6aSratchov 
44687bc9f6aSratchov void
44787bc9f6aSratchov filelist_done(void)
44887bc9f6aSratchov {
44987bc9f6aSratchov #ifdef DEBUG
45087bc9f6aSratchov 	struct file *f;
45187bc9f6aSratchov 
45287bc9f6aSratchov 	if (file_list != NULL) {
453*7b639200Sratchov 		for (f = file_list; f != NULL; f = f->next)
454*7b639200Sratchov 			logx(0, "%s: not closed", f->name);
45587bc9f6aSratchov 		panic();
45687bc9f6aSratchov 	}
45787bc9f6aSratchov 	log_sync = 1;
45887bc9f6aSratchov 	log_flush();
45987bc9f6aSratchov #endif
46087bc9f6aSratchov 	timo_done();
46187bc9f6aSratchov }
462