#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>
+/* XXX CFS workaround, to give a chance to let nal thread wake up
+ * from waiting in select
+ */
+static int procbridge_notifier_handler(void *arg)
+{
+ static char buf[8];
+ procbridge p = (procbridge) arg;
+
+ syscall(SYS_read, p->notifier[1], buf, sizeof(buf));
+ return 1;
+}
+
+void procbridge_wakeup_nal(procbridge p)
+{
+ static char buf[8];
+ syscall(SYS_write, p->notifier[0], buf, sizeof(buf));
+}
+
/* Function: forward
* Arguments: nal_t *nal: pointer to my top-side nal structure
* id: the command to pass to the lower layer
* side, and collects the result
*/
static int procbridge_forward(nal_t *n, int id, void *args, size_t args_len,
- void *ret, ptl_size_t ret_len)
+ void *ret, size_t ret_len)
{
bridge b = (bridge) n->nal_data;
* 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;
procbridge p=(procbridge)b->local;
p->nal_flags |= NAL_FLAG_STOPPING;
+ procbridge_wakeup_nal(p);
do {
pthread_mutex_lock(&p->mutex);
} while (1);
free(p);
- return(0);
}
-/* Function: validate
- * useless stub
- */
-static int procbridge_validate(nal_t *nal, void *base, size_t extent)
+static void procbridge_lock(nal_t * n, unsigned long *flags)
{
- return(0);
+ bridge b=(bridge)n->nal_data;
+ procbridge p=(procbridge)b->local;
+
+ pthread_mutex_lock(&p->mutex);
}
+static void procbridge_unlock(nal_t * n, unsigned long *flags)
+{
+ bridge b=(bridge)n->nal_data;
+ procbridge p=(procbridge)b->local;
+
+ pthread_mutex_unlock(&p->mutex);
+}
/* Function: yield
* Arguments: pid:
* overload it to explicitly block until signalled by the
* lower half.
*/
-static void procbridge_yield(nal_t *n)
+static int procbridge_yield(nal_t *n, unsigned long *flags, int milliseconds)
{
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);
+ if (milliseconds == 0)
+ return 0;
+
+ if (milliseconds < 0) {
+ pthread_cond_wait(&p->cond,&p->mutex);
+ } else {
+ struct timeval then;
+ struct timeval now;
+ struct timespec timeout;
+
+ gettimeofday(&then, NULL);
+ timeout.tv_sec = then.tv_sec + milliseconds/1000;
+ timeout.tv_nsec = then.tv_usec * 1000 + milliseconds % 1000 * 1000000;
+ if (timeout.tv_nsec >= 1000000000) {
+ timeout.tv_sec++;
+ timeout.tv_nsec -= 1000000000;
+ }
+
+ pthread_cond_timedwait(&p->cond, &p->mutex, &timeout);
+
+ gettimeofday(&now, NULL);
+ milliseconds -= (now.tv_sec - then.tv_sec) * 1000 +
+ (now.tv_usec - then.tv_usec) / 1000;
+
+ if (milliseconds < 0)
+ milliseconds = 0;
+ }
+
+ return (milliseconds);
}
+/* forward decl */
+extern int procbridge_startup (nal_t *, ptl_pid_t,
+ ptl_ni_limits_t *, ptl_ni_limits_t *);
-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.
* TODO: should be dyanmically allocated
*/
-static nal_t api_nal = {
- ni: {0},
+nal_t procapi_nal = {
nal_data: NULL,
- forward: procbridge_forward,
+ startup: procbridge_startup,
shutdown: procbridge_shutdown,
- validate: procbridge_validate,
+ forward: procbridge_forward,
yield: procbridge_yield,
lock: procbridge_lock,
unlock: procbridge_unlock
ptl_nid_t tcpnal_mynid;
-/* Function: procbridge_interface
+/* 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.
*/
-nal_t *procbridge_interface(int num_interface,
- ptl_pt_index_t ptl_size,
- ptl_ac_index_t acl_size,
- ptl_pid_t requested_pid)
+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;
+ nal->nal_data=b;
b->local=p;
- if (ptl_size)
- limits.max_ptable_index = ptl_size;
- if (acl_size)
- limits.max_atable_index = acl_size;
-
args.nia_requested_pid = requested_pid;
- args.nia_limits = &limits;
+ args.nia_requested_limits = requested_limits;
+ args.nia_actual_limits = actual_limits;
args.nia_nal_type = nal_type;
args.nia_bridge = b;
pthread_mutex_init(&p->mutex,0);
pthread_cond_init(&p->cond, 0);
p->nal_flags = 0;
- pthread_mutex_init(&p->nal_cb_lock, 0);
+ /* initialize notifier */
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, p->notifier)) {
+ perror("socketpair failed");
+ return PTL_FAIL;
+ }
+
+ if (!register_io_handler(p->notifier[1], READ_HANDLER,
+ procbridge_notifier_handler, p)) {
+ perror("fail to register notifier handler");
+ return PTL_FAIL;
+ }
+
+ /* create nal thread */
if (pthread_create(&p->t, NULL, nal_thread, &args)) {
perror("nal_init: pthread_create");
- return(NULL);
+ return PTL_FAIL;
}
do {
} while (1);
if (p->nal_flags & NAL_FLAG_STOPPED)
- return (NULL);
+ return PTL_FAIL;
b->nal_cb->ni.nid = tcpnal_mynid;
- initialized = 1;
- return (&api_nal);
+ return PTL_OK;
}