xref: /freebsd/contrib/ntp/include/ntp_worker.h (revision 4990d495fcc77c51b3f46c91ba3a064b565afae0)
12b15cb3dSCy Schubert /*
22b15cb3dSCy Schubert  * ntp_worker.h
32b15cb3dSCy Schubert  */
42b15cb3dSCy Schubert 
52b15cb3dSCy Schubert #ifndef NTP_WORKER_H
62b15cb3dSCy Schubert #define NTP_WORKER_H
72b15cb3dSCy Schubert 
82b15cb3dSCy Schubert #include "ntp_workimpl.h"
92b15cb3dSCy Schubert 
102b15cb3dSCy Schubert #ifdef WORKER
112b15cb3dSCy Schubert # if defined(WORK_THREAD) && defined(WORK_PIPE)
122b15cb3dSCy Schubert #  ifdef HAVE_SEMAPHORE_H
132b15cb3dSCy Schubert #   include <semaphore.h>
142b15cb3dSCy Schubert #  endif
152b15cb3dSCy Schubert # endif
162b15cb3dSCy Schubert #include "ntp_stdlib.h"
172b15cb3dSCy Schubert 
182b15cb3dSCy Schubert /* #define TEST_BLOCKING_WORKER */	/* ntp_config.c ntp_intres.c */
192b15cb3dSCy Schubert 
202b15cb3dSCy Schubert typedef enum blocking_work_req_tag {
212b15cb3dSCy Schubert 	BLOCKING_GETNAMEINFO,
222b15cb3dSCy Schubert 	BLOCKING_GETADDRINFO,
232b15cb3dSCy Schubert } blocking_work_req;
242b15cb3dSCy Schubert 
252b15cb3dSCy Schubert typedef void (*blocking_work_callback)(blocking_work_req, void *, size_t, void *);
262b15cb3dSCy Schubert 
272b15cb3dSCy Schubert typedef enum blocking_magic_sig_e {
282b15cb3dSCy Schubert 	BLOCKING_REQ_MAGIC  = 0x510c7ecf,
292b15cb3dSCy Schubert 	BLOCKING_RESP_MAGIC = 0x510c7e54,
302b15cb3dSCy Schubert } blocking_magic_sig;
312b15cb3dSCy Schubert 
322b15cb3dSCy Schubert /*
332b15cb3dSCy Schubert  * The same header is used for both requests to and responses from
342b15cb3dSCy Schubert  * the child.  In the child, done_func and context are opaque.
352b15cb3dSCy Schubert  */
362b15cb3dSCy Schubert typedef struct blocking_pipe_header_tag {
372b15cb3dSCy Schubert 	size_t			octets;
382b15cb3dSCy Schubert 	blocking_magic_sig	magic_sig;
392b15cb3dSCy Schubert 	blocking_work_req	rtype;
402b15cb3dSCy Schubert 	u_int			child_idx;
412b15cb3dSCy Schubert 	blocking_work_callback	done_func;
422b15cb3dSCy Schubert 	void *			context;
432b15cb3dSCy Schubert } blocking_pipe_header;
442b15cb3dSCy Schubert 
452b15cb3dSCy Schubert # ifdef WORK_THREAD
463311ff84SXin LI #  ifdef SYS_WINNT
473311ff84SXin LI typedef struct { HANDLE thnd; } thread_type;
483311ff84SXin LI typedef struct { HANDLE shnd; } sema_type;
492b15cb3dSCy Schubert #  else
503311ff84SXin LI typedef pthread_t	thread_type;
513311ff84SXin LI typedef sem_t		sema_type;
522b15cb3dSCy Schubert #  endif
533311ff84SXin LI typedef thread_type	*thr_ref;
543311ff84SXin LI typedef sema_type	*sem_ref;
552b15cb3dSCy Schubert # endif
562b15cb3dSCy Schubert 
572b15cb3dSCy Schubert /*
582b15cb3dSCy Schubert  *
592b15cb3dSCy Schubert  */
603311ff84SXin LI #if defined(WORK_FORK)
613311ff84SXin LI 
622b15cb3dSCy Schubert typedef struct blocking_child_tag {
632b15cb3dSCy Schubert 	int		reusable;
642b15cb3dSCy Schubert 	int		pid;
652b15cb3dSCy Schubert 	int		req_write_pipe;		/* parent */
662b15cb3dSCy Schubert 	int		resp_read_pipe;
672b15cb3dSCy Schubert 	void *		resp_read_ctx;
682b15cb3dSCy Schubert 	int		req_read_pipe;		/* child */
692b15cb3dSCy Schubert 	int		resp_write_pipe;
702b15cb3dSCy Schubert 	int		ispipe;
7168ba7e87SXin LI 	volatile u_int	resp_ready_seen;	/* signal/scan */
7268ba7e87SXin LI 	volatile u_int	resp_ready_done;	/* consumer/mainloop */
732b15cb3dSCy Schubert } blocking_child;
743311ff84SXin LI 
752b15cb3dSCy Schubert #elif defined(WORK_THREAD)
763311ff84SXin LI 
772b15cb3dSCy Schubert typedef struct blocking_child_tag {
782b15cb3dSCy Schubert 	/*
7968ba7e87SXin LI 	 * blocking workitems and blocking_responses are
8068ba7e87SXin LI 	 * dynamically-sized one-dimensional arrays of pointers to
8168ba7e87SXin LI 	 * blocking worker requests and responses.
823311ff84SXin LI 	 *
8368ba7e87SXin LI 	 * IMPORTANT: This structure is shared between threads, and all
8468ba7e87SXin LI 	 * access that is not atomic (especially queue operations) must
8568ba7e87SXin LI 	 * hold the 'accesslock' semaphore to avoid data races.
863311ff84SXin LI 	 *
8768ba7e87SXin LI 	 * The resource management (thread/semaphore
8868ba7e87SXin LI 	 * creation/destruction) functions and functions just testing a
8968ba7e87SXin LI 	 * handle are safe because these are only changed by the main
9068ba7e87SXin LI 	 * thread when no worker is running on the same data structure.
912b15cb3dSCy Schubert 	 */
922b15cb3dSCy Schubert 	int			reusable;
933311ff84SXin LI 	sem_ref			accesslock;	/* shared access lock */
943311ff84SXin LI 	thr_ref			thread_ref;	/* thread 'handle' */
953311ff84SXin LI 
963311ff84SXin LI 	/* the reuest queue */
973311ff84SXin LI 	blocking_pipe_header ** volatile
982b15cb3dSCy Schubert 				workitems;
992b15cb3dSCy Schubert 	volatile size_t		workitems_alloc;
1003311ff84SXin LI 	size_t			head_workitem;		/* parent */
1013311ff84SXin LI 	size_t			tail_workitem;		/* child */
1023311ff84SXin LI 	sem_ref			workitems_pending;	/* signalling */
1033311ff84SXin LI 
1043311ff84SXin LI 	/* the response queue */
1053311ff84SXin LI 	blocking_pipe_header ** volatile
1062b15cb3dSCy Schubert 				responses;
1072b15cb3dSCy Schubert 	volatile size_t		responses_alloc;
1083311ff84SXin LI 	size_t			head_response;		/* child */
1093311ff84SXin LI 	size_t			tail_response;		/* parent */
1103311ff84SXin LI 
1112b15cb3dSCy Schubert 	/* event handles / sem_t pointers */
1122b15cb3dSCy Schubert 	sem_ref			wake_scheduled_sleep;
1133311ff84SXin LI 
1143311ff84SXin LI 	/* some systems use a pipe for notification, others a semaphore.
1153311ff84SXin LI 	 * Both employ the queue above for the actual data transfer.
1163311ff84SXin LI 	 */
1172b15cb3dSCy Schubert #ifdef WORK_PIPE
1182b15cb3dSCy Schubert 	int			resp_read_pipe;		/* parent */
1192b15cb3dSCy Schubert 	int			resp_write_pipe;	/* child */
1202b15cb3dSCy Schubert 	int			ispipe;
1212b15cb3dSCy Schubert 	void *			resp_read_ctx;		/* child */
1222b15cb3dSCy Schubert #else
1233311ff84SXin LI 	sem_ref			responses_pending;	/* signalling */
1242b15cb3dSCy Schubert #endif
125*4990d495SXin LI 	volatile u_int		resp_ready_seen;	/* signal/scan */
126*4990d495SXin LI 	volatile u_int		resp_ready_done;	/* consumer/mainloop */
1273311ff84SXin LI 	sema_type		sem_table[4];
1283311ff84SXin LI 	thread_type		thr_table[1];
1292b15cb3dSCy Schubert } blocking_child;
1302b15cb3dSCy Schubert 
1312b15cb3dSCy Schubert #endif	/* WORK_THREAD */
1322b15cb3dSCy Schubert 
13368ba7e87SXin LI /* we need some global tag to indicate any blocking child may be ready: */
13468ba7e87SXin LI extern volatile u_int		blocking_child_ready_seen;/* signal/scan */
13568ba7e87SXin LI extern volatile u_int		blocking_child_ready_done;/* consumer/mainloop */
13668ba7e87SXin LI 
1372b15cb3dSCy Schubert extern	blocking_child **	blocking_children;
1382b15cb3dSCy Schubert extern	size_t			blocking_children_alloc;
1392b15cb3dSCy Schubert extern	int			worker_per_query;	/* boolean */
1402b15cb3dSCy Schubert extern	int			intres_req_pending;
1412b15cb3dSCy Schubert 
1422b15cb3dSCy Schubert extern	u_int	available_blocking_child_slot(void);
1432b15cb3dSCy Schubert extern	int	queue_blocking_request(blocking_work_req, void *,
1442b15cb3dSCy Schubert 				       size_t, blocking_work_callback,
1452b15cb3dSCy Schubert 				       void *);
1462b15cb3dSCy Schubert extern	int	queue_blocking_response(blocking_child *,
1472b15cb3dSCy Schubert 					blocking_pipe_header *, size_t,
1482b15cb3dSCy Schubert 					const blocking_pipe_header *);
1492b15cb3dSCy Schubert extern	void	process_blocking_resp(blocking_child *);
15068ba7e87SXin LI extern	void	harvest_blocking_responses(void);
1512b15cb3dSCy Schubert extern	int	send_blocking_req_internal(blocking_child *,
1522b15cb3dSCy Schubert 					   blocking_pipe_header *,
1532b15cb3dSCy Schubert 					   void *);
1542b15cb3dSCy Schubert extern	int	send_blocking_resp_internal(blocking_child *,
1552b15cb3dSCy Schubert 					    blocking_pipe_header *);
1562b15cb3dSCy Schubert extern	blocking_pipe_header *
1572b15cb3dSCy Schubert 		receive_blocking_req_internal(blocking_child *);
1582b15cb3dSCy Schubert extern	blocking_pipe_header *
1592b15cb3dSCy Schubert 		receive_blocking_resp_internal(blocking_child *);
1602b15cb3dSCy Schubert extern	int	blocking_child_common(blocking_child *);
1612b15cb3dSCy Schubert extern	void	exit_worker(int)
1622b15cb3dSCy Schubert 			__attribute__ ((__noreturn__));
1632b15cb3dSCy Schubert extern	int	worker_sleep(blocking_child *, time_t);
1642b15cb3dSCy Schubert extern	void	worker_idle_timer_fired(void);
1652b15cb3dSCy Schubert extern	void	interrupt_worker_sleep(void);
1662b15cb3dSCy Schubert extern	int	req_child_exit(blocking_child *);
1672b15cb3dSCy Schubert #ifndef HAVE_IO_COMPLETION_PORT
1682b15cb3dSCy Schubert extern	int	pipe_socketpair(int fds[2], int *is_pipe);
1692b15cb3dSCy Schubert extern	void	close_all_beyond(int);
1702b15cb3dSCy Schubert extern	void	close_all_except(int);
1712b15cb3dSCy Schubert extern	void	kill_asyncio	(int);
1722b15cb3dSCy Schubert #endif
1732b15cb3dSCy Schubert 
174*4990d495SXin LI extern void worker_global_lock(int inOrOut);
175*4990d495SXin LI 
1762b15cb3dSCy Schubert # ifdef WORK_PIPE
1772b15cb3dSCy Schubert typedef	void	(*addremove_io_fd_func)(int, int, int);
1782b15cb3dSCy Schubert extern	addremove_io_fd_func		addremove_io_fd;
1792b15cb3dSCy Schubert # else
1802b15cb3dSCy Schubert extern	void	handle_blocking_resp_sem(void *);
1812b15cb3dSCy Schubert typedef	void	(*addremove_io_semaphore_func)(sem_ref, int);
1822b15cb3dSCy Schubert extern	addremove_io_semaphore_func	addremove_io_semaphore;
1832b15cb3dSCy Schubert # endif
1842b15cb3dSCy Schubert 
1852b15cb3dSCy Schubert # ifdef WORK_FORK
1862b15cb3dSCy Schubert extern	int				worker_process;
1872b15cb3dSCy Schubert # endif
1882b15cb3dSCy Schubert 
1892b15cb3dSCy Schubert #endif	/* WORKER */
1902b15cb3dSCy Schubert 
1912b15cb3dSCy Schubert #if defined(HAVE_DROPROOT) && defined(WORK_FORK)
1922b15cb3dSCy Schubert extern void	fork_deferred_worker(void);
1932b15cb3dSCy Schubert #else
1942b15cb3dSCy Schubert # define	fork_deferred_worker()	do {} while (0)
1952b15cb3dSCy Schubert #endif
1962b15cb3dSCy Schubert 
1972b15cb3dSCy Schubert #endif	/* !NTP_WORKER_H */
198