Whamcloud - gitweb
fe24efcf3cf8066192cd6cc41963969a369ad659
[fs/lustre-release.git] / lnet / ulnds / select.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (c) 2002 Cray Inc.
5  *  Copyright (c) 2002 Eric Hoffman
6  *
7  *   This file is part of Lustre, http://www.lustre.org.
8  *
9  *   Lustre is free software; you can redistribute it and/or
10  *   modify it under the terms of version 2 of the GNU General Public
11  *   License as published by the Free Software Foundation.
12  *
13  *   Lustre is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with Lustre; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22
23 /* select.c:
24  *  Provides a general mechanism for registering and dispatching
25  *  io events through the select system call.
26  */
27
28 #ifdef sun
29 #include <sys/filio.h>
30 #else
31 #include <sys/ioctl.h>
32 #endif
33
34 #include <sys/time.h>
35 #include <sys/types.h>
36 #include <stdlib.h>
37 #include <pqtimer.h>
38 #include <dispatch.h>
39
40
41 static struct timeval beginning_of_epoch;
42 static io_handler io_handlers;
43
44 /* Function: now
45  *
46  * Return: the current time in canonical units: a 64 bit number
47  *   where the most significant 32 bits contains the number
48  *   of seconds, and the least signficant a count of (1/(2^32))ths
49  *   of a second.
50  */
51 when now()
52 {
53     struct timeval result;
54   
55     gettimeofday(&result,0);
56     return((((unsigned long long)result.tv_sec)<<32)|
57            (((unsigned long long)result.tv_usec)<<32)/1000000);
58 }
59
60
61 /* Function: register_io_handler
62  * Arguments: fd: the file descriptor of interest
63  *            type: a mask of READ_HANDLER, WRITE_HANDLER, EXCEPTION_HANDLER
64  *            function: a function to call when io is available on fd
65  *            arg: an opaque correlator to return to the handler
66  * Returns: a pointer to the io_handler structure
67  */
68 io_handler register_io_handler(int fd,
69                                int type,
70                                int (*function)(void *),
71                                void *arg)
72 {
73     io_handler i=(io_handler)malloc(sizeof(struct io_handler));
74     if ((i->fd=fd)>=0){
75         i->type=type;
76         i->function=function;
77         i->argument=arg;
78         i->disabled=0;
79         i->last=&io_handlers;
80         if ((i->next=io_handlers)) i->next->last=&i->next;
81         io_handlers=i;
82     }
83     return(i);
84 }
85
86 /* Function: remove_io_handler
87  * Arguments: i: a pointer to the handler to stop servicing
88  *
89  * remove_io_handler() doesn't actually free the handler, due
90  * to reentrancy problems. it just marks the handler for 
91  * later cleanup by the blocking function.
92  */
93 void remove_io_handler (io_handler i)
94 {
95     i->disabled=1;
96 }
97
98 static void set_flag(io_handler n,fd_set *fds)
99 {
100     if (n->type & READ_HANDLER) FD_SET(n->fd, &fds[0]);
101     if (n->type & WRITE_HANDLER) FD_SET(n->fd,&fds[1]);
102     if (n->type & EXCEPTION_HANDLER) FD_SET(n->fd, &fds[2]);
103 }
104
105
106 /* Function: select_timer_block
107  * Arguments: until: an absolute time when the select should return
108  * 
109  *   This function dispatches the various file descriptors' handler
110  *   functions, if the kernel indicates there is io available.
111  */
112 void select_timer_block(when until)
113 {
114     fd_set fds[3];
115     struct timeval timeout;
116     struct timeval *timeout_pointer;
117     int result;
118     io_handler j;
119     io_handler *k;
120
121     /* TODO: loop until the entire interval is expired*/
122     if (until){
123         when interval=until-now();
124         timeout.tv_sec=(interval>>32);
125         timeout.tv_usec=((interval<<32)/1000000)>>32;
126         timeout_pointer=&timeout;
127     } else timeout_pointer=0;
128
129
130     /* FIXME
131      * temporarily add timer for endless waiting problem.
132      * FIXME
133      */
134     timeout.tv_sec = 1;
135     timeout.tv_usec = 0;
136     timeout_pointer=&timeout;
137
138     FD_ZERO(&fds[0]);
139     FD_ZERO(&fds[1]);
140     FD_ZERO(&fds[2]);
141     for (k=&io_handlers;*k;){
142         if ((*k)->disabled){
143             j=*k;
144             *k=(*k)->next;
145             free(j);
146         }
147         if (*k) {
148             set_flag(*k,fds);
149             k=&(*k)->next;
150         }
151     }
152
153     result=select(FD_SETSIZE, &fds[0], &fds[1], &fds[2], timeout_pointer);
154
155     if (result > 0)
156         for (j=io_handlers;j;j=j->next){
157             if (!(j->disabled) && 
158                 ((FD_ISSET(j->fd, &fds[0]) && (j->type & READ_HANDLER)) ||
159                  (FD_ISSET(j->fd, &fds[1]) && (j->type & WRITE_HANDLER)) ||
160                  (FD_ISSET(j->fd, &fds[2]) && (j->type & EXCEPTION_HANDLER)))){
161                 if (!(*j->function)(j->argument))
162                     j->disabled=1;
163             }
164         }
165 }
166
167 /* Function: init_unix_timer()
168  *   is called to initialize the library 
169  */
170 void init_unix_timer()
171 {
172     io_handlers=0;
173     gettimeofday(&beginning_of_epoch, 0);
174     initialize_timer(select_timer_block);
175 }