1275970Scy/*
2275970Scy * ntp_worker.h
3275970Scy */
4275970Scy
5275970Scy#ifndef NTP_WORKER_H
6275970Scy#define NTP_WORKER_H
7275970Scy
8275970Scy#include "ntp_workimpl.h"
9275970Scy
10275970Scy#ifdef WORKER
11275970Scy# if defined(WORK_THREAD) && defined(WORK_PIPE)
12275970Scy#  ifdef HAVE_SEMAPHORE_H
13275970Scy#   include <semaphore.h>
14275970Scy#  endif
15275970Scy# endif
16275970Scy#include "ntp_stdlib.h"
17275970Scy
18275970Scy/* #define TEST_BLOCKING_WORKER */	/* ntp_config.c ntp_intres.c */
19275970Scy
20275970Scytypedef enum blocking_work_req_tag {
21275970Scy	BLOCKING_GETNAMEINFO,
22275970Scy	BLOCKING_GETADDRINFO,
23275970Scy} blocking_work_req;
24275970Scy
25275970Scytypedef void (*blocking_work_callback)(blocking_work_req, void *, size_t, void *);
26275970Scy
27275970Scytypedef enum blocking_magic_sig_e {
28275970Scy	BLOCKING_REQ_MAGIC  = 0x510c7ecf,
29275970Scy	BLOCKING_RESP_MAGIC = 0x510c7e54,
30275970Scy} blocking_magic_sig;
31275970Scy
32275970Scy/*
33275970Scy * The same header is used for both requests to and responses from
34275970Scy * the child.  In the child, done_func and context are opaque.
35275970Scy */
36275970Scytypedef struct blocking_pipe_header_tag {
37275970Scy	size_t			octets;
38275970Scy	blocking_magic_sig	magic_sig;
39275970Scy	blocking_work_req	rtype;
40275970Scy	u_int			child_idx;
41275970Scy	blocking_work_callback	done_func;
42275970Scy	void *			context;
43275970Scy} blocking_pipe_header;
44275970Scy
45275970Scy# ifdef WORK_THREAD
46293423Sdelphij#  ifdef SYS_WINNT
47293423Sdelphijtypedef struct { HANDLE thnd; } thread_type;
48293423Sdelphijtypedef struct { HANDLE shnd; } sema_type;
49275970Scy#  else
50293423Sdelphijtypedef pthread_t	thread_type;
51293423Sdelphijtypedef sem_t		sema_type;
52275970Scy#  endif
53293423Sdelphijtypedef thread_type	*thr_ref;
54293423Sdelphijtypedef sema_type	*sem_ref;
55275970Scy# endif
56275970Scy
57275970Scy/*
58275970Scy *
59275970Scy */
60293423Sdelphij#if defined(WORK_FORK)
61293423Sdelphij
62275970Scytypedef struct blocking_child_tag {
63294554Sdelphij	int		reusable;
64294554Sdelphij	int		pid;
65294554Sdelphij	int		req_write_pipe;		/* parent */
66294554Sdelphij	int		resp_read_pipe;
67294554Sdelphij	void *		resp_read_ctx;
68294554Sdelphij	int		req_read_pipe;		/* child */
69294554Sdelphij	int		resp_write_pipe;
70294554Sdelphij	int		ispipe;
71294554Sdelphij	volatile u_int	resp_ready_seen;	/* signal/scan */
72294554Sdelphij	volatile u_int	resp_ready_done;	/* consumer/mainloop */
73275970Scy} blocking_child;
74293423Sdelphij
75275970Scy#elif defined(WORK_THREAD)
76293423Sdelphij
77275970Scytypedef struct blocking_child_tag {
78294554Sdelphij	/*
79294554Sdelphij	 * blocking workitems and blocking_responses are
80294554Sdelphij	 * dynamically-sized one-dimensional arrays of pointers to
81294554Sdelphij	 * blocking worker requests and responses.
82294554Sdelphij	 *
83294554Sdelphij	 * IMPORTANT: This structure is shared between threads, and all
84294554Sdelphij	 * access that is not atomic (especially queue operations) must
85294554Sdelphij	 * hold the 'accesslock' semaphore to avoid data races.
86294554Sdelphij	 *
87294554Sdelphij	 * The resource management (thread/semaphore
88294554Sdelphij	 * creation/destruction) functions and functions just testing a
89294554Sdelphij	 * handle are safe because these are only changed by the main
90294554Sdelphij	 * thread when no worker is running on the same data structure.
91294554Sdelphij	 */
92275970Scy	int			reusable;
93293423Sdelphij	sem_ref			accesslock;	/* shared access lock */
94293423Sdelphij	thr_ref			thread_ref;	/* thread 'handle' */
95293423Sdelphij
96293423Sdelphij	/* the reuest queue */
97293423Sdelphij	blocking_pipe_header ** volatile
98275970Scy				workitems;
99275970Scy	volatile size_t		workitems_alloc;
100293423Sdelphij	size_t			head_workitem;		/* parent */
101293423Sdelphij	size_t			tail_workitem;		/* child */
102293423Sdelphij	sem_ref			workitems_pending;	/* signalling */
103293423Sdelphij
104293423Sdelphij	/* the response queue */
105293423Sdelphij	blocking_pipe_header ** volatile
106275970Scy				responses;
107275970Scy	volatile size_t		responses_alloc;
108293423Sdelphij	size_t			head_response;		/* child */
109293423Sdelphij	size_t			tail_response;		/* parent */
110293423Sdelphij
111275970Scy	/* event handles / sem_t pointers */
112275970Scy	sem_ref			wake_scheduled_sleep;
113293423Sdelphij
114293423Sdelphij	/* some systems use a pipe for notification, others a semaphore.
115293423Sdelphij	 * Both employ the queue above for the actual data transfer.
116293423Sdelphij	 */
117275970Scy#ifdef WORK_PIPE
118293423Sdelphij	int			resp_read_pipe;		/* parent */
119293423Sdelphij	int			resp_write_pipe;	/* child */
120275970Scy	int			ispipe;
121293423Sdelphij	void *			resp_read_ctx;		/* child */
122275970Scy#else
123293423Sdelphij	sem_ref			responses_pending;	/* signalling */
124275970Scy#endif
125298695Sdelphij	volatile u_int		resp_ready_seen;	/* signal/scan */
126298695Sdelphij	volatile u_int		resp_ready_done;	/* consumer/mainloop */
127293423Sdelphij	sema_type		sem_table[4];
128293423Sdelphij	thread_type		thr_table[1];
129275970Scy} blocking_child;
130275970Scy
131275970Scy#endif	/* WORK_THREAD */
132275970Scy
133294554Sdelphij/* we need some global tag to indicate any blocking child may be ready: */
134294554Sdelphijextern volatile u_int		blocking_child_ready_seen;/* signal/scan */
135294554Sdelphijextern volatile u_int		blocking_child_ready_done;/* consumer/mainloop */
136294554Sdelphij
137275970Scyextern	blocking_child **	blocking_children;
138275970Scyextern	size_t			blocking_children_alloc;
139275970Scyextern	int			worker_per_query;	/* boolean */
140275970Scyextern	int			intres_req_pending;
141275970Scy
142275970Scyextern	u_int	available_blocking_child_slot(void);
143275970Scyextern	int	queue_blocking_request(blocking_work_req, void *,
144275970Scy				       size_t, blocking_work_callback,
145275970Scy				       void *);
146293423Sdelphijextern	int	queue_blocking_response(blocking_child *,
147275970Scy					blocking_pipe_header *, size_t,
148275970Scy					const blocking_pipe_header *);
149275970Scyextern	void	process_blocking_resp(blocking_child *);
150294554Sdelphijextern	void	harvest_blocking_responses(void);
151275970Scyextern	int	send_blocking_req_internal(blocking_child *,
152275970Scy					   blocking_pipe_header *,
153275970Scy					   void *);
154275970Scyextern	int	send_blocking_resp_internal(blocking_child *,
155275970Scy					    blocking_pipe_header *);
156275970Scyextern	blocking_pipe_header *
157275970Scy		receive_blocking_req_internal(blocking_child *);
158275970Scyextern	blocking_pipe_header *
159275970Scy		receive_blocking_resp_internal(blocking_child *);
160275970Scyextern	int	blocking_child_common(blocking_child *);
161275970Scyextern	void	exit_worker(int)
162275970Scy			__attribute__ ((__noreturn__));
163275970Scyextern	int	worker_sleep(blocking_child *, time_t);
164275970Scyextern	void	worker_idle_timer_fired(void);
165275970Scyextern	void	interrupt_worker_sleep(void);
166275970Scyextern	int	req_child_exit(blocking_child *);
167275970Scy#ifndef HAVE_IO_COMPLETION_PORT
168275970Scyextern	int	pipe_socketpair(int fds[2], int *is_pipe);
169275970Scyextern	void	close_all_beyond(int);
170275970Scyextern	void	close_all_except(int);
171275970Scyextern	void	kill_asyncio	(int);
172275970Scy#endif
173275970Scy
174298695Sdelphijextern void worker_global_lock(int inOrOut);
175298695Sdelphij
176275970Scy# ifdef WORK_PIPE
177275970Scytypedef	void	(*addremove_io_fd_func)(int, int, int);
178275970Scyextern	addremove_io_fd_func		addremove_io_fd;
179275970Scy# else
180275970Scyextern	void	handle_blocking_resp_sem(void *);
181275970Scytypedef	void	(*addremove_io_semaphore_func)(sem_ref, int);
182275970Scyextern	addremove_io_semaphore_func	addremove_io_semaphore;
183275970Scy# endif
184275970Scy
185275970Scy# ifdef WORK_FORK
186275970Scyextern	int				worker_process;
187275970Scy# endif
188275970Scy
189275970Scy#endif	/* WORKER */
190275970Scy
191275970Scy#if defined(HAVE_DROPROOT) && defined(WORK_FORK)
192275970Scyextern void	fork_deferred_worker(void);
193275970Scy#else
194275970Scy# define	fork_deferred_worker()	do {} while (0)
195275970Scy#endif
196275970Scy
197275970Scy#endif	/* !NTP_WORKER_H */
198