1 /*
2  * selector.h
3  *
4  * MontaVista IPMI interface code for timers and file waiting.
5  *
6  * Author: MontaVista Software, Inc.
7  *         Corey Minyard <minyard@mvista.com>
8  *         source@mvista.com
9  *
10  * Copyright 2002,2003 MontaVista Software Inc.
11  *
12  *  This program is free software; you can redistribute it and/or
13  *  modify it under the terms of the GNU Lesser General Public License
14  *  as published by the Free Software Foundation; either version 2 of
15  *  the License, or (at your option) any later version.
16  *
17  *
18  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  *  You should have received a copy of the GNU Lesser General Public
30  *  License along with this program; if not, write to the Free
31  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32  */
33 
34 #ifndef SELECTOR
35 #define SELECTOR
36 #include <sys/time.h> /* For timeval */
37 
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41 
42 /* The main data structure used by the selector. */
43 struct selector_s;
44 #ifdef OPENIPMI_DEFINE_SELECTOR_T
45 /*
46  * Due to POSIX namespace collisions, we avoid the _t, but
47  * we allow the user to define something that brings it back.
48  */
49 typedef struct selector_s selector_t;
50 #endif
51 
52 /* You have to create a selector before you can use it. */
53 
54 /*
55  * Create a selector for use with threads.  You have to pass in the
56  * lock functions and a signal used to wake waiting threads.
57  *
58  * Note that this function will block wake_sig in the calling thread, and you
59  * must have it blocked on all threads.
60  */
61 typedef struct sel_lock_s sel_lock_t;
62 int sel_alloc_selector_thread(struct selector_s **new_selector, int wake_sig,
63 			      sel_lock_t *(*sel_lock_alloc)(void *cb_data),
64 			      void (*sel_lock_free)(sel_lock_t *),
65 			      void (*sel_lock)(sel_lock_t *),
66 			      void (*sel_unlock)(sel_lock_t *),
67 			      void *cb_data);
68 
69   /* Create a selector for use in a single-threaded environment.  No
70      need for locks or wakeups.  This just call the above call with
71      NULL for all the values. */
72 int sel_alloc_selector_nothread(struct selector_s **new_selector);
73 
74 /* Used to destroy a selector. */
75 int sel_free_selector(struct selector_s *new_selector);
76 
77 /* A function to call when select sees something on a file
78    descriptor. */
79 typedef void (*sel_fd_handler_t)(int fd, void *data);
80 
81 /* Set the handlers for a file descriptor.  The "data" parameter is
82    not used, it is just passed to the exception handlers.  The done
83    handler (if non-NULL) will be called when the data is removed or
84    replaced. */
85 typedef void (*sel_fd_cleared_cb)(int fd, void *data);
86 int sel_set_fd_handlers(struct selector_s *sel,
87 			int               fd,
88 			void              *data,
89 			sel_fd_handler_t  read_handler,
90 			sel_fd_handler_t  write_handler,
91 			sel_fd_handler_t  except_handler,
92 			sel_fd_cleared_cb done);
93 
94 /* Remove the handlers for a file descriptor.  This will also disable
95    the handling of all I/O for the fd.  Note that when this returns,
96    some other thread may be in a handler.  To avoid races with
97    clearing the data (SMP only), you should provide a done handler in
98    the set routine; it will be called when the registered handler is
99    sure to not be called again. */
100 void sel_clear_fd_handlers(struct selector_s *sel,
101 			   int        fd);
102 /* Like above, but can only be called if no handlers are active.
103    If it detects a handler is active, it will assert.  This should
104    only be used at startup to clear the fd handler after an error
105    before any handlers are enabled. */
106 void sel_clear_fd_handlers_imm(struct selector_s *sel, int fd);
107 
108 /* Turn on and off handling for I/O from a file descriptor. */
109 #define SEL_FD_HANDLER_ENABLED	0
110 #define SEL_FD_HANDLER_DISABLED	1
111 void sel_set_fd_read_handler(struct selector_s *sel, int fd, int state);
112 void sel_set_fd_write_handler(struct selector_s *sel, int fd, int state);
113 void sel_set_fd_except_handler(struct selector_s *sel, int fd, int state);
114 
115 struct sel_timer_s;
116 typedef struct sel_timer_s sel_timer_t;
117 
118 typedef void (*sel_timeout_handler_t)(struct selector_s *sel,
119 				      sel_timer_t *timer,
120 				      void        *data);
121 
122 int sel_alloc_timer(struct selector_s     *sel,
123 		    sel_timeout_handler_t handler,
124 		    void                  *user_data,
125 		    sel_timer_t           **new_timer);
126 
127 int sel_free_timer(sel_timer_t *timer);
128 
129 int sel_start_timer(sel_timer_t    *timer,
130 		    struct timeval *timeout);
131 
132 int sel_stop_timer(sel_timer_t *timer);
133 
134 /* Stops the timer and calls the done handler when the stop is
135    complete.  This will return an error if the timer is not
136    running or if another done handler is pending running, and
137    the done handler will not be called. */
138 int sel_stop_timer_with_done(sel_timer_t *timer,
139 			     sel_timeout_handler_t done_handler,
140 			     void *cb_data);
141 
142 /* Use this for times provided to sel_start_time() */
143 void sel_get_monotonic_time(struct timeval *tv);
144 
145 typedef struct sel_runner_s sel_runner_t;
146 typedef void (*sel_runner_func_t)(sel_runner_t *runner, void *cb_data);
147 int sel_alloc_runner(struct selector_s *sel, sel_runner_t **new_runner);
148 int sel_free_runner(sel_runner_t *runner);
149 int sel_run(sel_runner_t *runner, sel_runner_func_t func, void *cb_data);
150 
151 /* For multi-threaded programs, you will need to wake the selector
152    thread if you add a timer to the top of the heap or change the fd
153    mask.  This code should send a signal to the thread that calls
154    sel-select_loop.  The user will have to allocate the signal, set
155    the handlers, etc.  The thread_id and cb_data are just the values
156    passed into sel_select_loop(). */
157 typedef void (*sel_send_sig_cb)(long thread_id, void *cb_data);
158 
159 /*
160  * This is the select interface for program. All handlers on timers and
161  * fds will get chances to be called.
162  * return >0 if sel_select did something (ran a timer or fd)
163  *         0 if timeout
164  *        <0 if error (errno will be set)
165  * The timeout is a relative timeout (just like normal select() on
166  * *nix).
167  */
168 int sel_select(struct selector_s *sel,
169 	       sel_send_sig_cb send_sig,
170 	       long            thread_id,
171 	       void            *cb_data,
172 	       struct timeval  *timeout);
173 
174 /*
175  * Like the above call, but it will return EINTR if interrupted.
176  */
177 int sel_select_intr(struct selector_s *sel,
178 		    sel_send_sig_cb send_sig,
179 		    long            thread_id,
180 		    void            *cb_data,
181 		    struct timeval  *timeout);
182 
183 /*
184  * Like the above call, but allows the user to install their own sigmask
185  * while waiting.
186  */
187 int sel_select_intr_sigmask(struct selector_s *sel,
188 			    sel_send_sig_cb send_sig,
189 			    long            thread_id,
190 			    void            *cb_data,
191 			    struct timeval  *timeout,
192 			    sigset_t        *sigmask);
193 
194 /* This is the main loop for the program.  If NULL is passed in to
195    send_sig, then the signal sender is not used.  If this encounters
196    an unrecoverable problem with select(), it will return the errno.
197    Otherwise it will loop forever. */
198 int sel_select_loop(struct selector_s *sel,
199 		    sel_send_sig_cb send_sig,
200 		    long            thread_id,
201 		    void            *cb_data);
202 
203 /* Wake all threads in all select loops. */
204 void sel_wake_all(struct selector_s *sel);
205 
206 typedef void (*ipmi_sel_add_read_fds_cb)(struct selector_s *sel,
207 					 int            *num_fds,
208 					 fd_set         *fdset,
209 					 struct timeval *timeout,
210 					 int            *timeout_invalid,
211 					 void           *cb_data);
212 typedef void (*ipmi_sel_check_read_fds_cb)(struct selector_s *sel,
213 					   fd_set     *fds,
214 					   void       *cb_data);
215 typedef void (*ipmi_sel_check_timeout_cb)(struct selector_s *sel,
216 					  void       *cb_data);
217 void ipmi_sel_set_read_fds_handler(struct selector_s          *sel,
218 				   ipmi_sel_add_read_fds_cb   add,
219 				   ipmi_sel_check_read_fds_cb handle,
220 				   ipmi_sel_check_timeout_cb  timeout,
221 				   void                       *cb_data);
222 
223 /* DEPRECATED - Do not use any more. */
224 
225 #include <OpenIPMI/deprecator.h>
226 #include <OpenIPMI/os_handler.h>
227 int sel_alloc_selector(os_handler_t *os_hnd, struct selector_s **new_selector)
228   IPMI_FUNC_DEPRECATED;
229 
230 /*
231  * If you fork and expect to use the selector in the forked process,
232  * you *must* call this function in the forked process or you may
233  * get strange results.
234  */
235 int sel_setup_forked_process(struct selector_s *sel);
236 
237 #ifdef __cplusplus
238 }
239 #endif
240 
241 #endif /* SELECTOR */
242