1 /* $NetBSD: ntp_worker.h,v 1.4 2016/01/08 21:35:35 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 22 typedef enum blocking_work_req_tag { 23 BLOCKING_GETNAMEINFO, 24 BLOCKING_GETADDRINFO, 25 } blocking_work_req; 26 27 typedef void (*blocking_work_callback)(blocking_work_req, void *, size_t, void *); 28 29 typedef 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 */ 38 typedef 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 49 typedef struct { HANDLE thnd; } thread_type; 50 typedef struct { HANDLE shnd; } sema_type; 51 # else 52 typedef pthread_t thread_type; 53 typedef sem_t sema_type; 54 # endif 55 typedef thread_type *thr_ref; 56 typedef sema_type *sem_ref; 57 # endif 58 59 /* 60 * 61 */ 62 #if defined(WORK_FORK) 63 64 typedef 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 } blocking_child; 74 75 #elif defined(WORK_THREAD) 76 77 typedef struct blocking_child_tag { 78 /* 79 * blocking workitems and blocking_responses are dynamically-sized 80 * one-dimensional arrays of pointers to blocking worker requests and 81 * responses. 82 * 83 * IMPORTANT: This structure is shared between threads, and all access 84 * that is not atomic (especially queue operations) must hold the 85 * 'accesslock' semaphore to avoid data races. 86 * 87 * The resource management (thread/semaphore creation/destruction) 88 * functions and functions just testing a handle are safe because these 89 * are only changed by the main thread when no worker is running on the 90 * 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 #else 123 sem_ref responses_pending; /* signalling */ 124 #endif 125 sema_type sem_table[4]; 126 thread_type thr_table[1]; 127 } blocking_child; 128 129 #endif /* WORK_THREAD */ 130 131 extern blocking_child ** blocking_children; 132 extern size_t blocking_children_alloc; 133 extern int worker_per_query; /* boolean */ 134 extern int intres_req_pending; 135 136 extern u_int available_blocking_child_slot(void); 137 extern int queue_blocking_request(blocking_work_req, void *, 138 size_t, blocking_work_callback, 139 void *); 140 extern int queue_blocking_response(blocking_child *, 141 blocking_pipe_header *, size_t, 142 const blocking_pipe_header *); 143 extern void process_blocking_resp(blocking_child *); 144 extern int send_blocking_req_internal(blocking_child *, 145 blocking_pipe_header *, 146 void *); 147 extern int send_blocking_resp_internal(blocking_child *, 148 blocking_pipe_header *); 149 extern blocking_pipe_header * 150 receive_blocking_req_internal(blocking_child *); 151 extern blocking_pipe_header * 152 receive_blocking_resp_internal(blocking_child *); 153 extern int blocking_child_common(blocking_child *); 154 extern void exit_worker(int) 155 __attribute__ ((__noreturn__)); 156 extern int worker_sleep(blocking_child *, time_t); 157 extern void worker_idle_timer_fired(void); 158 extern void interrupt_worker_sleep(void); 159 extern int req_child_exit(blocking_child *); 160 #ifndef HAVE_IO_COMPLETION_PORT 161 extern int pipe_socketpair(int fds[2], int *is_pipe); 162 extern void close_all_beyond(int); 163 extern void close_all_except(int); 164 extern void kill_asyncio (int); 165 #endif 166 167 # ifdef WORK_PIPE 168 typedef void (*addremove_io_fd_func)(int, int, int); 169 extern addremove_io_fd_func addremove_io_fd; 170 # else 171 extern void handle_blocking_resp_sem(void *); 172 typedef void (*addremove_io_semaphore_func)(sem_ref, int); 173 extern addremove_io_semaphore_func addremove_io_semaphore; 174 # endif 175 176 # ifdef WORK_FORK 177 extern int worker_process; 178 # endif 179 180 #endif /* WORKER */ 181 182 #if defined(HAVE_DROPROOT) && defined(WORK_FORK) 183 extern void fork_deferred_worker(void); 184 #else 185 # define fork_deferred_worker() do {} while (0) 186 #endif 187 188 #endif /* !NTP_WORKER_H */ 189