Whamcloud - gitweb
c3ee103268aec08538fa8a24c95f9d8d60566fee
[fs/lustre-release.git] / lnet / ulnds / proclib.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  *
6  *   This file is part of Portals, http://www.sf.net/projects/sandiaportals/
7  *
8  *   Portals is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2.1 of the GNU Lesser General
10  *   Public License as published by the Free Software Foundation.
11  *
12  *   Portals is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU Lesser General Public License for more details.
16  *
17  *   You should have received a copy of the GNU Lesser General Public
18  *   License along with Portals; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 /* lib.c:
23  *  This file provides the 'library' side for the process-based nals.
24  *  it is responsible for communication with the 'api' side and
25  *  providing service to the generic portals 'library'
26  *  implementation. 'library' might be better termed 'communication'
27  *  or 'kernel'.
28  */
29  
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <stdarg.h>
33 #include <unistd.h>
34 #include <syscall.h>
35 #include <procbridge.h>
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <netdb.h>
39 #include <errno.h>
40 #include <timer.h>
41 //#include <util/pqtimer.h>
42 #include <dispatch.h>
43
44 /* the following functions are stubs to satisfy the nal definition
45    without doing anything particularily useful*/
46
47 static int nal_write(nal_cb_t *nal,
48                      void *private,
49                      user_ptr dst_addr,
50                      void *src_addr,
51                      ptl_size_t len)
52 {
53     memcpy(dst_addr, src_addr, len);
54     return 0;
55 }
56
57 static int nal_read(nal_cb_t * nal,
58                     void *private,
59                     void *dst_addr,
60                     user_ptr src_addr,
61                     size_t len)
62 {
63         memcpy(dst_addr, src_addr, len);
64         return 0;
65 }
66
67 static void *nal_malloc(nal_cb_t *nal,
68                         ptl_size_t len)
69 {
70     void *buf =  malloc(len);
71     return buf;
72 }
73
74 static void nal_free(nal_cb_t *nal,
75                      void *buf,
76                      ptl_size_t len)
77 {
78     free(buf);
79 }
80
81 static void nal_printf(nal_cb_t *nal,
82                        const char *fmt,
83                        ...)
84 {
85     va_list        ap;
86
87     va_start(ap, fmt);
88     vprintf(fmt, ap);
89     va_end(ap);
90 }
91
92
93 static void nal_cli(nal_cb_t *nal,
94                     unsigned long *flags)
95 {
96 }
97
98
99 static void nal_sti(nal_cb_t *nal,
100                     unsigned long *flags)
101 {
102 }
103
104
105 static int nal_dist(nal_cb_t *nal,
106                     ptl_nid_t nid,
107                     unsigned long *dist)
108 {
109     return 0;
110 }
111     
112
113
114 /* Function:  data_from_api
115  * Arguments: t: the nal state for this interface
116  * Returns: whether to continue reading from the pipe
117  *
118  *   data_from_api() reads data from the api side in response
119  *   to a select.
120  *
121  *   We define data_failure() for syntactic convenience
122  *   of unix error reporting.
123  */
124
125 #define data_failure(operand,fd,buffer,length)\
126        if(syscall(SYS_##operand,fd,buffer,length)!=length){\
127           lib_fini(b->nal_cb);\
128           return(0);\
129        }
130 static int data_from_api(void *arg)
131 {
132         bridge b = arg;
133     procbridge p=(procbridge)b->local;
134     /* where are these two sizes derived from ??*/
135     char arg_block[ 256 ];
136     char ret_block[ 128 ];
137     ptl_size_t arg_len,ret_len;
138     int fd=p->to_lib[0];
139     int index;
140
141     data_failure(read,fd, &index, sizeof(index));
142
143     if (index==PTL_FINI) {
144         lib_fini(b->nal_cb);
145         if (b->shutdown) (*b->shutdown)(b);
146         syscall(SYS_write, p->from_lib[1],&b->alive,sizeof(b->alive));
147
148         /* a heavy-handed but convenient way of shutting down
149            the lower side thread */
150         pthread_exit(0);
151     }
152
153     data_failure(read,fd, &arg_len, sizeof(arg_len));
154     data_failure(read,fd, &ret_len, sizeof(ret_len));
155     data_failure(read,fd, arg_block, arg_len);
156
157     lib_dispatch(b->nal_cb, NULL, index, arg_block, ret_block);
158
159     data_failure(write,p->from_lib[1],ret_block, ret_len);
160     return(1);
161 }
162 #undef data_failure
163
164
165
166 static void wakeup_topside(void *z)
167 {
168     bridge b=z;
169     procbridge p=b->local;
170
171     pthread_mutex_lock(&p->mutex);
172     pthread_cond_broadcast(&p->cond);
173     pthread_mutex_unlock(&p->mutex);
174 }
175
176
177 /* Function:  nal_thread
178  * Arguments: z: an opaque reference to a nal control structure
179  *               allocated and partially populated by the api level code
180  * Returns: nothing, and only on error or explicit shutdown
181  *
182  *  This function is the entry point of the pthread initiated on 
183  *  the api side of the interface. This thread is used to handle
184  *  asynchronous delivery to the application.
185  * 
186  *  We define a limit macro to place a ceiling on limits
187  *   for syntactic convenience
188  */
189 #define LIMIT(x,y,max)\
190      if ((unsigned int)x > max) y = max;
191
192 extern int tcpnal_init(bridge);
193
194 nal_initialize nal_table[PTL_IFACE_MAX]={0,tcpnal_init,0};
195
196 void *nal_thread(void *z)
197 {
198     bridge b=z;
199     procbridge p=b->local;
200     int rc;
201     ptl_pid_t pid_request;
202     int nal_type;
203     ptl_ni_limits_t desired;
204     ptl_ni_limits_t actual;
205     
206     b->nal_cb=(nal_cb_t *)malloc(sizeof(nal_cb_t));
207     b->nal_cb->nal_data=b;
208     b->nal_cb->cb_read=nal_read;
209     b->nal_cb->cb_write=nal_write;
210     b->nal_cb->cb_malloc=nal_malloc;
211     b->nal_cb->cb_free=nal_free;
212     b->nal_cb->cb_map=NULL;
213     b->nal_cb->cb_unmap=NULL;
214     b->nal_cb->cb_printf=nal_printf;
215     b->nal_cb->cb_cli=nal_cli;
216     b->nal_cb->cb_sti=nal_sti;
217     b->nal_cb->cb_dist=nal_dist;
218
219
220     register_io_handler(p->to_lib[0],READ_HANDLER,data_from_api,(void *)b);
221
222     if(!(rc = syscall(SYS_read, p->to_lib[0], &pid_request, sizeof(pid_request))))
223         perror("procbridge read from api");
224     if(!(rc = syscall(SYS_read, p->to_lib[0], &desired, sizeof(ptl_ni_limits_t))))
225         perror("procbridge read from api");
226     if(!(rc = syscall(SYS_read, p->to_lib[0], &nal_type, sizeof(nal_type))))
227         perror("procbridge read from api");
228
229     actual = desired;
230     LIMIT(desired.max_match_entries,actual.max_match_entries,MAX_MES);
231     LIMIT(desired.max_mem_descriptors,actual.max_mem_descriptors,MAX_MDS);
232     LIMIT(desired.max_event_queues,actual.max_event_queues,MAX_EQS);
233     LIMIT(desired.max_atable_index,actual.max_atable_index,MAX_ACLS);
234     LIMIT(desired.max_ptable_index,actual.max_ptable_index,MAX_PTLS);
235
236     set_address(b,pid_request);
237
238     if (nal_table[nal_type]) rc=(*nal_table[nal_type])(b);
239     /* initialize the generic 'library' level code */
240
241     rc = lib_init(b->nal_cb, 
242                   b->nal_cb->ni.nid,
243                   b->nal_cb->ni.pid,
244                   10,
245                   actual.max_ptable_index,
246                   actual.max_atable_index);
247
248     /*
249      * Whatever the initialization returned is passed back to the
250      * user level code for further interpretation.  We just exit if
251      * it is non-zero since something went wrong.
252      */
253     /* this should perform error checking */
254 #if 0
255     write(p->from_lib[1], &actual, sizeof(ptl_ni_limits_t));
256 #endif
257     syscall(SYS_write, p->from_lib[1], &rc, sizeof(rc));
258     
259     if(!rc) {
260         /* the thunk function is called each time the timer loop
261            performs an operation and returns to blocking mode. we
262            overload this function to inform the api side that
263            it may be interested in looking at the event queue */
264         register_thunk(wakeup_topside,b);
265         timer_loop();
266     }
267     return(0);
268 }
269 #undef LIMIT
270