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