1/*	$NetBSD: ntp_worker.h,v 1.6 2020/05/25 20:47:20 christos Exp $	*/
2
3/*
4 * ntp_worker.h
5 */
6
7#ifndef NTP_WORKER_H
8#define NTP_WORKER_H
9
10#include "ntp_workimpl.h"
11
12#ifdef WORKER
13# if defined(WORK_THREAD) && defined(WORK_PIPE)
14#  ifdef HAVE_SEMAPHORE_H
15#   include <semaphore.h>
16#  endif
17# endif
18#include "ntp_stdlib.h"
19
20/* #define TEST_BLOCKING_WORKER */	/* ntp_config.c ntp_intres.c */
21
22typedef enum blocking_work_req_tag {
23	BLOCKING_GETNAMEINFO,
24	BLOCKING_GETADDRINFO,
25} blocking_work_req;
26
27typedef void (*blocking_work_callback)(blocking_work_req, void *, size_t, void *);
28
29typedef enum blocking_magic_sig_e {
30	BLOCKING_REQ_MAGIC  = 0x510c7ecf,
31	BLOCKING_RESP_MAGIC = 0x510c7e54,
32} blocking_magic_sig;
33
34/*
35 * The same header is used for both requests to and responses from
36 * the child.  In the child, done_func and context are opaque.
37 */
38typedef struct blocking_pipe_header_tag {
39	size_t			octets;
40	blocking_magic_sig	magic_sig;
41	blocking_work_req	rtype;
42	u_int			child_idx;
43	blocking_work_callback	done_func;
44	void *			context;
45} blocking_pipe_header;
46
47# ifdef WORK_THREAD
48#  ifdef SYS_WINNT
49typedef struct { HANDLE thnd; } thread_type;
50typedef struct { HANDLE shnd; } sema_type;
51#  else
52typedef pthread_t	thread_type;
53typedef sem_t		sema_type;
54#  endif
55typedef thread_type	*thr_ref;
56typedef sema_type	*sem_ref;
57# endif
58
59/*
60 *
61 */
62#if defined(WORK_FORK)
63
64typedef struct blocking_child_tag {
65	int		reusable;
66	int		pid;
67	int		req_write_pipe;		/* parent */
68	int		resp_read_pipe;
69	void *		resp_read_ctx;
70	int		req_read_pipe;		/* child */
71	int		resp_write_pipe;
72	int		ispipe;
73	volatile u_int	resp_ready_seen;	/* signal/scan */
74	volatile u_int	resp_ready_done;	/* consumer/mainloop */
75} blocking_child;
76
77#elif defined(WORK_THREAD)
78
79typedef struct blocking_child_tag {
80	/*
81	 * blocking workitems and blocking_responses are
82	 * dynamically-sized one-dimensional arrays of pointers to
83	 * blocking worker requests and responses.
84	 *
85	 * IMPORTANT: This structure is shared between threads, and all
86	 * access that is not atomic (especially queue operations) must
87	 * hold the 'accesslock' semaphore to avoid data races.
88	 *
89	 * The resource management (thread/semaphore
90	 * creation/destruction) functions and functions just testing a
91	 * handle are safe because these are only changed by the main
92	 * thread when no worker is running on the same data structure.
93	 */
94	int			reusable;
95	sem_ref			accesslock;	/* shared access lock */
96	thr_ref			thread_ref;	/* thread 'handle' */
97
98	/* the reuest queue */
99	blocking_pipe_header ** volatile
100				workitems;
101	volatile size_t		workitems_alloc;
102	size_t			head_workitem;		/* parent */
103	size_t			tail_workitem;		/* child */
104	sem_ref			workitems_pending;	/* signalling */
105
106	/* the response queue */
107	blocking_pipe_header ** volatile
108				responses;
109	volatile size_t		responses_alloc;
110	size_t			head_response;		/* child */
111	size_t			tail_response;		/* parent */
112
113	/* event handles / sem_t pointers */
114	sem_ref			wake_scheduled_sleep;
115
116	/* some systems use a pipe for notification, others a semaphore.
117	 * Both employ the queue above for the actual data transfer.
118	 */
119#ifdef WORK_PIPE
120	int			resp_read_pipe;		/* parent */
121	int			resp_write_pipe;	/* child */
122	int			ispipe;
123	void *			resp_read_ctx;		/* child */
124#else
125	sem_ref			responses_pending;	/* signalling */
126#endif
127	volatile u_int		resp_ready_seen;	/* signal/scan */
128	volatile u_int		resp_ready_done;	/* consumer/mainloop */
129	sema_type		sem_table[4];
130	thread_type		thr_table[1];
131} blocking_child;
132
133#endif	/* WORK_THREAD */
134
135/* we need some global tag to indicate any blocking child may be ready: */
136extern volatile u_int		blocking_child_ready_seen;/* signal/scan */
137extern volatile u_int		blocking_child_ready_done;/* consumer/mainloop */
138
139extern	blocking_child **	blocking_children;
140extern	size_t			blocking_children_alloc;
141extern	int			worker_per_query;	/* boolean */
142extern	int			intres_req_pending;
143
144extern	u_int	available_blocking_child_slot(void);
145extern	int	queue_blocking_request(blocking_work_req, void *,
146				       size_t, blocking_work_callback,
147				       void *);
148extern	int	queue_blocking_response(blocking_child *,
149					blocking_pipe_header *, size_t,
150					const blocking_pipe_header *);
151extern	void	process_blocking_resp(blocking_child *);
152extern	void	harvest_blocking_responses(void);
153extern	int	send_blocking_req_internal(blocking_child *,
154					   blocking_pipe_header *,
155					   void *);
156extern	int	send_blocking_resp_internal(blocking_child *,
157					    blocking_pipe_header *);
158extern	blocking_pipe_header *
159		receive_blocking_req_internal(blocking_child *);
160extern	blocking_pipe_header *
161		receive_blocking_resp_internal(blocking_child *);
162extern	int	blocking_child_common(blocking_child *);
163extern	void	exit_worker(int)
164			__attribute__ ((__noreturn__));
165extern	int	worker_sleep(blocking_child *, time_t);
166extern	void	worker_idle_timer_fired(void);
167extern	void	interrupt_worker_sleep(void);
168extern	int	req_child_exit(blocking_child *);
169#ifndef HAVE_IO_COMPLETION_PORT
170extern	int	pipe_socketpair(int fds[2], int *is_pipe);
171extern	void	close_all_beyond(int);
172extern	void	close_all_except(int);
173extern	void	kill_asyncio	(int);
174#endif
175
176extern void worker_global_lock(int inOrOut);
177
178# ifdef WORK_PIPE
179typedef	void	(*addremove_io_fd_func)(int, int, int);
180extern	addremove_io_fd_func		addremove_io_fd;
181# else
182extern	void	handle_blocking_resp_sem(void *);
183typedef	void	(*addremove_io_semaphore_func)(sem_ref, int);
184extern	addremove_io_semaphore_func	addremove_io_semaphore;
185# endif
186
187# ifdef WORK_FORK
188extern	int				worker_process;
189# endif
190
191#endif	/* WORKER */
192
193#if defined(HAVE_DROPROOT) && defined(WORK_FORK)
194extern void	fork_deferred_worker(void);
195#else
196# define	fork_deferred_worker()	do {} while (0)
197#endif
198
199#endif	/* !NTP_WORKER_H */
200