1290001Sglebius/* 2290001Sglebius * ntp_worker.h 3290001Sglebius */ 4290001Sglebius 5290001Sglebius#ifndef NTP_WORKER_H 6290001Sglebius#define NTP_WORKER_H 7290001Sglebius 8290001Sglebius#include "ntp_workimpl.h" 9290001Sglebius 10290001Sglebius#ifdef WORKER 11290001Sglebius# if defined(WORK_THREAD) && defined(WORK_PIPE) 12290001Sglebius# ifdef HAVE_SEMAPHORE_H 13290001Sglebius# include <semaphore.h> 14290001Sglebius# endif 15290001Sglebius# endif 16290001Sglebius#include "ntp_stdlib.h" 17290001Sglebius 18290001Sglebius/* #define TEST_BLOCKING_WORKER */ /* ntp_config.c ntp_intres.c */ 19290001Sglebius 20290001Sglebiustypedef enum blocking_work_req_tag { 21290001Sglebius BLOCKING_GETNAMEINFO, 22290001Sglebius BLOCKING_GETADDRINFO, 23290001Sglebius} blocking_work_req; 24290001Sglebius 25290001Sglebiustypedef void (*blocking_work_callback)(blocking_work_req, void *, size_t, void *); 26290001Sglebius 27290001Sglebiustypedef enum blocking_magic_sig_e { 28290001Sglebius BLOCKING_REQ_MAGIC = 0x510c7ecf, 29290001Sglebius BLOCKING_RESP_MAGIC = 0x510c7e54, 30290001Sglebius} blocking_magic_sig; 31290001Sglebius 32290001Sglebius/* 33290001Sglebius * The same header is used for both requests to and responses from 34290001Sglebius * the child. In the child, done_func and context are opaque. 35290001Sglebius */ 36290001Sglebiustypedef struct blocking_pipe_header_tag { 37290001Sglebius size_t octets; 38290001Sglebius blocking_magic_sig magic_sig; 39290001Sglebius blocking_work_req rtype; 40290001Sglebius u_int child_idx; 41290001Sglebius blocking_work_callback done_func; 42290001Sglebius void * context; 43290001Sglebius} blocking_pipe_header; 44290001Sglebius 45290001Sglebius# ifdef WORK_THREAD 46293896Sglebius# ifdef SYS_WINNT 47293896Sglebiustypedef struct { HANDLE thnd; } thread_type; 48293896Sglebiustypedef struct { HANDLE shnd; } sema_type; 49290001Sglebius# else 50293896Sglebiustypedef pthread_t thread_type; 51293896Sglebiustypedef sem_t sema_type; 52290001Sglebius# endif 53293896Sglebiustypedef thread_type *thr_ref; 54293896Sglebiustypedef sema_type *sem_ref; 55290001Sglebius# endif 56290001Sglebius 57290001Sglebius/* 58290001Sglebius * 59290001Sglebius */ 60293896Sglebius#if defined(WORK_FORK) 61293896Sglebius 62290001Sglebiustypedef struct blocking_child_tag { 63294905Sdelphij int reusable; 64294905Sdelphij int pid; 65294905Sdelphij int req_write_pipe; /* parent */ 66294905Sdelphij int resp_read_pipe; 67294905Sdelphij void * resp_read_ctx; 68294905Sdelphij int req_read_pipe; /* child */ 69294905Sdelphij int resp_write_pipe; 70294905Sdelphij int ispipe; 71294905Sdelphij volatile u_int resp_ready_seen; /* signal/scan */ 72294905Sdelphij volatile u_int resp_ready_done; /* consumer/mainloop */ 73290001Sglebius} blocking_child; 74293896Sglebius 75290001Sglebius#elif defined(WORK_THREAD) 76293896Sglebius 77290001Sglebiustypedef struct blocking_child_tag { 78294905Sdelphij /* 79294905Sdelphij * blocking workitems and blocking_responses are 80294905Sdelphij * dynamically-sized one-dimensional arrays of pointers to 81294905Sdelphij * blocking worker requests and responses. 82294905Sdelphij * 83294905Sdelphij * IMPORTANT: This structure is shared between threads, and all 84294905Sdelphij * access that is not atomic (especially queue operations) must 85294905Sdelphij * hold the 'accesslock' semaphore to avoid data races. 86294905Sdelphij * 87294905Sdelphij * The resource management (thread/semaphore 88294905Sdelphij * creation/destruction) functions and functions just testing a 89294905Sdelphij * handle are safe because these are only changed by the main 90294905Sdelphij * thread when no worker is running on the same data structure. 91294905Sdelphij */ 92290001Sglebius int reusable; 93293896Sglebius sem_ref accesslock; /* shared access lock */ 94293896Sglebius thr_ref thread_ref; /* thread 'handle' */ 95293896Sglebius 96293896Sglebius /* the reuest queue */ 97293896Sglebius blocking_pipe_header ** volatile 98290001Sglebius workitems; 99290001Sglebius volatile size_t workitems_alloc; 100293896Sglebius size_t head_workitem; /* parent */ 101293896Sglebius size_t tail_workitem; /* child */ 102293896Sglebius sem_ref workitems_pending; /* signalling */ 103293896Sglebius 104293896Sglebius /* the response queue */ 105293896Sglebius blocking_pipe_header ** volatile 106290001Sglebius responses; 107290001Sglebius volatile size_t responses_alloc; 108293896Sglebius size_t head_response; /* child */ 109293896Sglebius size_t tail_response; /* parent */ 110293896Sglebius 111290001Sglebius /* event handles / sem_t pointers */ 112290001Sglebius sem_ref wake_scheduled_sleep; 113293896Sglebius 114293896Sglebius /* some systems use a pipe for notification, others a semaphore. 115293896Sglebius * Both employ the queue above for the actual data transfer. 116293896Sglebius */ 117290001Sglebius#ifdef WORK_PIPE 118293896Sglebius int resp_read_pipe; /* parent */ 119293896Sglebius int resp_write_pipe; /* child */ 120290001Sglebius int ispipe; 121293896Sglebius void * resp_read_ctx; /* child */ 122290001Sglebius#else 123293896Sglebius sem_ref responses_pending; /* signalling */ 124290001Sglebius#endif 125298770Sdelphij volatile u_int resp_ready_seen; /* signal/scan */ 126298770Sdelphij volatile u_int resp_ready_done; /* consumer/mainloop */ 127293896Sglebius sema_type sem_table[4]; 128293896Sglebius thread_type thr_table[1]; 129290001Sglebius} blocking_child; 130290001Sglebius 131290001Sglebius#endif /* WORK_THREAD */ 132290001Sglebius 133294905Sdelphij/* we need some global tag to indicate any blocking child may be ready: */ 134294905Sdelphijextern volatile u_int blocking_child_ready_seen;/* signal/scan */ 135294905Sdelphijextern volatile u_int blocking_child_ready_done;/* consumer/mainloop */ 136294905Sdelphij 137290001Sglebiusextern blocking_child ** blocking_children; 138290001Sglebiusextern size_t blocking_children_alloc; 139290001Sglebiusextern int worker_per_query; /* boolean */ 140290001Sglebiusextern int intres_req_pending; 141290001Sglebius 142290001Sglebiusextern u_int available_blocking_child_slot(void); 143290001Sglebiusextern int queue_blocking_request(blocking_work_req, void *, 144290001Sglebius size_t, blocking_work_callback, 145290001Sglebius void *); 146293896Sglebiusextern int queue_blocking_response(blocking_child *, 147290001Sglebius blocking_pipe_header *, size_t, 148290001Sglebius const blocking_pipe_header *); 149290001Sglebiusextern void process_blocking_resp(blocking_child *); 150294905Sdelphijextern void harvest_blocking_responses(void); 151290001Sglebiusextern int send_blocking_req_internal(blocking_child *, 152290001Sglebius blocking_pipe_header *, 153290001Sglebius void *); 154290001Sglebiusextern int send_blocking_resp_internal(blocking_child *, 155290001Sglebius blocking_pipe_header *); 156290001Sglebiusextern blocking_pipe_header * 157290001Sglebius receive_blocking_req_internal(blocking_child *); 158290001Sglebiusextern blocking_pipe_header * 159290001Sglebius receive_blocking_resp_internal(blocking_child *); 160290001Sglebiusextern int blocking_child_common(blocking_child *); 161290001Sglebiusextern void exit_worker(int) 162290001Sglebius __attribute__ ((__noreturn__)); 163290001Sglebiusextern int worker_sleep(blocking_child *, time_t); 164290001Sglebiusextern void worker_idle_timer_fired(void); 165290001Sglebiusextern void interrupt_worker_sleep(void); 166290001Sglebiusextern int req_child_exit(blocking_child *); 167290001Sglebius#ifndef HAVE_IO_COMPLETION_PORT 168290001Sglebiusextern int pipe_socketpair(int fds[2], int *is_pipe); 169290001Sglebiusextern void close_all_beyond(int); 170290001Sglebiusextern void close_all_except(int); 171290001Sglebiusextern void kill_asyncio (int); 172290001Sglebius#endif 173290001Sglebius 174298770Sdelphijextern void worker_global_lock(int inOrOut); 175298770Sdelphij 176290001Sglebius# ifdef WORK_PIPE 177290001Sglebiustypedef void (*addremove_io_fd_func)(int, int, int); 178290001Sglebiusextern addremove_io_fd_func addremove_io_fd; 179290001Sglebius# else 180290001Sglebiusextern void handle_blocking_resp_sem(void *); 181290001Sglebiustypedef void (*addremove_io_semaphore_func)(sem_ref, int); 182290001Sglebiusextern addremove_io_semaphore_func addremove_io_semaphore; 183290001Sglebius# endif 184290001Sglebius 185290001Sglebius# ifdef WORK_FORK 186290001Sglebiusextern int worker_process; 187290001Sglebius# endif 188290001Sglebius 189290001Sglebius#endif /* WORKER */ 190290001Sglebius 191290001Sglebius#if defined(HAVE_DROPROOT) && defined(WORK_FORK) 192290001Sglebiusextern void fork_deferred_worker(void); 193290001Sglebius#else 194290001Sglebius# define fork_deferred_worker() do {} while (0) 195290001Sglebius#endif 196290001Sglebius 197290001Sglebius#endif /* !NTP_WORKER_H */ 198