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