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 
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           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 
79 typedef 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: */
136 extern volatile u_int                   blocking_child_ready_seen;/* signal/scan */
137 extern volatile u_int                   blocking_child_ready_done;/* consumer/mainloop */
138 
139 extern    blocking_child **   blocking_children;
140 extern    size_t                        blocking_children_alloc;
141 extern    int                           worker_per_query;   /* boolean */
142 extern    int                           intres_req_pending;
143 
144 extern    u_int     available_blocking_child_slot(void);
145 extern    int       queue_blocking_request(blocking_work_req, void *,
146                                                size_t, blocking_work_callback,
147                                                void *);
148 extern    int       queue_blocking_response(blocking_child *,
149                                                   blocking_pipe_header *, size_t,
150                                                   const blocking_pipe_header *);
151 extern    void      process_blocking_resp(blocking_child *);
152 extern    void      harvest_blocking_responses(void);
153 extern    int       send_blocking_req_internal(blocking_child *,
154                                                      blocking_pipe_header *,
155                                                      void *);
156 extern    int       send_blocking_resp_internal(blocking_child *,
157                                                       blocking_pipe_header *);
158 extern    blocking_pipe_header *
159                     receive_blocking_req_internal(blocking_child *);
160 extern    blocking_pipe_header *
161                     receive_blocking_resp_internal(blocking_child *);
162 extern    int       blocking_child_common(blocking_child *);
163 extern    void      exit_worker(int)
164                               __attribute__ ((__noreturn__));
165 extern    int       worker_sleep(blocking_child *, time_t);
166 extern    void      worker_idle_timer_fired(void);
167 extern    void      interrupt_worker_sleep(void);
168 extern    int       req_child_exit(blocking_child *);
169 #ifndef HAVE_IO_COMPLETION_PORT
170 extern    int       pipe_socketpair(int fds[2], int *is_pipe);
171 extern    void      close_all_beyond(int);
172 extern    void      close_all_except(int);
173 extern    void      kill_asyncio        (int);
174 #endif
175 
176 extern void worker_global_lock(int inOrOut);
177 
178 # ifdef WORK_PIPE
179 typedef   void      (*addremove_io_fd_func)(int, int, int);
180 extern    addremove_io_fd_func                    addremove_io_fd;
181 # else
182 extern    void      handle_blocking_resp_sem(void *);
183 typedef   void      (*addremove_io_semaphore_func)(sem_ref, int);
184 extern    addremove_io_semaphore_func   addremove_io_semaphore;
185 # endif
186 
187 # ifdef WORK_FORK
188 extern    int                                     worker_process;
189 # endif
190 
191 #endif    /* WORKER */
192 
193 #if defined(HAVE_DROPROOT) && defined(WORK_FORK)
194 extern void         fork_deferred_worker(void);
195 #else
196 # define  fork_deferred_worker()        do {} while (0)
197 #endif
198 
199 #endif    /* !NTP_WORKER_H */
200