xref: /freebsd/contrib/ntp/include/ntp_worker.h (revision fafb1ee7bdc5d8a7d07cd03b2fb0bbb76f7a9d7c)
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 
20 typedef enum blocking_work_req_tag {
21 	BLOCKING_GETNAMEINFO,
22 	BLOCKING_GETADDRINFO,
23 } blocking_work_req;
24 
25 typedef void (*blocking_work_callback)(blocking_work_req, void *, size_t, void *);
26 
27 typedef 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  */
36 typedef 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
47 typedef struct { HANDLE thnd; } thread_type;
48 typedef struct { HANDLE shnd; } sema_type;
49 #  else
50 typedef pthread_t	thread_type;
51 typedef sem_t		sema_type;
52 #  endif
53 typedef thread_type	*thr_ref;
54 typedef sema_type	*sem_ref;
55 # endif
56 
57 /*
58  *
59  */
60 #if defined(WORK_FORK)
61 
62 typedef 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 } blocking_child;
72 
73 #elif defined(WORK_THREAD)
74 
75 typedef struct blocking_child_tag {
76 /*
77  * blocking workitems and blocking_responses are dynamically-sized
78  * one-dimensional arrays of pointers to blocking worker requests and
79  * responses.
80  *
81  * IMPORTANT: This structure is shared between threads, and all access
82  * that is not atomic (especially queue operations) must hold the
83  * 'accesslock' semaphore to avoid data races.
84  *
85  * The resource management (thread/semaphore creation/destruction)
86  * functions and functions just testing a handle are safe because these
87  * are only changed by the main thread when no worker is running on the
88  * same data structure.
89  */
90 	int			reusable;
91 	sem_ref			accesslock;	/* shared access lock */
92 	thr_ref			thread_ref;	/* thread 'handle' */
93 
94 	/* the reuest queue */
95 	blocking_pipe_header ** volatile
96 				workitems;
97 	volatile size_t		workitems_alloc;
98 	size_t			head_workitem;		/* parent */
99 	size_t			tail_workitem;		/* child */
100 	sem_ref			workitems_pending;	/* signalling */
101 
102 	/* the response queue */
103 	blocking_pipe_header ** volatile
104 				responses;
105 	volatile size_t		responses_alloc;
106 	size_t			head_response;		/* child */
107 	size_t			tail_response;		/* parent */
108 
109 	/* event handles / sem_t pointers */
110 	sem_ref			wake_scheduled_sleep;
111 
112 	/* some systems use a pipe for notification, others a semaphore.
113 	 * Both employ the queue above for the actual data transfer.
114 	 */
115 #ifdef WORK_PIPE
116 	int			resp_read_pipe;		/* parent */
117 	int			resp_write_pipe;	/* child */
118 	int			ispipe;
119 	void *			resp_read_ctx;		/* child */
120 #else
121 	sem_ref			responses_pending;	/* signalling */
122 #endif
123 	sema_type		sem_table[4];
124 	thread_type		thr_table[1];
125 } blocking_child;
126 
127 #endif	/* WORK_THREAD */
128 
129 extern	blocking_child **	blocking_children;
130 extern	size_t			blocking_children_alloc;
131 extern	int			worker_per_query;	/* boolean */
132 extern	int			intres_req_pending;
133 
134 extern	u_int	available_blocking_child_slot(void);
135 extern	int	queue_blocking_request(blocking_work_req, void *,
136 				       size_t, blocking_work_callback,
137 				       void *);
138 extern	int	queue_blocking_response(blocking_child *,
139 					blocking_pipe_header *, size_t,
140 					const blocking_pipe_header *);
141 extern	void	process_blocking_resp(blocking_child *);
142 extern	int	send_blocking_req_internal(blocking_child *,
143 					   blocking_pipe_header *,
144 					   void *);
145 extern	int	send_blocking_resp_internal(blocking_child *,
146 					    blocking_pipe_header *);
147 extern	blocking_pipe_header *
148 		receive_blocking_req_internal(blocking_child *);
149 extern	blocking_pipe_header *
150 		receive_blocking_resp_internal(blocking_child *);
151 extern	int	blocking_child_common(blocking_child *);
152 extern	void	exit_worker(int)
153 			__attribute__ ((__noreturn__));
154 extern	int	worker_sleep(blocking_child *, time_t);
155 extern	void	worker_idle_timer_fired(void);
156 extern	void	interrupt_worker_sleep(void);
157 extern	int	req_child_exit(blocking_child *);
158 #ifndef HAVE_IO_COMPLETION_PORT
159 extern	int	pipe_socketpair(int fds[2], int *is_pipe);
160 extern	void	close_all_beyond(int);
161 extern	void	close_all_except(int);
162 extern	void	kill_asyncio	(int);
163 #endif
164 
165 # ifdef WORK_PIPE
166 typedef	void	(*addremove_io_fd_func)(int, int, int);
167 extern	addremove_io_fd_func		addremove_io_fd;
168 # else
169 extern	void	handle_blocking_resp_sem(void *);
170 typedef	void	(*addremove_io_semaphore_func)(sem_ref, int);
171 extern	addremove_io_semaphore_func	addremove_io_semaphore;
172 # endif
173 
174 # ifdef WORK_FORK
175 extern	int				worker_process;
176 # endif
177 
178 #endif	/* WORKER */
179 
180 #if defined(HAVE_DROPROOT) && defined(WORK_FORK)
181 extern void	fork_deferred_worker(void);
182 #else
183 # define	fork_deferred_worker()	do {} while (0)
184 #endif
185 
186 #endif	/* !NTP_WORKER_H */
187