1290001Sglebius/*
2290001Sglebius * ntp_worker.h
3290001Sglebius */
4290001Sglebius
5290001Sglebius#ifndef NTP_WORKER_H
6290001Sglebius#define NTP_WORKER_H
7290001Sglebius
8290001Sglebius#include "ntp_workimpl.h"
9290001Sglebius
10290001Sglebius#ifdef WORKER
11290001Sglebius# if defined(WORK_THREAD) && defined(WORK_PIPE)
12290001Sglebius#  ifdef HAVE_SEMAPHORE_H
13290001Sglebius#   include <semaphore.h>
14290001Sglebius#  endif
15290001Sglebius# endif
16290001Sglebius#include "ntp_stdlib.h"
17290001Sglebius
18290001Sglebius/* #define TEST_BLOCKING_WORKER */	/* ntp_config.c ntp_intres.c */
19290001Sglebius
20290001Sglebiustypedef enum blocking_work_req_tag {
21290001Sglebius	BLOCKING_GETNAMEINFO,
22290001Sglebius	BLOCKING_GETADDRINFO,
23290001Sglebius} blocking_work_req;
24290001Sglebius
25290001Sglebiustypedef void (*blocking_work_callback)(blocking_work_req, void *, size_t, void *);
26290001Sglebius
27290001Sglebiustypedef enum blocking_magic_sig_e {
28290001Sglebius	BLOCKING_REQ_MAGIC  = 0x510c7ecf,
29290001Sglebius	BLOCKING_RESP_MAGIC = 0x510c7e54,
30290001Sglebius} blocking_magic_sig;
31290001Sglebius
32290001Sglebius/*
33290001Sglebius * The same header is used for both requests to and responses from
34290001Sglebius * the child.  In the child, done_func and context are opaque.
35290001Sglebius */
36290001Sglebiustypedef struct blocking_pipe_header_tag {
37290001Sglebius	size_t			octets;
38290001Sglebius	blocking_magic_sig	magic_sig;
39290001Sglebius	blocking_work_req	rtype;
40290001Sglebius	u_int			child_idx;
41290001Sglebius	blocking_work_callback	done_func;
42290001Sglebius	void *			context;
43290001Sglebius} blocking_pipe_header;
44290001Sglebius
45290001Sglebius# ifdef WORK_THREAD
46293896Sglebius#  ifdef SYS_WINNT
47293896Sglebiustypedef struct { HANDLE thnd; } thread_type;
48293896Sglebiustypedef struct { HANDLE shnd; } sema_type;
49290001Sglebius#  else
50293896Sglebiustypedef pthread_t	thread_type;
51293896Sglebiustypedef sem_t		sema_type;
52290001Sglebius#  endif
53293896Sglebiustypedef thread_type	*thr_ref;
54293896Sglebiustypedef sema_type	*sem_ref;
55290001Sglebius# endif
56290001Sglebius
57290001Sglebius/*
58290001Sglebius *
59290001Sglebius */
60293896Sglebius#if defined(WORK_FORK)
61293896Sglebius
62290001Sglebiustypedef struct blocking_child_tag {
63294905Sdelphij	int		reusable;
64294905Sdelphij	int		pid;
65294905Sdelphij	int		req_write_pipe;		/* parent */
66294905Sdelphij	int		resp_read_pipe;
67294905Sdelphij	void *		resp_read_ctx;
68294905Sdelphij	int		req_read_pipe;		/* child */
69294905Sdelphij	int		resp_write_pipe;
70294905Sdelphij	int		ispipe;
71294905Sdelphij	volatile u_int	resp_ready_seen;	/* signal/scan */
72294905Sdelphij	volatile u_int	resp_ready_done;	/* consumer/mainloop */
73290001Sglebius} blocking_child;
74293896Sglebius
75290001Sglebius#elif defined(WORK_THREAD)
76293896Sglebius
77290001Sglebiustypedef struct blocking_child_tag {
78294905Sdelphij	/*
79294905Sdelphij	 * blocking workitems and blocking_responses are
80294905Sdelphij	 * dynamically-sized one-dimensional arrays of pointers to
81294905Sdelphij	 * blocking worker requests and responses.
82294905Sdelphij	 *
83294905Sdelphij	 * IMPORTANT: This structure is shared between threads, and all
84294905Sdelphij	 * access that is not atomic (especially queue operations) must
85294905Sdelphij	 * hold the 'accesslock' semaphore to avoid data races.
86294905Sdelphij	 *
87294905Sdelphij	 * The resource management (thread/semaphore
88294905Sdelphij	 * creation/destruction) functions and functions just testing a
89294905Sdelphij	 * handle are safe because these are only changed by the main
90294905Sdelphij	 * thread when no worker is running on the same data structure.
91294905Sdelphij	 */
92290001Sglebius	int			reusable;
93293896Sglebius	sem_ref			accesslock;	/* shared access lock */
94293896Sglebius	thr_ref			thread_ref;	/* thread 'handle' */
95293896Sglebius
96293896Sglebius	/* the reuest queue */
97293896Sglebius	blocking_pipe_header ** volatile
98290001Sglebius				workitems;
99290001Sglebius	volatile size_t		workitems_alloc;
100293896Sglebius	size_t			head_workitem;		/* parent */
101293896Sglebius	size_t			tail_workitem;		/* child */
102293896Sglebius	sem_ref			workitems_pending;	/* signalling */
103293896Sglebius
104293896Sglebius	/* the response queue */
105293896Sglebius	blocking_pipe_header ** volatile
106290001Sglebius				responses;
107290001Sglebius	volatile size_t		responses_alloc;
108293896Sglebius	size_t			head_response;		/* child */
109293896Sglebius	size_t			tail_response;		/* parent */
110293896Sglebius
111290001Sglebius	/* event handles / sem_t pointers */
112290001Sglebius	sem_ref			wake_scheduled_sleep;
113293896Sglebius
114293896Sglebius	/* some systems use a pipe for notification, others a semaphore.
115293896Sglebius	 * Both employ the queue above for the actual data transfer.
116293896Sglebius	 */
117290001Sglebius#ifdef WORK_PIPE
118293896Sglebius	int			resp_read_pipe;		/* parent */
119293896Sglebius	int			resp_write_pipe;	/* child */
120290001Sglebius	int			ispipe;
121293896Sglebius	void *			resp_read_ctx;		/* child */
122290001Sglebius#else
123293896Sglebius	sem_ref			responses_pending;	/* signalling */
124290001Sglebius#endif
125298770Sdelphij	volatile u_int		resp_ready_seen;	/* signal/scan */
126298770Sdelphij	volatile u_int		resp_ready_done;	/* consumer/mainloop */
127293896Sglebius	sema_type		sem_table[4];
128293896Sglebius	thread_type		thr_table[1];
129290001Sglebius} blocking_child;
130290001Sglebius
131290001Sglebius#endif	/* WORK_THREAD */
132290001Sglebius
133294905Sdelphij/* we need some global tag to indicate any blocking child may be ready: */
134294905Sdelphijextern volatile u_int		blocking_child_ready_seen;/* signal/scan */
135294905Sdelphijextern volatile u_int		blocking_child_ready_done;/* consumer/mainloop */
136294905Sdelphij
137290001Sglebiusextern	blocking_child **	blocking_children;
138290001Sglebiusextern	size_t			blocking_children_alloc;
139290001Sglebiusextern	int			worker_per_query;	/* boolean */
140290001Sglebiusextern	int			intres_req_pending;
141290001Sglebius
142290001Sglebiusextern	u_int	available_blocking_child_slot(void);
143290001Sglebiusextern	int	queue_blocking_request(blocking_work_req, void *,
144290001Sglebius				       size_t, blocking_work_callback,
145290001Sglebius				       void *);
146293896Sglebiusextern	int	queue_blocking_response(blocking_child *,
147290001Sglebius					blocking_pipe_header *, size_t,
148290001Sglebius					const blocking_pipe_header *);
149290001Sglebiusextern	void	process_blocking_resp(blocking_child *);
150294905Sdelphijextern	void	harvest_blocking_responses(void);
151290001Sglebiusextern	int	send_blocking_req_internal(blocking_child *,
152290001Sglebius					   blocking_pipe_header *,
153290001Sglebius					   void *);
154290001Sglebiusextern	int	send_blocking_resp_internal(blocking_child *,
155290001Sglebius					    blocking_pipe_header *);
156290001Sglebiusextern	blocking_pipe_header *
157290001Sglebius		receive_blocking_req_internal(blocking_child *);
158290001Sglebiusextern	blocking_pipe_header *
159290001Sglebius		receive_blocking_resp_internal(blocking_child *);
160290001Sglebiusextern	int	blocking_child_common(blocking_child *);
161290001Sglebiusextern	void	exit_worker(int)
162290001Sglebius			__attribute__ ((__noreturn__));
163290001Sglebiusextern	int	worker_sleep(blocking_child *, time_t);
164290001Sglebiusextern	void	worker_idle_timer_fired(void);
165290001Sglebiusextern	void	interrupt_worker_sleep(void);
166290001Sglebiusextern	int	req_child_exit(blocking_child *);
167290001Sglebius#ifndef HAVE_IO_COMPLETION_PORT
168290001Sglebiusextern	int	pipe_socketpair(int fds[2], int *is_pipe);
169290001Sglebiusextern	void	close_all_beyond(int);
170290001Sglebiusextern	void	close_all_except(int);
171290001Sglebiusextern	void	kill_asyncio	(int);
172290001Sglebius#endif
173290001Sglebius
174298770Sdelphijextern void worker_global_lock(int inOrOut);
175298770Sdelphij
176290001Sglebius# ifdef WORK_PIPE
177290001Sglebiustypedef	void	(*addremove_io_fd_func)(int, int, int);
178290001Sglebiusextern	addremove_io_fd_func		addremove_io_fd;
179290001Sglebius# else
180290001Sglebiusextern	void	handle_blocking_resp_sem(void *);
181290001Sglebiustypedef	void	(*addremove_io_semaphore_func)(sem_ref, int);
182290001Sglebiusextern	addremove_io_semaphore_func	addremove_io_semaphore;
183290001Sglebius# endif
184290001Sglebius
185290001Sglebius# ifdef WORK_FORK
186290001Sglebiusextern	int				worker_process;
187290001Sglebius# endif
188290001Sglebius
189290001Sglebius#endif	/* WORKER */
190290001Sglebius
191290001Sglebius#if defined(HAVE_DROPROOT) && defined(WORK_FORK)
192290001Sglebiusextern void	fork_deferred_worker(void);
193290001Sglebius#else
194290001Sglebius# define	fork_deferred_worker()	do {} while (0)
195290001Sglebius#endif
196290001Sglebius
197290001Sglebius#endif	/* !NTP_WORKER_H */
198