Code Search for Developers
 
 
  

usfusd_local.c from EmStar at Krugle


Show usfusd_local.c syntax highlighted

/*
 *
 * Copyright (c) 2003 The Regents of the University of California.  All 
 * rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Neither the name of the University nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
 
/*
 *  file operations
 */


static
int usfusd_pollnow(client_conn_t *conn, int *events)
{
  struct pollfd pfd = {
    fd: conn->parent->local_fd,
    events: *events
  };
  
  int retval = poll(&pfd, 1, 0);
  if (retval == -1)
    retval = -errno;
  
  *events = pfd.revents;

  return retval;
}


static
int usfusd_on_deck(client_conn_t *conn, int block_type)
{
  return (conn == conn->parent->blocked[block_type]);
}


static
usfusd_msg_t *usfusd_msg_copy(usfusd_msg_t *msg)
{
  usfusd_msg_t *retval = malloc(sizeof(usfusd_msg_t));
  memmove(retval, msg, sizeof(usfusd_msg_t));  
  return retval;
}


static
void usfusd_block(client_conn_t *conn, usfusd_msg_t *msg, char *buf, int block_type)
{
  /* try to be on deck */
  if (conn->parent->blocked[block_type] == NULL) 
    conn->parent->blocked[block_type] = conn;
  
  /* enable us if we're on deck */
  usfusd_proto_set_enable(ptr->proto, usfusd_on_deck(conn, block_type));
  
  /* save message */
  conn->blocked_msg = usfusd_msg_copy(msg);

  /* save buf if present */
  if (buf) {
    conn->blocked_buf = malloc(msg->datalen);
    memmove(conn->blocked_buf, buf, msg->datalen);
  }

  /* save type */
  conn->block_type = block_type;
}


static
void usfusd_unblock(client_t *c, int block_type)
{
  client_conn_t *last = c->blocked[block_type];
  client_conn_t *ptr = last;
  usfusd_msg_t *msg;
  char *buf;

  /* unblock */

  /* if last is bogus, find the next blocked conn */
  if ((last == NULL) || last->defunct)
    goto seek_next;

 run_ptr:
  /* run this connection now */

  /* save out these parameters */
  msg = ptr->blocked_msg;
  buf = ptr->blocked_buf;
  ptr->blocked_msg = NULL;
  ptr->blocked_buf = NULL;
  
  /* now perform the syscall */
  switch (block_type) {
  case BLOCK_READ:
    usfusd_read(ptr, msg);
    break;
  case BLOCK_WRITE:
    usfusd_write(ptr, msg, buf);
    break;
  }

  /* free the parameters */
  free(msg);
  if (buf) free(buf);
  
 seek_next:
  /* seek out the next item */

  c->blocked[block_type] = NULL;
  ptr = usfusd_conns_next(last);

  while (ptr != last) {
    /* is this guy trying to block for this type? */
    if (ptr->blocked_msg && (ptr->block_type == block_type))
      goto run_ptr;

    /* next */
    if (ptr) ptr = usfusd_conns_next(ptr);
    else ptr = usfusd_conns_top(c);
  }

  /* nothing to block.. */
  return;

}


void usfusd_unblock_if(client_conn_t *conn)
{
  int i;
  for (i=0; i<BLOCK_MAX; i++) 
    if (conn->parent->blocked[i] == conn)
      usfusd_unblock(conn, i);
}


static
int usfusd_unblock_read(void *data, int fd, int cond, g_event_t *event)
{
  usfusd_unblock((client_t *)data, READ_BLOCK);
  return EVENT_RENEW;
}


static
int usfusd_unblock_write(void *data, int fd, int cond, g_event_t *event)
{
  usfusd_unblock((client_t *)data, WRITE_BLOCK);
  return EVENT_RENEW;
}


void usfusd_read(client_conn_t *conn, usfusd_msg_t *msg)
{
  if (conn->parent->usfusd_device)
    usfusd_read_fusd(conn, msg);

  else {
    char *buf = NULL;

    /* poll now */
    int events = POLLIN;
    msg->retval = usfusd_pollnow(conn, &events);

    /* poll OK */
    if (msg->retval >= 0) {
    
      /* if data present, read */
      if (events & POLLIN) {
	buf = malloc(msg->length);
	msg->retval = read(conn->parent->local_fd, buf, msg->length);
	if (msg->retval < 0)
	  msg->retval = -errno;
      }

      /* otherwise */
      else {

	/* if nonblocking */
	if (conn->parent->flags & O_NONBLOCK) 
	  msg->retval = -EAGAIN;	

	else {
	  /* block this client */
	  usfusd_block(conn, msg, NULL, READ_BLOCK);

	  /* enable the local read event if present */
	  g_event_set_enable(conn->parent->local_event[READ_BLOCK], 1);
	  return;
	}
      }
    }

    /* reply */
    usfusd_proto_send(conn->proto, msg, buf);

    /* clean up */
    if (buf) free(buf);

    /* check for bad FD */
    if (msg->retval == -EBADFD)
      usfusd_conn_close(conn);
  }
}


