Whamcloud - gitweb
land b_eq on HEAD
[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     FD_ZERO(&fds[0]);
130     FD_ZERO(&fds[1]);
131     FD_ZERO(&fds[2]);
132     for (k=&io_handlers;*k;){
133         if ((*k)->disabled){
134             j=*k;
135             *k=(*k)->next;
136             free(j);
137         }
138         if (*k) {
139             set_flag(*k,fds);
140             k=&(*k)->next;
141         }
142     }
143
144     result=select(FD_SETSIZE, &fds[0], &fds[1], &fds[2], timeout_pointer);
145
146     if (result > 0)
147         for (j=io_handlers;j;j=j->next){
148             if (!(j->disabled) && 
149                 ((FD_ISSET(j->fd, &fds[0]) && (j->type & READ_HANDLER)) ||
150                  (FD_ISSET(j->fd, &fds[1]) && (j->type & WRITE_HANDLER)) ||
151                  (FD_ISSET(j->fd, &fds[2]) && (j->type & EXCEPTION_HANDLER)))){
152                 if (!(*j->function)(j->argument))
153                     j->disabled=1;
154             }
155         }
156 }
157
158 /* Function: init_unix_timer()
159  *   is called to initialize the library 
160  */
161 void init_unix_timer()
162 {
163     io_handlers=0;
164     gettimeofday(&beginning_of_epoch, 0);
165     initialize_timer(select_timer_block);
166 }