1/* $NetBSD: ntp_worker.h,v 1.6 2020/05/25 20:47:20 christos Exp $ */ 2 3/* 4 * ntp_worker.h 5 */ 6 7#ifndef NTP_WORKER_H 8#define NTP_WORKER_H 9 10#include "ntp_workimpl.h" 11 12#ifdef WORKER 13# if defined(WORK_THREAD) && defined(WORK_PIPE) 14# ifdef HAVE_SEMAPHORE_H 15# include <semaphore.h> 16# endif 17# endif 18#include "ntp_stdlib.h" 19 20/* #define TEST_BLOCKING_WORKER */ /* ntp_config.c ntp_intres.c */ 21 22typedef enum blocking_work_req_tag { 23 BLOCKING_GETNAMEINFO, 24 BLOCKING_GETADDRINFO, 25} blocking_work_req; 26 27typedef void (*blocking_work_callback)(blocking_work_req, void *, size_t, void *); 28 29typedef enum blocking_magic_sig_e { 30 BLOCKING_REQ_MAGIC = 0x510c7ecf, 31 BLOCKING_RESP_MAGIC = 0x510c7e54, 32} blocking_magic_sig; 33 34/* 35 * The same header is used for both requests to and responses from 36 * the child. In the child, done_func and context are opaque. 37 */ 38typedef struct blocking_pipe_header_tag { 39 size_t octets; 40 blocking_magic_sig magic_sig; 41 blocking_work_req rtype; 42 u_int child_idx; 43 blocking_work_callback done_func; 44 void * context; 45} blocking_pipe_header; 46 47# ifdef WORK_THREAD 48# ifdef SYS_WINNT 49typedef struct { HANDLE thnd; } thread_type; 50typedef struct { HANDLE shnd; } sema_type; 51# else 52typedef pthread_t thread_type; 53typedef sem_t sema_type; 54# endif 55typedef thread_type *thr_ref; 56typedef sema_type *sem_ref; 57# endif 58 59/* 60 * 61 */ 62#if defined(WORK_FORK) 63 64typedef struct blocking_child_tag { 65 int reusable; 66 int pid; 67 int req_write_pipe; /* parent */ 68 int resp_read_pipe; 69 void * resp_read_ctx; 70 int req_read_pipe; /* child */ 71 int resp_write_pipe; 72 int ispipe; 73 volatile u_int resp_ready_seen; /* signal/scan */ 74 volatile u_int resp_ready_done; /* consumer/mainloop */ 75} blocking_child; 76 77#elif defined(WORK_THREAD) 78 79typedef struct blocking_child_tag { 80 /* 81 * blocking workitems and blocking_responses are 82 * dynamically-sized one-dimensional arrays of pointers to 83 * blocking worker requests and responses. 84 * 85 * IMPORTANT: This structure is shared between threads, and all 86 * access that is not atomic (especially queue operations) must 87 * hold the 'accesslock' semaphore to avoid data races. 88 * 89 * The resource management (thread/semaphore 90 * creation/destruction) functions and functions just testing a 91 * handle are safe because these are only changed by the main 92 * thread when no worker is running on the same data structure. 93 */ 94 int reusable; 95 sem_ref accesslock; /* shared access lock */ 96 thr_ref thread_ref; /* thread 'handle' */ 97 98 /* the reuest queue */ 99 blocking_pipe_header ** volatile 100 workitems; 101 volatile size_t workitems_alloc; 102 size_t head_workitem; /* parent */ 103 size_t tail_workitem; /* child */ 104 sem_ref workitems_pending; /* signalling */ 105 106 /* the response queue */ 107 blocking_pipe_header ** volatile 108 responses; 109 volatile size_t responses_alloc; 110 size_t head_response; /* child */ 111 size_t tail_response; /* parent */ 112 113 /* event handles / sem_t pointers */ 114 sem_ref wake_scheduled_sleep; 115 116 /* some systems use a pipe for notification, others a semaphore. 117 * Both employ the queue above for the actual data transfer. 118 */ 119#ifdef WORK_PIPE 120 int resp_read_pipe; /* parent */ 121 int resp_write_pipe; /* child */ 122 int ispipe; 123 void * resp_read_ctx; /* child */ 124#else 125 sem_ref responses_pending; /* signalling */ 126#endif 127 volatile u_int resp_ready_seen; /* signal/scan */ 128 volatile u_int resp_ready_done; /* consumer/mainloop */ 129 sema_type sem_table[4]; 130 thread_type thr_table[1]; 131} blocking_child; 132 133#endif /* WORK_THREAD */ 134 135/* we need some global tag to indicate any blocking child may be ready: */ 136extern volatile u_int blocking_child_ready_seen;/* signal/scan */ 137extern volatile u_int blocking_child_ready_done;/* consumer/mainloop */ 138 139extern blocking_child ** blocking_children; 140extern size_t blocking_children_alloc; 141extern int worker_per_query; /* boolean */ 142extern int intres_req_pending; 143 144extern u_int available_blocking_child_slot(void); 145extern int queue_blocking_request(blocking_work_req, void *, 146 size_t, blocking_work_callback, 147 void *); 148extern int queue_blocking_response(blocking_child *, 149 blocking_pipe_header *, size_t, 150 const blocking_pipe_header *); 151extern void process_blocking_resp(blocking_child *); 152extern void harvest_blocking_responses(void); 153extern int send_blocking_req_internal(blocking_child *, 154 blocking_pipe_header *, 155 void *); 156extern int send_blocking_resp_internal(blocking_child *, 157 blocking_pipe_header *); 158extern blocking_pipe_header * 159 receive_blocking_req_internal(blocking_child *); 160extern blocking_pipe_header * 161 receive_blocking_resp_internal(blocking_child *); 162extern int blocking_child_common(blocking_child *); 163extern void exit_worker(int) 164 __attribute__ ((__noreturn__)); 165extern int worker_sleep(blocking_child *, time_t); 166extern void worker_idle_timer_fired(void); 167extern void interrupt_worker_sleep(void); 168extern int req_child_exit(blocking_child *); 169#ifndef HAVE_IO_COMPLETION_PORT 170extern int pipe_socketpair(int fds[2], int *is_pipe); 171extern void close_all_beyond(int); 172extern void close_all_except(int); 173extern void kill_asyncio (int); 174#endif 175 176extern void worker_global_lock(int inOrOut); 177 178# ifdef WORK_PIPE 179typedef void (*addremove_io_fd_func)(int, int, int); 180extern addremove_io_fd_func addremove_io_fd; 181# else 182extern void handle_blocking_resp_sem(void *); 183typedef void (*addremove_io_semaphore_func)(sem_ref, int); 184extern addremove_io_semaphore_func addremove_io_semaphore; 185# endif 186 187# ifdef WORK_FORK 188extern int worker_process; 189# endif 190 191#endif /* WORKER */ 192 193#if defined(HAVE_DROPROOT) && defined(WORK_FORK) 194extern void fork_deferred_worker(void); 195#else 196# define fork_deferred_worker() do {} while (0) 197#endif 198 199#endif /* !NTP_WORKER_H */ 200