Whamcloud - gitweb
b=2776
[fs/lustre-release.git] / lnet / ulnds / socklnd / procapi.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) 2003 Cluster File Systems, Inc.
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 /* api.c:
24  *  This file provides the 'api' side for the process-based nals.
25  *  it is responsible for creating the 'library' side thread,
26  *  and passing wrapped portals transactions to it.
27  *
28  *  Along with initialization, shutdown, and transport to the library
29  *  side, this file contains some stubs to satisfy the nal definition.
30  */
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <string.h>
35 #ifndef __CYGWIN__
36 #include <syscall.h>
37 #endif
38 #include <sys/socket.h>
39 #include <procbridge.h>
40 #include <pqtimer.h>
41 #include <dispatch.h>
42 #include <errno.h>
43
44
45 /* XXX CFS workaround, to give a chance to let nal thread wake up
46  * from waiting in select
47  */
48 static int procbridge_notifier_handler(void *arg)
49 {
50     static char buf[8];
51     procbridge p = (procbridge) arg;
52
53     syscall(SYS_read, p->notifier[1], buf, sizeof(buf));
54     return 1;
55 }
56
57 void procbridge_wakeup_nal(procbridge p)
58 {
59     static char buf[8];
60     syscall(SYS_write, p->notifier[0], buf, sizeof(buf));
61 }
62
63 /* Function: forward
64  * Arguments: nal_t *nal: pointer to my top-side nal structure
65  *            id: the command to pass to the lower layer
66  *            args, args_len:pointer to and length of the request
67  *            ret, ret_len:  pointer to and size of the result
68  * Returns: a portals status code
69  *
70  * forwards a packaged api call from the 'api' side to the 'library'
71  *   side, and collects the result
72  */
73 static int procbridge_forward(nal_t *n, int id, void *args, size_t args_len,
74                               void *ret, size_t ret_len)
75 {
76     bridge b = (bridge) n->nal_data;
77
78     if (id == PTL_FINI) {
79             lib_fini(b->nal_cb);
80
81             if (b->shutdown)
82                 (*b->shutdown)(b);
83     }
84
85     lib_dispatch(b->nal_cb, NULL, id, args, ret);
86
87     return (PTL_OK);
88 }
89
90
91 /* Function: shutdown
92  * Arguments: nal: a pointer to my top side nal structure
93  *            ni: my network interface index
94  *
95  * cleanup nal state, reclaim the lower side thread and
96  *   its state using PTL_FINI codepoint
97  */
98 static int procbridge_shutdown(nal_t *n, int ni)
99 {
100     bridge b=(bridge)n->nal_data;
101     procbridge p=(procbridge)b->local;
102
103     p->nal_flags |= NAL_FLAG_STOPPING;
104     procbridge_wakeup_nal(p);
105
106     do {
107         pthread_mutex_lock(&p->mutex);
108         if (p->nal_flags & NAL_FLAG_STOPPED) {
109                 pthread_mutex_unlock(&p->mutex);
110                 break;
111         }
112         pthread_cond_wait(&p->cond, &p->mutex);
113         pthread_mutex_unlock(&p->mutex);
114     } while (1);
115
116     free(p);
117     return(0);
118 }
119
120
121 /* Function: validate
122  *    useless stub
123  */
124 static int procbridge_validate(nal_t *nal, void *base, size_t extent)
125 {
126     return(0);
127 }
128
129
130 static void procbridge_lock(nal_t * n, unsigned long *flags)
131 {
132     bridge b=(bridge)n->nal_data;
133     procbridge p=(procbridge)b->local;
134
135     pthread_mutex_lock(&p->mutex);
136 }
137
138 static void procbridge_unlock(nal_t * n, unsigned long *flags)
139 {
140     bridge b=(bridge)n->nal_data;
141     procbridge p=(procbridge)b->local;
142
143     pthread_mutex_unlock(&p->mutex);
144 }
145
146 /* Function: yield
147  * Arguments:  pid:
148  *
149  *  this function was originally intended to allow the
150  *   lower half thread to be scheduled to allow progress. we
151  *   overload it to explicitly block until signalled by the
152  *   lower half.
153  */
154 static int procbridge_yield(nal_t *n, unsigned long *flags, int milliseconds)
155 {
156     bridge b=(bridge)n->nal_data;
157     procbridge p=(procbridge)b->local;
158
159     if (milliseconds == 0)
160             return 0;
161             
162     if (milliseconds < 0) {
163         pthread_cond_wait(&p->cond,&p->mutex);
164     } else {
165         struct timeval then;
166         struct timeval now;
167         struct timespec timeout;
168
169         gettimeofday(&then, NULL);
170         timeout.tv_sec = then.tv_sec + milliseconds/1000;
171         timeout.tv_nsec = then.tv_usec * 1000 + milliseconds % 1000 * 1000000;
172         if (timeout.tv_nsec >= 1000000000) {
173                 timeout.tv_sec++;
174                 timeout.tv_nsec -= 1000000000;
175         }
176
177         pthread_cond_timedwait(&p->cond, &p->mutex, &timeout);
178
179         gettimeofday(&now, NULL);
180         milliseconds -= (now.tv_sec - then.tv_sec) * 1000 + 
181                         (now.tv_usec - then.tv_usec) / 1000;
182         
183         if (milliseconds < 0)
184                 milliseconds = 0;
185     }
186
187     return (milliseconds);
188 }
189
190
191 /* api_nal
192  *  the interface vector to allow the generic code to access
193  *  this nal. this is seperate from the library side nal_cb.
194  *  TODO: should be dyanmically allocated
195  */
196 static nal_t api_nal = {
197     ni:       {0},
198     nal_data: NULL,
199     forward:  procbridge_forward,
200     shutdown: procbridge_shutdown,
201     validate: procbridge_validate,
202     yield:    procbridge_yield,
203     lock:     procbridge_lock,
204     unlock:   procbridge_unlock
205 };
206
207 ptl_nid_t tcpnal_mynid;
208
209 /* Function: procbridge_interface
210  *
211  * Arguments:  pid: requested process id (port offset)
212  *                  PTL_ID_ANY not supported.
213  *             desired: limits passed from the application
214  *                      and effectively ignored
215  *             actual:  limits actually allocated and returned
216  *
217  * Returns: a pointer to my statically allocated top side NAL
218  *          structure
219  *
220  * initializes the tcp nal. we define unix_failure as an
221  * error wrapper to cut down clutter.
222  */
223 nal_t *procbridge_interface(int num_interface,
224                             ptl_pt_index_t ptl_size,
225                             ptl_ac_index_t acl_size,
226                             ptl_pid_t requested_pid)
227 {
228     nal_init_args_t args;
229     procbridge p;
230     bridge b;
231     static int initialized=0;
232     ptl_ni_limits_t limits = {-1,-1,-1,-1,-1};
233     int nal_type = PTL_IFACE_TCP;/* PTL_IFACE_DEFAULT FIXME hack */
234
235     if(initialized) return (&api_nal);
236
237     init_unix_timer();
238
239     b=(bridge)malloc(sizeof(struct bridge));
240     p=(procbridge)malloc(sizeof(struct procbridge));
241     api_nal.nal_data=b;
242     b->local=p;
243
244     if (ptl_size)
245             limits.max_ptable_index = ptl_size;
246     if (acl_size)
247             limits.max_atable_index = acl_size;
248
249     args.nia_requested_pid = requested_pid;
250     args.nia_limits = &limits;
251     args.nia_nal_type = nal_type;
252     args.nia_bridge = b;
253
254     /* init procbridge */
255     pthread_mutex_init(&p->mutex,0);
256     pthread_cond_init(&p->cond, 0);
257     p->nal_flags = 0;
258
259     /* initialize notifier */
260     if (socketpair(AF_UNIX, SOCK_STREAM, 0, p->notifier)) {
261         perror("socketpair failed");
262         return NULL;
263     }
264
265     if (!register_io_handler(p->notifier[1], READ_HANDLER,
266                 procbridge_notifier_handler, p)) {
267         perror("fail to register notifier handler");
268         return NULL;
269     }
270
271     /* create nal thread */
272     if (pthread_create(&p->t, NULL, nal_thread, &args)) {
273         perror("nal_init: pthread_create");
274         return(NULL);
275     }
276
277     do {
278         pthread_mutex_lock(&p->mutex);
279         if (p->nal_flags & (NAL_FLAG_RUNNING | NAL_FLAG_STOPPED)) {
280                 pthread_mutex_unlock(&p->mutex);
281                 break;
282         }
283         pthread_cond_wait(&p->cond, &p->mutex);
284         pthread_mutex_unlock(&p->mutex);
285     } while (1);
286
287     if (p->nal_flags & NAL_FLAG_STOPPED)
288         return (NULL);
289
290     b->nal_cb->ni.nid = tcpnal_mynid;
291     initialized = 1;
292
293     return (&api_nal);
294 }