xref: /freebsd/contrib/ntp/include/ntp_worker.h (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
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 	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 
77 typedef 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 #else
123 	sem_ref			responses_pending;	/* signalling */
124 #endif
125 	volatile u_int		resp_ready_seen;	/* signal/scan */
126 	volatile u_int		resp_ready_done;	/* consumer/mainloop */
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: */
134 extern volatile u_int		blocking_child_ready_seen;/* signal/scan */
135 extern volatile u_int		blocking_child_ready_done;/* consumer/mainloop */
136 
137 extern	blocking_child **	blocking_children;
138 extern	size_t			blocking_children_alloc;
139 extern	int			worker_per_query;	/* boolean */
140 extern	int			intres_req_pending;
141 
142 extern	u_int	available_blocking_child_slot(void);
143 extern	int	queue_blocking_request(blocking_work_req, void *,
144 				       size_t, blocking_work_callback,
145 				       void *);
146 extern	int	queue_blocking_response(blocking_child *,
147 					blocking_pipe_header *, size_t,
148 					const blocking_pipe_header *);
149 extern	void	process_blocking_resp(blocking_child *);
150 extern	void	harvest_blocking_responses(void);
151 extern	int	send_blocking_req_internal(blocking_child *,
152 					   blocking_pipe_header *,
153 					   void *);
154 extern	int	send_blocking_resp_internal(blocking_child *,
155 					    blocking_pipe_header *);
156 extern	blocking_pipe_header *
157 		receive_blocking_req_internal(blocking_child *);
158 extern	blocking_pipe_header *
159 		receive_blocking_resp_internal(blocking_child *);
160 extern	int	blocking_child_common(blocking_child *);
161 extern	void	exit_worker(int)
162 			__attribute__ ((__noreturn__));
163 extern	int	worker_sleep(blocking_child *, time_t);
164 extern	void	worker_idle_timer_fired(void);
165 extern	void	interrupt_worker_sleep(void);
166 extern	int	req_child_exit(blocking_child *);
167 #ifndef HAVE_IO_COMPLETION_PORT
168 extern	int	pipe_socketpair(int fds[2], int *is_pipe);
169 extern	void	close_all_beyond(int);
170 extern	void	close_all_except(int);
171 extern	void	kill_asyncio	(int);
172 #endif
173 
174 extern void worker_global_lock(int inOrOut);
175 
176 # ifdef WORK_PIPE
177 typedef	void	(*addremove_io_fd_func)(int, int, int);
178 extern	addremove_io_fd_func		addremove_io_fd;
179 # else
180 extern	void	handle_blocking_resp_sem(void *);
181 typedef	void	(*addremove_io_semaphore_func)(sem_ref, int);
182 extern	addremove_io_semaphore_func	addremove_io_semaphore;
183 # endif
184 
185 # ifdef WORK_FORK
186 extern	int				worker_process;
187 # endif
188 
189 #endif	/* WORKER */
190 
191 #if defined(HAVE_DROPROOT) && defined(WORK_FORK)
192 extern void	fork_deferred_worker(void);
193 #else
194 # define	fork_deferred_worker()	do {} while (0)
195 #endif
196 
197 #endif	/* !NTP_WORKER_H */
198