ntp_worker.h revision 293896
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 20typedef enum blocking_work_req_tag { 21 BLOCKING_GETNAMEINFO, 22 BLOCKING_GETADDRINFO, 23} blocking_work_req; 24 25typedef void (*blocking_work_callback)(blocking_work_req, void *, size_t, void *); 26 27typedef 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 */ 36typedef 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 47typedef struct { HANDLE thnd; } thread_type; 48typedef struct { HANDLE shnd; } sema_type; 49# else 50typedef pthread_t thread_type; 51typedef sem_t sema_type; 52# endif 53typedef thread_type *thr_ref; 54typedef sema_type *sem_ref; 55# endif 56 57/* 58 * 59 */ 60#if defined(WORK_FORK) 61 62typedef 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} blocking_child; 72 73#elif defined(WORK_THREAD) 74 75typedef struct blocking_child_tag { 76/* 77 * blocking workitems and blocking_responses are dynamically-sized 78 * one-dimensional arrays of pointers to blocking worker requests and 79 * responses. 80 * 81 * IMPORTANT: This structure is shared between threads, and all access 82 * that is not atomic (especially queue operations) must hold the 83 * 'accesslock' semaphore to avoid data races. 84 * 85 * The resource management (thread/semaphore creation/destruction) 86 * functions and functions just testing a handle are safe because these 87 * are only changed by the main thread when no worker is running on the 88 * same data structure. 89 */ 90 int reusable; 91 sem_ref accesslock; /* shared access lock */ 92 thr_ref thread_ref; /* thread 'handle' */ 93 94 /* the reuest queue */ 95 blocking_pipe_header ** volatile 96 workitems; 97 volatile size_t workitems_alloc; 98 size_t head_workitem; /* parent */ 99 size_t tail_workitem; /* child */ 100 sem_ref workitems_pending; /* signalling */ 101 102 /* the response queue */ 103 blocking_pipe_header ** volatile 104 responses; 105 volatile size_t responses_alloc; 106 size_t head_response; /* child */ 107 size_t tail_response; /* parent */ 108 109 /* event handles / sem_t pointers */ 110 sem_ref wake_scheduled_sleep; 111 112 /* some systems use a pipe for notification, others a semaphore. 113 * Both employ the queue above for the actual data transfer. 114 */ 115#ifdef WORK_PIPE 116 int resp_read_pipe; /* parent */ 117 int resp_write_pipe; /* child */ 118 int ispipe; 119 void * resp_read_ctx; /* child */ 120#else 121 sem_ref responses_pending; /* signalling */ 122#endif 123 sema_type sem_table[4]; 124 thread_type thr_table[1]; 125} blocking_child; 126 127#endif /* WORK_THREAD */ 128 129extern blocking_child ** blocking_children; 130extern size_t blocking_children_alloc; 131extern int worker_per_query; /* boolean */ 132extern int intres_req_pending; 133 134extern u_int available_blocking_child_slot(void); 135extern int queue_blocking_request(blocking_work_req, void *, 136 size_t, blocking_work_callback, 137 void *); 138extern int queue_blocking_response(blocking_child *, 139 blocking_pipe_header *, size_t, 140 const blocking_pipe_header *); 141extern void process_blocking_resp(blocking_child *); 142extern int send_blocking_req_internal(blocking_child *, 143 blocking_pipe_header *, 144 void *); 145extern int send_blocking_resp_internal(blocking_child *, 146 blocking_pipe_header *); 147extern blocking_pipe_header * 148 receive_blocking_req_internal(blocking_child *); 149extern blocking_pipe_header * 150 receive_blocking_resp_internal(blocking_child *); 151extern int blocking_child_common(blocking_child *); 152extern void exit_worker(int) 153 __attribute__ ((__noreturn__)); 154extern int worker_sleep(blocking_child *, time_t); 155extern void worker_idle_timer_fired(void); 156extern void interrupt_worker_sleep(void); 157extern int req_child_exit(blocking_child *); 158#ifndef HAVE_IO_COMPLETION_PORT 159extern int pipe_socketpair(int fds[2], int *is_pipe); 160extern void close_all_beyond(int); 161extern void close_all_except(int); 162extern void kill_asyncio (int); 163#endif 164 165# ifdef WORK_PIPE 166typedef void (*addremove_io_fd_func)(int, int, int); 167extern addremove_io_fd_func addremove_io_fd; 168# else 169extern void handle_blocking_resp_sem(void *); 170typedef void (*addremove_io_semaphore_func)(sem_ref, int); 171extern addremove_io_semaphore_func addremove_io_semaphore; 172# endif 173 174# ifdef WORK_FORK 175extern int worker_process; 176# endif 177 178#endif /* WORKER */ 179 180#if defined(HAVE_DROPROOT) && defined(WORK_FORK) 181extern void fork_deferred_worker(void); 182#else 183# define fork_deferred_worker() do {} while (0) 184#endif 185 186#endif /* !NTP_WORKER_H */ 187