void usfusd_write(client_conn_t *conn, usfusd_msg_t *msg, char *buf)
{
  if (conn->parent->usfusd_device)
    usfusd_write_fusd(conn, msg, buf);

  else {
    char *buf = NULL;

    /* poll now */
    int events = POLLOUT;
    msg->retval = usfusd_pollnow(conn, &events);

    /* poll OK */
    if (msg->retval >= 0) {
    
      /* if data present, read */
      if (events & POLLOUT) {
	msg->retval = write(conn->parent->local_fd, buf, msg->length);
	if (msg->retval < 0)
	  msg->retval = -errno;
      }

      /* otherwise */
      else {

	/* if nonblocking */
	if (conn->parent->flags & O_NONBLOCK) 
	  msg->retval = -EAGAIN;	

	else {
	  /* block this client */
	  usfusd_block(conn, msg, buf, WRITE_BLOCK);
	  
	  /* enable the local read event if present */
	  g_event_set_enable(conn->parent->local_event[WRITE_BLOCK], 1);
	  return;
	}
      }
    }
    
    /* reply */
    usfusd_proto_send(conn->proto, msg, NULL);
    
    /* check for bad FD */
    if (msg->retval == -EBADFD)
      usfusd_conn_close(conn);
  }
}


void usfusd_ioctl(client_conn_t *conn, usfusd_msg_t *msg, char *buf)
{
  if (conn->parent->usfusd_device)
    usfusd_ioctl_fusd(conn, msg, buf);

  else {
    msg->retval = ioctl(conn->parent->local_fd, msg->cmd, buf);
    if (msg->retval == -1)
      msg->retval = -errno;
    usfusd_proto_send(conn->proto, msg, buf); 

    if (msg->retval == -EBADFD)
      usfusd_conn_close(conn);
  }
}


void usfusd_fcntl(client_conn_t *conn, usfusd_msg_t *msg)
{
  conn->parent->flags = msg->arg;
}


int usfusd_poll2fusd(int poll)
{
  int cond = 0;

  /* convert to fusd cond */
  if (c->revents & POLLIN)
    cond |= FUSD_NOTIFY_INPUT;
  if (c->revents & POLLOUT)
    cond |= FUSD_NOTIFY_OUTPUT;
  if (c->revents & (POLLHUP | POLLPRI | POLLERR))
    cond |= FUSD_NOTIFY_EXCEPT;  
  
  return cond;
}


int usfusd_fusd2poll(int fusd)
{
  int poll = 0;

  /* convert to fusd cond */
  if (fusd & FUSD_NOTIFY_INPUT)
    poll |= POLLIN;
  if (fusd & FUSD_NOTIFY_OUTPUT)
    poll |= POLLOUT;
  if (fusd & FUSD_NOTIFY_EXCEPT)
    poll |= POLLPRI;
  
  return cond;
}


int usfusd_handle_poll(void *data, int fd, int cond, g_event_t *event)
{
  client_t *c = (client_t*)data;
  client_conn_t *ptr = NULL;
  int poll = usfusd_fusd2poll(cond);
  
  /* update client flags */
  for (ptr = usfusd_conns_top(c); ptr; usfusd_conns_next(ptr)) 
    if (ptr->poll_msg && (ptr->revents & poll)) {
      /* reply */
      ptr->poll_msg->cmd = poll & ptr->revents;
      usfusd_proto_send(conn->proto, msg, NULL);      /* $$$ check retval ? */
      
      ptr->revents = 0;
      free(ptr->poll_msg);
      ptr->poll_msg = NULL;
    }
  
  usfusd_update_poll(c);
  return EVENT_DONE;
}

static
void usfusd_update_poll(client_t *c)
{
  client_conn_t *ptr = NULL;
  int cond;
  
  /* update client flags */
  c->revents = 0;
  for (ptr = usfusd_conns_top(c); ptr; usfusd_conns_next(ptr)) 
    c->revents |= ptr->revents;

  /* destroy and create new event */
  g_event_destroy(c->poll_event);

  cond = usfusd_poll2fusd(c->revents);  
  if (cond) 
    g_event_add(c->local_fd, cond, usfusd_handle_poll, c, NULL. &(c->poll_event));
}


