1275970Scy/* 2275970Scy * ntp_worker.h 3275970Scy */ 4275970Scy 5275970Scy#ifndef NTP_WORKER_H 6275970Scy#define NTP_WORKER_H 7275970Scy 8275970Scy#include "ntp_workimpl.h" 9275970Scy 10275970Scy#ifdef WORKER 11275970Scy# if defined(WORK_THREAD) && defined(WORK_PIPE) 12275970Scy# ifdef HAVE_SEMAPHORE_H 13275970Scy# include <semaphore.h> 14275970Scy# endif 15275970Scy# endif 16275970Scy#include "ntp_stdlib.h" 17275970Scy 18275970Scy/* #define TEST_BLOCKING_WORKER */ /* ntp_config.c ntp_intres.c */ 19275970Scy 20275970Scytypedef enum blocking_work_req_tag { 21275970Scy BLOCKING_GETNAMEINFO, 22275970Scy BLOCKING_GETADDRINFO, 23275970Scy} blocking_work_req; 24275970Scy 25275970Scytypedef void (*blocking_work_callback)(blocking_work_req, void *, size_t, void *); 26275970Scy 27275970Scytypedef enum blocking_magic_sig_e { 28275970Scy BLOCKING_REQ_MAGIC = 0x510c7ecf, 29275970Scy BLOCKING_RESP_MAGIC = 0x510c7e54, 30275970Scy} blocking_magic_sig; 31275970Scy 32275970Scy/* 33275970Scy * The same header is used for both requests to and responses from 34275970Scy * the child. In the child, done_func and context are opaque. 35275970Scy */ 36275970Scytypedef struct blocking_pipe_header_tag { 37275970Scy size_t octets; 38275970Scy blocking_magic_sig magic_sig; 39275970Scy blocking_work_req rtype; 40275970Scy u_int child_idx; 41275970Scy blocking_work_callback done_func; 42275970Scy void * context; 43275970Scy} blocking_pipe_header; 44275970Scy 45275970Scy# ifdef WORK_THREAD 46293423Sdelphij# ifdef SYS_WINNT 47293423Sdelphijtypedef struct { HANDLE thnd; } thread_type; 48293423Sdelphijtypedef struct { HANDLE shnd; } sema_type; 49275970Scy# else 50293423Sdelphijtypedef pthread_t thread_type; 51293423Sdelphijtypedef sem_t sema_type; 52275970Scy# endif 53293423Sdelphijtypedef thread_type *thr_ref; 54293423Sdelphijtypedef sema_type *sem_ref; 55275970Scy# endif 56275970Scy 57275970Scy/* 58275970Scy * 59275970Scy */ 60293423Sdelphij#if defined(WORK_FORK) 61293423Sdelphij 62275970Scytypedef struct blocking_child_tag { 63294554Sdelphij int reusable; 64294554Sdelphij int pid; 65294554Sdelphij int req_write_pipe; /* parent */ 66294554Sdelphij int resp_read_pipe; 67294554Sdelphij void * resp_read_ctx; 68294554Sdelphij int req_read_pipe; /* child */ 69294554Sdelphij int resp_write_pipe; 70294554Sdelphij int ispipe; 71294554Sdelphij volatile u_int resp_ready_seen; /* signal/scan */ 72294554Sdelphij volatile u_int resp_ready_done; /* consumer/mainloop */ 73275970Scy} blocking_child; 74293423Sdelphij 75275970Scy#elif defined(WORK_THREAD) 76293423Sdelphij 77275970Scytypedef struct blocking_child_tag { 78294554Sdelphij /* 79294554Sdelphij * blocking workitems and blocking_responses are 80294554Sdelphij * dynamically-sized one-dimensional arrays of pointers to 81294554Sdelphij * blocking worker requests and responses. 82294554Sdelphij * 83294554Sdelphij * IMPORTANT: This structure is shared between threads, and all 84294554Sdelphij * access that is not atomic (especially queue operations) must 85294554Sdelphij * hold the 'accesslock' semaphore to avoid data races. 86294554Sdelphij * 87294554Sdelphij * The resource management (thread/semaphore 88294554Sdelphij * creation/destruction) functions and functions just testing a 89294554Sdelphij * handle are safe because these are only changed by the main 90294554Sdelphij * thread when no worker is running on the same data structure. 91294554Sdelphij */ 92275970Scy int reusable; 93293423Sdelphij sem_ref accesslock; /* shared access lock */ 94293423Sdelphij thr_ref thread_ref; /* thread 'handle' */ 95293423Sdelphij 96293423Sdelphij /* the reuest queue */ 97293423Sdelphij blocking_pipe_header ** volatile 98275970Scy workitems; 99275970Scy volatile size_t workitems_alloc; 100293423Sdelphij size_t head_workitem; /* parent */ 101293423Sdelphij size_t tail_workitem; /* child */ 102293423Sdelphij sem_ref workitems_pending; /* signalling */ 103293423Sdelphij 104293423Sdelphij /* the response queue */ 105293423Sdelphij blocking_pipe_header ** volatile 106275970Scy responses; 107275970Scy volatile size_t responses_alloc; 108293423Sdelphij size_t head_response; /* child */ 109293423Sdelphij size_t tail_response; /* parent */ 110293423Sdelphij 111275970Scy /* event handles / sem_t pointers */ 112275970Scy sem_ref wake_scheduled_sleep; 113293423Sdelphij 114293423Sdelphij /* some systems use a pipe for notification, others a semaphore. 115293423Sdelphij * Both employ the queue above for the actual data transfer. 116293423Sdelphij */ 117275970Scy#ifdef WORK_PIPE 118293423Sdelphij int resp_read_pipe; /* parent */ 119293423Sdelphij int resp_write_pipe; /* child */ 120275970Scy int ispipe; 121293423Sdelphij void * resp_read_ctx; /* child */ 122275970Scy#else 123293423Sdelphij sem_ref responses_pending; /* signalling */ 124275970Scy#endif 125298695Sdelphij volatile u_int resp_ready_seen; /* signal/scan */ 126298695Sdelphij volatile u_int resp_ready_done; /* consumer/mainloop */ 127293423Sdelphij sema_type sem_table[4]; 128293423Sdelphij thread_type thr_table[1]; 129275970Scy} blocking_child; 130275970Scy 131275970Scy#endif /* WORK_THREAD */ 132275970Scy 133294554Sdelphij/* we need some global tag to indicate any blocking child may be ready: */ 134294554Sdelphijextern volatile u_int blocking_child_ready_seen;/* signal/scan */ 135294554Sdelphijextern volatile u_int blocking_child_ready_done;/* consumer/mainloop */ 136294554Sdelphij 137275970Scyextern blocking_child ** blocking_children; 138275970Scyextern size_t blocking_children_alloc; 139275970Scyextern int worker_per_query; /* boolean */ 140275970Scyextern int intres_req_pending; 141275970Scy 142275970Scyextern u_int available_blocking_child_slot(void); 143275970Scyextern int queue_blocking_request(blocking_work_req, void *, 144275970Scy size_t, blocking_work_callback, 145275970Scy void *); 146293423Sdelphijextern int queue_blocking_response(blocking_child *, 147275970Scy blocking_pipe_header *, size_t, 148275970Scy const blocking_pipe_header *); 149275970Scyextern void process_blocking_resp(blocking_child *); 150294554Sdelphijextern void harvest_blocking_responses(void); 151275970Scyextern int send_blocking_req_internal(blocking_child *, 152275970Scy blocking_pipe_header *, 153275970Scy void *); 154275970Scyextern int send_blocking_resp_internal(blocking_child *, 155275970Scy blocking_pipe_header *); 156275970Scyextern blocking_pipe_header * 157275970Scy receive_blocking_req_internal(blocking_child *); 158275970Scyextern blocking_pipe_header * 159275970Scy receive_blocking_resp_internal(blocking_child *); 160275970Scyextern int blocking_child_common(blocking_child *); 161275970Scyextern void exit_worker(int) 162275970Scy __attribute__ ((__noreturn__)); 163275970Scyextern int worker_sleep(blocking_child *, time_t); 164275970Scyextern void worker_idle_timer_fired(void); 165275970Scyextern void interrupt_worker_sleep(void); 166275970Scyextern int req_child_exit(blocking_child *); 167275970Scy#ifndef HAVE_IO_COMPLETION_PORT 168275970Scyextern int pipe_socketpair(int fds[2], int *is_pipe); 169275970Scyextern void close_all_beyond(int); 170275970Scyextern void close_all_except(int); 171275970Scyextern void kill_asyncio (int); 172275970Scy#endif 173275970Scy 174298695Sdelphijextern void worker_global_lock(int inOrOut); 175298695Sdelphij 176275970Scy# ifdef WORK_PIPE 177275970Scytypedef void (*addremove_io_fd_func)(int, int, int); 178275970Scyextern addremove_io_fd_func addremove_io_fd; 179275970Scy# else 180275970Scyextern void handle_blocking_resp_sem(void *); 181275970Scytypedef void (*addremove_io_semaphore_func)(sem_ref, int); 182275970Scyextern addremove_io_semaphore_func addremove_io_semaphore; 183275970Scy# endif 184275970Scy 185275970Scy# ifdef WORK_FORK 186275970Scyextern int worker_process; 187275970Scy# endif 188275970Scy 189275970Scy#endif /* WORKER */ 190275970Scy 191275970Scy#if defined(HAVE_DROPROOT) && defined(WORK_FORK) 192275970Scyextern void fork_deferred_worker(void); 193275970Scy#else 194275970Scy# define fork_deferred_worker() do {} while (0) 195275970Scy#endif 196275970Scy 197275970Scy#endif /* !NTP_WORKER_H */ 198