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