void usfusd_poll(client_conn_t *conn, usfusd_msg_t *msg, int diff)
{
  if (conn->parent->usfusd_device)
    usfusd_poll_fusd(conn, msg, diff);

  else {

    /* poll now */
    int result = msg->cmd;
    msg->retval = usfusd_pollnow(conn, &result);

    /* clear the conn's revents flags */
    conn->revents = 0;
    
    if (msg->retval >= 0) {
      
      /* if immediate poll or the result flagged something */
      if ((diff == 0) || result) {
	msg->cmd = result;
	msg->retval = usfusd_proto_send(conn->proto, msg, NULL); 
      }
      
      /* save if diff requested */
      else if (diff) {
	/* save events and copy of message */
	conn->revents = msg->cmd;
	conn->poll_msg = ufusd_msg_copy(msg);
      }
    }
    
    /* recompute poll flags and reset event */
    usfusd_poll_update(conn->parent);
    
    if (msg->retval == -EBADFD)
      usfusd_conn_close(conn);
  }
}


void usfusd_dup(client_conn_t *conn, usfusd_msg_t *msg)
{
  client_t *c;
  int retval = ENOENT;

  /* only open once per connection */
  if (conn->parent->usfusd_fileno) {
    retval = EBUSY;
    goto reply;
  }

  /* search for existing client */
  for (c = usfusd_clients_top(&state); c; s = usfusd_clients_next(c)) {
    if (c->usfusd_fileno == msg->arg) {
      usfusd_conn_dequeue(conn);
      usfusd_conns_push(c, conn);
      conn->parent = c;
      retval = 0;
      goto reply;
    }
  }

 reply:
  msg->retval = -retval;
  usfusd_proto_send(conn->proto, msg, NULL);
}


void usfusd_open(client_conn_t *conn, usfusd_msg_t *msg, char *data_buf)
{
  int fd;
  int retval = 0;

  /* only open once per connection */
  if (conn->parent->usfusd_fileno) {
    retval = EBUSY;
    goto reply;
  }

  /* data buffer must be valid */
  if (data_buf == NULL) {
    retval = ENOENT;
    goto reply;
  }

  /* null-term (should be already..) */
  data_buf[msg->datalen-1] = 0;
  
  /* try to open directly */
  fd = open(data_buf, msg->arg);

  /* error? */
  if (fd < 0) {

    /* most error transparent */
    if (errno != ENOENT) {
      retval = errno;
      goto reply;
    }

    retval = usfusd_open_fusd(conn, msg);
    goto reply;
  }

  /* success.  save fd */
  conn->parent->local_fd = fd;
  retval = 0;

  /* create and disable read event */
  if (g_event_add(fd, FUSD_NOTIFY_INPUT, usfusd_unblock_read, conn->parent,
		  NULL, &(conn->parent->local_event[READ_BLOCK])) < 0) {
    elog(LOG_CRIT, "Failed to create event for local fd: %m\n");
    exit(1);
  }
  g_event_set_enable(conn->parent->local_event[READ_BLOCK], 0);

  /* create and disable write event */
  if (g_event_add(fd, FUSD_NOTIFY_OUTPUT, usfusd_unblock_write, conn->parent,
		  NULL, &(conn->parent->local_event[WRITE_BLOCK])) < 0) {
    elog(LOG_CRIT, "Failed to create event for local fd: %m\n");
    exit(1);
  }
  g_event_set_enable(conn->parent->local_event[WRITE_BLOCK], 0);

 reply:
  conn->parent->usfusd_fileno = usfusd_new_fileno();
  msg->retval = -retval;
  msg->arg = conn->parent->usfusd_fileno;  
  usfusd_proto_send(conn->proto, msg, NULL);
}






See more files for this project here

EmStar

EmStar is a software system for developing and deploying wireless sensor networks involving Linux-based platforms. As the wireless sensor network community has attempted to deploy more complex designs---large-scale, long-lived systems that need self-organization and adaptivity---a number of difficult software design issues have arisen. Advances in software design have not kept pace with the capabilities of hardware. This is because designing for an adaptive, efficient, and useful sensor network has turned out to be surprisingly complex and difficult. EmStar is a Linux-based software framework, whose goal is to dramatically reduce this complexity, enabling work to be shared and reused, and simplifying and speeding the design of new sensor network applications.

Project homepage: http://cvs.cens.ucla.edu/emstar/
Programming language(s): C,Shell Script
License: other

  usfusd.c
  usfusd_fusd.c
  usfusd_i.h
  usfusd_local.c