* vim:expandtab:shiftwidth=8:tabstop=8:
*
* Copyright (c) 2002 Cray Inc.
+ * Copyright (c) 2003 Cluster File Systems, Inc.
*
- * This file is part of Portals, http://www.sf.net/projects/sandiaportals/
+ * This file is part of Lustre, http://www.lustre.org.
*
- * Portals is free software; you can redistribute it and/or
- * modify it under the terms of version 2.1 of the GNU Lesser General
- * Public License as published by the Free Software Foundation.
+ * Lustre is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
*
- * Portals is distributed in the hope that it will be useful,
+ * Lustre is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
+ * GNU General Public License for more details.
*
- * You should have received a copy of the GNU Lesser General Public
- * License along with Portals; if not, write to the Free Software
+ * You should have received a copy of the GNU General Public License
+ * along with Lustre; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
+#ifndef __CYGWIN__
#include <syscall.h>
+#endif
+#include <sys/socket.h>
#include <procbridge.h>
#include <pqtimer.h>
#include <dispatch.h>
#include <errno.h>
-/* Function: forward
- * Arguments: nal_t *nal: pointer to my top-side nal structure
- * id: the command to pass to the lower layer
- * args, args_len:pointer to and length of the request
- * ret, ret_len: pointer to and size of the result
- * Returns: a portals status code
- *
- * forwards a packaged api call from the 'api' side to the 'library'
- * side, and collects the result
+/* XXX CFS workaround, to give a chance to let nal thread wake up
+ * from waiting in select
*/
-#define forward_failure(operand,fd,buffer,length)\
- if(syscall(SYS_##operand,fd,buffer,length)!=length){\
- lib_fini(b->nal_cb);\
- return(PTL_SEGV);\
- }
-static int procbridge_forward(nal_t *n, int id, void *args, ptl_size_t args_len,
- void *ret, ptl_size_t ret_len)
+static int procbridge_notifier_handler(void *arg)
{
- bridge b=(bridge)n->nal_data;
- procbridge p=(procbridge)b->local;
- int lib=p->to_lib[1];
- int k;
-
- forward_failure(write,lib, &id, sizeof(id));
- forward_failure(write,lib,&args_len, sizeof(args_len));
- forward_failure(write,lib,&ret_len, sizeof(ret_len));
- forward_failure(write,lib,args, args_len);
+ static char buf[8];
+ procbridge p = (procbridge) arg;
- do {
- k=syscall(SYS_read, p->from_lib[0], ret, ret_len);
- } while ((k!=ret_len) && (errno += EINTR));
-
- if(k!=ret_len){
- perror("nal: read return block");
- return PTL_SEGV;
- }
- return (PTL_OK);
+ syscall(SYS_read, p->notifier[1], buf, sizeof(buf));
+ return 1;
}
-#undef forward_failure
+void procbridge_wakeup_nal(procbridge p)
+{
+ static char buf[8];
+ syscall(SYS_write, p->notifier[0], buf, sizeof(buf));
+}
/* Function: shutdown
* Arguments: nal: a pointer to my top side nal structure
* cleanup nal state, reclaim the lower side thread and
* its state using PTL_FINI codepoint
*/
-static int procbridge_shutdown(nal_t *n, int ni)
+static void procbridge_shutdown(nal_t *n)
{
- bridge b=(bridge)n->nal_data;
+ lib_nal_t *nal = n->nal_data;
+ bridge b=(bridge)nal->libnal_data;
procbridge p=(procbridge)b->local;
- int code=PTL_FINI;
- syscall(SYS_write, p->to_lib[1],&code,sizeof(code));
- syscall(SYS_read, p->from_lib[0],&code,sizeof(code));
+ p->nal_flags |= NAL_FLAG_STOPPING;
+ procbridge_wakeup_nal(p);
- syscall(SYS_close, p->to_lib[0]);
- syscall(SYS_close, p->to_lib[1]);
- syscall(SYS_close, p->from_lib[0]);
- syscall(SYS_close, p->from_lib[1]);
+ do {
+ pthread_mutex_lock(&p->mutex);
+ if (p->nal_flags & NAL_FLAG_STOPPED) {
+ pthread_mutex_unlock(&p->mutex);
+ break;
+ }
+ pthread_cond_wait(&p->cond, &p->mutex);
+ pthread_mutex_unlock(&p->mutex);
+ } while (1);
free(p);
- return(0);
}
-/* Function: validate
- * useless stub
- */
-static int procbridge_validate(nal_t *nal, void *base, ptl_size_t extent)
-{
- return(0);
-}
-
+/* forward decl */
+extern int procbridge_startup (nal_t *, ptl_pid_t,
+ ptl_ni_limits_t *, ptl_ni_limits_t *);
-/* Function: yield
- * Arguments: pid:
- *
- * this function was originally intended to allow the
- * lower half thread to be scheduled to allow progress. we
- * overload it to explicitly block until signalled by the
- * lower half.
- */
-static void procbridge_yield(nal_t *n)
-{
- bridge b=(bridge)n->nal_data;
- procbridge p=(procbridge)b->local;
-
- pthread_mutex_lock(&p->mutex);
- pthread_cond_wait(&p->cond,&p->mutex);
- pthread_mutex_unlock(&p->mutex);
-}
-
-
-static void procbridge_lock(nal_t * nal, unsigned long *flags){}
-static void procbridge_unlock(nal_t * nal, unsigned long *flags){}
/* api_nal
* the interface vector to allow the generic code to access
- * this nal. this is seperate from the library side nal_cb.
+ * this nal. this is seperate from the library side lib_nal.
* TODO: should be dyanmically allocated
*/
-static nal_t api_nal = {
- ni: {0},
+nal_t procapi_nal = {
nal_data: NULL,
- forward: procbridge_forward,
- shutdown: procbridge_shutdown,
- validate: procbridge_validate,
- yield: procbridge_yield,
- lock: procbridge_lock,
- unlock: procbridge_unlock
+ nal_ni_init: procbridge_startup,
+ nal_ni_fini: procbridge_shutdown,
};
-/* Function: bridge_init
+ptl_nid_t tcpnal_mynid;
+
+/* Function: procbridge_startup
*
* Arguments: pid: requested process id (port offset)
* PTL_ID_ANY not supported.
* and effectively ignored
* actual: limits actually allocated and returned
*
- * Returns: a pointer to my statically allocated top side NAL
- * structure
+ * Returns: portals rc
*
* initializes the tcp nal. we define unix_failure as an
* error wrapper to cut down clutter.
*/
-#define unix_failure(operand,fd,buffer,length,text)\
- if(syscall(SYS_##operand,fd,buffer,length)!=length){\
- perror(text);\
- return(NULL);\
- }
-#if 0
-static nal_t *bridge_init(ptl_interface_t nal,
- ptl_pid_t pid_request,
- ptl_ni_limits_t *desired,
- ptl_ni_limits_t *actual,
- int *rc)
+int procbridge_startup (nal_t *nal, ptl_pid_t requested_pid,
+ ptl_ni_limits_t *requested_limits,
+ ptl_ni_limits_t *actual_limits)
{
+ nal_init_args_t args;
+
procbridge p;
bridge b;
- static int initialized=0;
- ptl_ni_limits_t limits = {-1,-1,-1,-1,-1};
+ /* XXX nal_type is purely private to tcpnal here */
+ int nal_type = PTL_IFACE_TCP;/* PTL_IFACE_DEFAULT FIXME hack */
- if(initialized) return (&api_nal);
+ LASSERT(nal == &procapi_nal);
init_unix_timer();
b=(bridge)malloc(sizeof(struct bridge));
p=(procbridge)malloc(sizeof(struct procbridge));
- api_nal.nal_data=b;
b->local=p;
- if(pipe(p->to_lib) || pipe(p->from_lib)) {
- perror("nal_init: pipe");
- return(NULL);
- }
-
- if (desired) limits = *desired;
- unix_failure(write,p->to_lib[1], &pid_request, sizeof(pid_request),
- "nal_init: write");
- unix_failure(write,p->to_lib[1], &limits, sizeof(ptl_ni_limits_t),
- "nal_init: write");
- unix_failure(write,p->to_lib[1], &nal, sizeof(ptl_interface_t),
- "nal_init: write");
+ args.nia_requested_pid = requested_pid;
+ args.nia_requested_limits = requested_limits;
+ args.nia_actual_limits = actual_limits;
+ args.nia_nal_type = nal_type;
+ args.nia_bridge = b;
+ args.nia_apinal = nal;
- if(pthread_create(&p->t, NULL, nal_thread, b)) {
- perror("nal_init: pthread_create");
- return(NULL);
- }
-
- unix_failure(read,p->from_lib[0], actual, sizeof(ptl_ni_limits_t),
- "tcp_init: read");
- unix_failure(read,p->from_lib[0], rc, sizeof(rc),
- "nal_init: read");
-
- if(*rc) return(NULL);
-
- initialized = 1;
+ /* init procbridge */
pthread_mutex_init(&p->mutex,0);
pthread_cond_init(&p->cond, 0);
+ p->nal_flags = 0;
- return (&api_nal);
-}
-#endif
-
-ptl_nid_t tcpnal_mynid;
-
-nal_t *procbridge_interface(int num_interface,
- ptl_pt_index_t ptl_size,
- ptl_ac_index_t acl_size,
- ptl_pid_t requested_pid)
-{
- procbridge p;
- bridge b;
- static int initialized=0;
- ptl_ni_limits_t limits = {-1,-1,-1,-1,-1};
- int rc, nal_type = PTL_IFACE_TCP;/* PTL_IFACE_DEFAULT FIXME hack */
-
- if(initialized) return (&api_nal);
-
- init_unix_timer();
-
- b=(bridge)malloc(sizeof(struct bridge));
- p=(procbridge)malloc(sizeof(struct procbridge));
- api_nal.nal_data=b;
- b->local=p;
-
- if(pipe(p->to_lib) || pipe(p->from_lib)) {
- perror("nal_init: pipe");
- return(NULL);
+ /* initialize notifier */
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, p->notifier)) {
+ perror("socketpair failed");
+ return PTL_FAIL;
}
- if (ptl_size)
- limits.max_ptable_index = ptl_size;
- if (acl_size)
- limits.max_atable_index = acl_size;
-
- unix_failure(write,p->to_lib[1], &requested_pid, sizeof(requested_pid),
- "nal_init: write");
- unix_failure(write,p->to_lib[1], &limits, sizeof(ptl_ni_limits_t),
- "nal_init: write");
- unix_failure(write,p->to_lib[1], &nal_type, sizeof(nal_type),
- "nal_init: write");
+ if (!register_io_handler(p->notifier[1], READ_HANDLER,
+ procbridge_notifier_handler, p)) {
+ perror("fail to register notifier handler");
+ return PTL_FAIL;
+ }
- if(pthread_create(&p->t, NULL, nal_thread, b)) {
+ /* create nal thread */
+ if (pthread_create(&p->t, NULL, nal_thread, &args)) {
perror("nal_init: pthread_create");
- return(NULL);
+ return PTL_FAIL;
}
- unix_failure(read,p->from_lib[0], &rc, sizeof(rc),
- "nal_init: read");
+ do {
+ pthread_mutex_lock(&p->mutex);
+ if (p->nal_flags & (NAL_FLAG_RUNNING | NAL_FLAG_STOPPED)) {
+ pthread_mutex_unlock(&p->mutex);
+ break;
+ }
+ pthread_cond_wait(&p->cond, &p->mutex);
+ pthread_mutex_unlock(&p->mutex);
+ } while (1);
- if(rc) return(NULL);
+ if (p->nal_flags & NAL_FLAG_STOPPED)
+ return PTL_FAIL;
- b->nal_cb->ni.nid = tcpnal_mynid;
- initialized = 1;
- pthread_mutex_init(&p->mutex,0);
- pthread_cond_init(&p->cond, 0);
+ b->lib_nal->libnal_ni.ni_pid.nid = tcpnal_mynid;
- return (&api_nal);
+ return PTL_OK;
}
-#undef unix_failure