Esempio n. 1
0
void client_process(int fd, short events)
{
	struct mux_client *client = NULL;
	pthread_mutex_lock(&client_list_mutex);
	FOREACH(struct mux_client *lc, &client_list) {
		if(lc->fd == fd) {
			client = lc;
			break;
		}
	} ENDFOREACH
	pthread_mutex_unlock(&client_list_mutex);

	if(!client) {
		usbmuxd_log(LL_INFO, "client_process: fd %d not found in client list", fd);
		return;
	}

	if(client->state == CLIENT_CONNECTED) {
		usbmuxd_log(LL_SPEW, "client_process in CONNECTED state");
		device_client_process(client->connect_device, client, events);
	} else {
		if(events & POLLIN) {
			process_recv(client);
		} else if(events & POLLOUT) { //not both in case client died as part of process_recv
			process_send(client);
		}
	}

}
Esempio n. 2
0
/**
 * ish_cl_event_cb() - bus driver callback for incoming message/packet
 * @device:	Pointer to the the ishtp client device for which this message
 *		is targeted
 *
 * Remove the packet from the list and process the message by calling
 * process_recv
 */
static void ish_cl_event_cb(struct ishtp_cl_device *device)
{
	struct ishtp_cl	*hid_ishtp_cl = device->driver_data;
	struct ishtp_cl_rb *rb_in_proc;
	size_t r_length;
	unsigned long flags;

	if (!hid_ishtp_cl)
		return;

	spin_lock_irqsave(&hid_ishtp_cl->in_process_spinlock, flags);
	while (!list_empty(&hid_ishtp_cl->in_process_list.list)) {
		rb_in_proc = list_entry(
			hid_ishtp_cl->in_process_list.list.next,
			struct ishtp_cl_rb, list);
		list_del_init(&rb_in_proc->list);
		spin_unlock_irqrestore(&hid_ishtp_cl->in_process_spinlock,
			flags);

		if (!rb_in_proc->buffer.data)
			return;

		r_length = rb_in_proc->buf_idx;

		/* decide what to do with received data */
		process_recv(hid_ishtp_cl, rb_in_proc->buffer.data, r_length);

		ishtp_cl_io_rb_recycle(rb_in_proc);
		spin_lock_irqsave(&hid_ishtp_cl->in_process_spinlock, flags);
	}
	spin_unlock_irqrestore(&hid_ishtp_cl->in_process_spinlock, flags);
}
Esempio n. 3
0
static gboolean
on_transport_recv (CockpitTransport *transport,
                   const gchar *channel_id,
                   GBytes *data,
                   gpointer user_data)
{
  CockpitChannel *self = user_data;

  if (g_strcmp0 (channel_id, self->priv->id) != 0)
    return FALSE;

  process_recv (self, data);
  return TRUE;
}
Esempio n. 4
0
static gboolean
on_transport_recv (CockpitTransport *transport,
                   const gchar *channel_id,
                   GBytes *data,
                   gpointer user_data)
{
  CockpitChannel *self = user_data;

  if (g_strcmp0 (channel_id, self->priv->id) != 0)
    return FALSE;

  if (self->priv->frozen)
    g_queue_push_tail (self->priv->frozen, frozen_message_new (data, NULL));
  else
    process_recv (self, data);

  return TRUE;
}
Esempio n. 5
0
static void proc_net_data_recv(i32 net)
{
        struct client_ctx *cl_ctx = net_cl_ctx_find(net);
        bool dummy;
        i32 rv;

        mqp_reset(&rx_mqp); /* Start w/ a clean buffer */

        rv = net_recv(net, &rx_mqp, 0, &dummy);
        if(rv > 0)
                /* Working Principle: Only RX processing errors should be
                   reported as 'false'. Status of TX as a follow-up to RX
                   messages need not be reported by the xyz_rx() routines.
                   Error observed in TX is dealt in the next iteration of
                   the RX loop.
                */
                if(false == process_recv(cl_ctx, &rx_mqp))
                        rv = MQP_ERR_CONTENT;

        if(rv < 0)
                do_net_close_rx(cl_ctx, true);
}
Esempio n. 6
0
/**
 * cockpit_channel_ready:
 * @self: a pipe
 * @message: an optional control message, or NULL
 *
 * Called by channel implementations to signal when they're
 * ready. Any messages received before the channel was ready
 * will be delivered to the channel's recv() vfunc in the order
 * that they were received.
 *
 * If this is called immediately after or during construction then
 * the closing will happen after the main loop so that handlers
 * can connect appropriately.
 */
void
cockpit_channel_ready (CockpitChannel *self,
                       JsonObject *message)
{
  FrozenMessage *frozen;

  g_return_if_fail (self->priv->frozen != NULL);

  g_object_ref (self);

  while (self->priv->frozen)
    {
      frozen = g_queue_pop_head (self->priv->frozen);
      if (frozen == NULL)
        break;

      /* Is it a control message */
      if (frozen->control)
        {
          process_control (self, json_object_get_string_member (frozen->control, "command"),
                           frozen->control);
        }
      else
        {
          process_recv (self, frozen->payload);
        }

      frozen_message_free (frozen);
    }

  if (self->priv->frozen)
    g_queue_free (self->priv->frozen);
  self->priv->frozen = NULL;

  cockpit_channel_control (self, "ready", message);

  g_object_unref (self);
}
Esempio n. 7
0
File: main.c Progetto: inste/reader
int event_loop(char * device_file, int port, int log_fd) {
	int tty_fd, is_dev_opened;
	char data[BUFFER], device_data[BUFFER];
	int count, data_count;
	int i, j;

	int listen_fd;
	int log_listen_fd;
	int log_sock_fd = -1;
	int sock_fd[BUFFER];
	int sock_fd_count = 0;

	struct sockaddr_in	sa = { 0 };
	socklen_t		sl = sizeof(sa);

	int finished;

	time_t open_time;

	char * reqs, * logtmp;

	fd_set rfds;
	struct timeval tv;
	int retval;

	start_time = time(NULL);

	listen_fd = open_socket(port);
	listen(listen_fd, 25);

	log_listen_fd = open_socket(LOG_PORT);
	listen(log_listen_fd, 2);

	reqs = (char *)malloc(sizeof(char) * BUFFER * (SMALL + 1));
	logtmp = (char *)malloc(sizeof(char) * BUFFER);

	for (i = 0; i < ITEMS_COUNT; ++i) {
		memset(global_data[i].key, 0, SMALL);
		memset(global_data[i].value, 0, SMALL);
	}

	is_dev_opened = 0;

	snprintf(logtmp, BUFFER, "Process started");
	write_log(log_fd, log_sock_fd, logtmp);

	while (1) {

		if (!is_dev_opened) {
			tty_fd = open_device(device_file);
			++is_dev_opened;
			open_time = time(NULL);

			if (tty_fd > 0) {
				last_update = time(NULL);
				usleep(MICROSLEEP);
			}
			if (-ENXIO == tty_fd) {
				snprintf(logtmp, BUFFER, "Device file %s doesn't exist", device_file);
				write_log(log_fd, log_sock_fd, logtmp);
				is_dev_opened = 0;
				usleep(MICROSLEEP);
			}
			if (!tty_fd) {
				snprintf(logtmp, BUFFER, "Device file %s can't be opened", device_file);
				write_log(log_fd, log_sock_fd, logtmp);
				is_dev_opened = 0;
				usleep(MICROSLEEP);
			}
		} else {
			open_time = time(NULL);
		}

		tv.tv_sec = 0;
		tv.tv_usec = MICROSLEEP;

		FD_ZERO(&rfds);
		FD_SET(listen_fd, &rfds);
		FD_SET(log_listen_fd, &rfds);

		if (is_dev_opened)
			FD_SET(tty_fd, &rfds);

		if (log_sock_fd > 0)
			FD_SET(log_sock_fd, &rfds);

		for (i = 0; i < sock_fd_count; ++i)
			FD_SET(sock_fd[i], &rfds);

		retval = select(
				get_max(tty_fd,
					listen_fd,
					log_listen_fd,
					log_sock_fd,
					sock_fd,
					sock_fd_count) + 1,
				&rfds,
				NULL,
				NULL,
				&tv);
		if (retval) {

			if (is_dev_opened && FD_ISSET(tty_fd, &rfds)) {
				char temp1[BUFFER];
				count = read(tty_fd, temp1, BUFFER);

				if (count + data_count > BUFFER) {
					goto device_reading_cleanup;
				}

				finished = 0;
				for (i = 0; i < count; ++i) {
					if (';' == temp1[i]) {
						++finished;
						break;
					}
				}

				memcpy(device_data + data_count, temp1, count * sizeof(char));
				data_count += count;

				if ((time(NULL) - open_time) > OUTDATE_TIMEOUT) { // Device vanished during reading, 10 sec timeout
					snprintf(logtmp, BUFFER, "Device  %s vanished during reading, closing", device_file);
					write_log(log_fd, log_sock_fd, logtmp);

					goto device_reading_cleanup;
				}

				if (finished) {
					device_data[data_count] = '\0';

					if (-1 == process_recv(log_fd, log_sock_fd, device_data)) {
						last_update = 0;
					}

					goto device_reading_cleanup;
				}

				goto device_reading_exit;

device_reading_cleanup:
				data_count = 0;
				continue;
device_reading_exit:
				;;
			}

			if (FD_ISSET(listen_fd, &rfds)) {
				sock_fd[sock_fd_count] = accept(listen_fd, (struct sockaddr *)&sa, &sl);
				getpeername(sock_fd[sock_fd_count], (struct sockaddr *)&sa, &sl);
				memset(reqs + sock_fd_count * (SMALL + 1), 0, sizeof(char) * (SMALL + 1));
				++sock_fd_count;

				snprintf(logtmp, BUFFER,
						"Accepted data connection from %s, has %d conns",
						inet_ntoa(sa.sin_addr), sock_fd_count);
				write_log(log_fd, log_sock_fd, logtmp);
				continue;
			}
			if (FD_ISSET(log_listen_fd, &rfds)) {
				if (log_sock_fd > 0) { // Closing previous connection
					close(log_sock_fd);
				}

				log_sock_fd = accept(log_listen_fd, (struct sockaddr *)&sa, &sl);
				getpeername(log_sock_fd, (struct sockaddr *)&sa, &sl);
				snprintf(logtmp, BUFFER, "Accepted log connection from %s", inet_ntoa(sa.sin_addr));
				write_log(log_fd, log_sock_fd, logtmp);
				continue;
			}
			if (log_sock_fd > -1 && FD_ISSET(log_sock_fd, &rfds)) {
				j = 0;
				ioctl(log_sock_fd, FIONREAD, &j);
				if (!j) { // Socket was closed on client
					close(log_sock_fd);
					log_sock_fd = -1;

					snprintf(logtmp, BUFFER, "Log connection closed");
					write_log(log_fd, log_sock_fd, logtmp);
				} else {// Data arrived to read should be ignored on this sock
					char temp1[BUFFER];
					read(log_sock_fd, temp1, BUFFER);
				}
			}
			for (i = 0; i < sock_fd_count; ++i) {
				if (FD_ISSET(sock_fd[i], &rfds)) {
					j = 0;
					ioctl(sock_fd[i], FIONREAD, &j);

					if (!j) { // Socket was closed, cleaning up
						close(sock_fd[i]);
						memmove(sock_fd + i, sock_fd + i + 1, sizeof(int) * sock_fd_count - i - 1);
						--sock_fd_count;

						snprintf(logtmp, BUFFER, "Closed, has %d conns", sock_fd_count);
						write_log(log_fd, log_sock_fd, logtmp);
						continue;
					} else {
						count = read(sock_fd[i], data, SMALL);

						if (count + *(reqs + i * (SMALL + 1)) <= SMALL) { // Unexpectedly big request?
							memcpy(reqs + i * (SMALL + 1) + *(reqs + i * (SMALL + 1)) + 1, data, count);
							*(reqs + i * (SMALL + 1)) += count;

							finished = 0;
							for (j = 0; j < *(reqs + i * (SMALL + 1)); ++j) {
								if ('\n' == *(reqs + i * (SMALL + 1) + 1 + j)) {
									finished = 2;  // Zabbix protocol
									break;
								}
							}

							if (finished) {
								*(reqs + i * (SMALL + 1) + j + 1) = 0x00;
								process_zabbix(reqs + i * (SMALL + 1) + 1, sock_fd[i]);
								*(reqs + i * (SMALL + 1)) = 0x00;
							}
						} else {
								count = snprintf(data, SMALL, "BIG_REQUEST\r");
								write(sock_fd[i], data, count);
						}
					}
				}
			}
		}

		if (!retval) {
			if (is_dev_opened && time(NULL) - last_update > OUTDATE_TIMEOUT) {
				data_count = 0;
				close(tty_fd);
				is_dev_opened = 0;

				snprintf(logtmp, BUFFER, "Endpoint communication was lost during reading (%u %u), reopen",
					(unsigned int)time(NULL), (unsigned int)last_update);
				write_log(log_fd, log_sock_fd, logtmp);
			}
		}
	}

	free(reqs);
	free(logtmp);

	return 0;
}
Esempio n. 8
0
File: srv.c Progetto: pivovard/ZCU
int main(int argc, char **argv)
{
  fd_set master_fds; /* master file descriptor list */
  fd_set read_fds; /* temp file descriptor list for read events */
  fd_set write_fds; /* temp file descriptor list for write events */

  int listen_sock, fdmax;
  int optval;
  int i;
  struct sockaddr_in addr;
  char *reply;

  /* this should be implemented as a generic map socket:offset,
    -1 ... not connected, >=0 ... amount of sent bytes */
  int sock_to_offset[SOCKET_MAX];

  /**********/

  for (i = 0; i < SOCKET_MAX; i++) sock_to_offset[i] = NOT_CONNECTED;

  reply = generate_large_message();

  /* clear the master and temp sets */
  FD_ZERO(&master_fds);
  FD_ZERO(&read_fds);
  FD_ZERO(&write_fds);

  /* create socket */
  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (listen_sock < 0) err("socket()");

  /* non-blocking operation */
  optval = 1;
  if (ioctl(listen_sock, FIONBIO, (char *)&optval) < 0)
  {
    close(listen_sock);
    err("ioctl nonblock");
  }  

  /* set reusable flag */
  optval = 1;
  setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));

  /* prepare inet address */
  memset(&addr, 0, sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_port = htons(SRV_PORT);
  addr.sin_addr.s_addr = htonl(INADDR_ANY); /* listen on all interfaces */
  if (bind(listen_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) err("bind");

  if (listen(listen_sock, 10) < 0) err("listen");

  /* add the listener to the master set */
  FD_SET(listen_sock, &master_fds);
  /* keep track of the biggest file descriptor */
  fdmax = listen_sock; /* so far, it's this one*/

  for(;;)
  {
    /* copy it */
    memcpy(&read_fds, &master_fds, sizeof(master_fds));
    memcpy(&write_fds, &master_fds, sizeof(master_fds));

    /* wait for any action */
    if (select(fdmax + 1, &read_fds, &write_fds, NULL, NULL) == -1)
    {
      close(listen_sock);
      err("select");
    }
    printf("select is OK\n");

    for (i = 0; i <= fdmax; i++)
    {
      if (FD_ISSET(i, &read_fds))
      {
        /* the socket is the listening socket */
        if (i == listen_sock) process_accept(listen_sock, &master_fds, &fdmax,
                                            sock_to_offset);
        /* otherwise it is a connection socket ready for reading */
        else process_recv(i, &master_fds, &fdmax, reply, sock_to_offset);
      } else if (FD_ISSET(i, &write_fds)) {
        /* socket is ready to send data */
        process_send(i, &master_fds, &fdmax, reply, sock_to_offset);
      }
    }
  }

  return 0;
}
Esempio n. 9
0
File: vm.c Progetto: catseye/Bhuna
int
vm_run(struct vm *vm, int xmax)
{
	vm_label_t label;
	struct value l, r, v;
	struct activation *ar;
	struct builtin *ext_bi;
	int varity;
	int xcount = 0;
	struct value zero, one, two;
	/*int upcount, index; */

#ifdef DEBUG
	if (trace_vm) {
		printf("___ virtual machine started ___\n");
	}
#endif

	zero = value_new_integer(0);
	value_deregister(zero);
	one = value_new_integer(1);
	value_deregister(one);
	two = value_new_integer(2);
	value_deregister(two);

	while (*vm->pc != INSTR_HALT) {
#ifdef DEBUG
		if (trace_vm) {
			printf("#%d:\n", vm->pc - vm->program);
			dump_stack(vm);
		}
#endif
		if (((++xcount) & 0xff) == 0) {
			if (a_count + v_count > gc_target) {
#ifdef DEBUG
				if (trace_gc > 0) {
					printf("[ARC] GARBAGE COLLECTION STARTED on %d activation records + %d values\n",
						a_count, v_count);
					/*activation_dump(current_ar, 0);
					printf("\n");*/
					dump_activation_stack(vm);
				}
#endif
				gc();
#ifdef DEBUG
				if (trace_gc > 0) {
					printf("[ARC] GARBAGE COLLECTION FINISHED, now %d activation records + %d values\n",
						a_count, v_count);
					/*activation_dump(current_ar, 0);
					printf("\n");*/
				}
#endif
				/*
				 * Slide the target to account for the fact that there
				 * are now 'a_count' activation records in existence.
				 * Only GC when there are gc_trigger *more* ar's.
				 */
				gc_target = a_count + v_count + gc_trigger;
			}
			
			/*
			 * Also, give up control if we've exceeded our timeslice.
			 */
			if (xcount >= xmax)
				return(VM_TIME_EXPIRED);
		}

		switch (*vm->pc) {

#ifdef INLINE_BUILTINS
		case INDEX_BUILTIN_NOT:
			POP_VALUE(l);
			if (l.type == VALUE_BOOLEAN) {
				v = value_new_boolean(!l.v.b);
			} else {
				v = value_new_error("type mismatch");
			}
			PUSH_VALUE(v);
			break;
		case INDEX_BUILTIN_AND:
			POP_VALUE(r);
			POP_VALUE(l);
			if (l.type == VALUE_BOOLEAN && r.type == VALUE_BOOLEAN) {
				v = value_new_boolean(l.v.b && r.v.b);
			} else {
				v = value_new_error("type mismatch");
			}
			PUSH_VALUE(v);
			break;
		case INDEX_BUILTIN_OR:
			POP_VALUE(r);
			POP_VALUE(l);
			if (l.type == VALUE_BOOLEAN && r.type == VALUE_BOOLEAN) {
				v = value_new_boolean(l.v.b || r.v.b);
			} else {
				v = value_new_error("type mismatch");
			}
			PUSH_VALUE(v);
			break;

		case INDEX_BUILTIN_EQU:
			POP_VALUE(r);
			POP_VALUE(l);
			if (l.type == VALUE_INTEGER && r.type == VALUE_INTEGER) {
				v = value_new_boolean(l.v.i == r.v.i);
			} else if (l.type == VALUE_OPAQUE && r.type == VALUE_OPAQUE) {
				v = value_new_boolean(l.v.ptr == r.v.ptr);
			} else {
				v = value_new_error("type mismatch");
			}
			PUSH_VALUE(v);
			break;
		case INDEX_BUILTIN_NEQ:
			POP_VALUE(r);
			POP_VALUE(l);
			if (l.type == VALUE_INTEGER && r.type == VALUE_INTEGER) {
				v = value_new_boolean(l.v.i != r.v.i);
			} else {
				v = value_new_error("type mismatch");
			}
			PUSH_VALUE(v);
			break;
		case INDEX_BUILTIN_GT:
			POP_VALUE(r);
			POP_VALUE(l);
			if (l.type == VALUE_INTEGER && r.type == VALUE_INTEGER) {
				v = value_new_boolean(l.v.i > r.v.i);
			} else {
				v = value_new_error("type mismatch");
			}
			PUSH_VALUE(v);
			break;
		case INDEX_BUILTIN_LT:
			POP_VALUE(r);
			POP_VALUE(l);
			if (l.type == VALUE_INTEGER && r.type == VALUE_INTEGER) {
				v = value_new_boolean(l.v.i < r.v.i);
			} else {
				v = value_new_error("type mismatch");
			}
			PUSH_VALUE(v);
			break;
		case INDEX_BUILTIN_GTE:
			POP_VALUE(r);
			POP_VALUE(l);
			if (l.type == VALUE_INTEGER && r.type == VALUE_INTEGER) {
				v = value_new_boolean(l.v.i >= r.v.i);
			} else {
				v = value_new_error("type mismatch");
			}
			PUSH_VALUE(v);
			break;
		case INDEX_BUILTIN_LTE:
			POP_VALUE(r);
			POP_VALUE(l);
			if (l.type == VALUE_INTEGER && r.type == VALUE_INTEGER) {
				v = value_new_boolean(l.v.i <= r.v.i);
			} else {
				v = value_new_error("type mismatch");
			}
			PUSH_VALUE(v);
			break;

		case INDEX_BUILTIN_ADD:
			POP_VALUE(r);
			POP_VALUE(l);
			if (l.type == VALUE_INTEGER && r.type == VALUE_INTEGER) {
				v = value_new_integer(l.v.i + r.v.i);
			} else {
				v = value_new_error("type mismatch");
			}
			PUSH_VALUE(v);
			break;
		case INDEX_BUILTIN_MUL:
			POP_VALUE(r);
			POP_VALUE(l);
			if (l.type == VALUE_INTEGER && r.type == VALUE_INTEGER) {
				v = value_new_integer(l.v.i * r.v.i);
			} else {
				v = value_new_error("type mismatch");
			}
			PUSH_VALUE(v);
			break;
		case INDEX_BUILTIN_SUB:
			POP_VALUE(r);
			POP_VALUE(l);
			/* subs++; */
			if (l.type == VALUE_INTEGER && r.type == VALUE_INTEGER) {
				v = value_new_integer(l.v.i - r.v.i);
			} else {
				v = value_new_error("type mismatch");
			}
			PUSH_VALUE(v);
			break;
		case INDEX_BUILTIN_DIV:
			POP_VALUE(r);
			POP_VALUE(l);
			if (l.type == VALUE_INTEGER && r.type == VALUE_INTEGER) {
				if (r.v.i == 0)
					v = value_new_error("division by zero");
				else
					v = value_new_integer(l.v.i / r.v.i);
			} else {
				v = value_new_error("type mismatch");
			}
			PUSH_VALUE(v);
			break;
		case INDEX_BUILTIN_MOD:
			POP_VALUE(r);
			POP_VALUE(l);
			if (l.type == VALUE_INTEGER && r.type == VALUE_INTEGER) {
				if (r.v.i == 0)
					v = value_new_error("modulo by zero");
				else
					v = value_new_integer(l.v.i % r.v.i);
			} else {
				v = value_new_error("type mismatch");			}
			PUSH_VALUE(v);
			break;

#endif /* INLINE_BUILTINS */

		/*
		 * This sort of needs to be here even when INLINE_BUILTINS
		 * isn't used (in practice INLINE_BUILTINS will always be
		 * used anyway...)
		 */
		case INDEX_BUILTIN_RECV:
			POP_VALUE(l);
			r = value_null();

			if (l.type == VALUE_INTEGER) {
				if (!process_recv(&r)) {
					PUSH_VALUE(l);
					return(VM_WAITING);
				}
			} else {
				r = value_new_error("type mismatch");
			}
			PUSH_VALUE(r);
			break;

		case INSTR_PUSH_VALUE:
			l = *(struct value *)(vm->pc + 1);
#ifdef DEBUG
			if (trace_vm) {
				printf("INSTR_PUSH_VALUE:\n");
				value_print(l);
				printf("\n");
			}
#endif
			PUSH_VALUE(l);
			vm->pc += sizeof(struct value);
			break;

		case INSTR_PUSH_ZERO:
#ifdef DEBUG
			if (trace_vm) {
				printf("INSTR_PUSH_ZERO\n");
			}
#endif
			PUSH_VALUE(zero);
			break;
		case INSTR_PUSH_ONE:
#ifdef DEBUG
			if (trace_vm) {
				printf("INSTR_PUSH_ONE\n");
			}
#endif
			PUSH_VALUE(one);
			break;
		case INSTR_PUSH_TWO:
#ifdef DEBUG
			if (trace_vm) {
				printf("INSTR_PUSH_TWO\n");
			}
#endif
			PUSH_VALUE(two);
			break;

		case INSTR_PUSH_LOCAL:
			l = activation_get_value(vm->current_ar,
			    *(vm->pc + 1), *(vm->pc + 2));

#ifdef DEBUG
			if (trace_vm) {
				printf("INSTR_PUSH_LOCAL:\n");
				value_print(l);
				printf("\n");
			}
#endif
			PUSH_VALUE(l);
			vm->pc += sizeof(unsigned char) * 2;
			break;

		case INSTR_POP_LOCAL:
			POP_VALUE(l);
#ifdef DEBUG
			if (trace_vm) {
				printf("INSTR_POP_LOCAL:\n");
				value_print(l);
				printf("\n");
			}
#endif
			activation_set_value(vm->current_ar,
			    *(vm->pc + 1), *(vm->pc + 2), l);
			vm->pc += sizeof(unsigned char) * 2;
			break;

		case INSTR_INIT_LOCAL:
			POP_VALUE(l);
#ifdef DEBUG
			if (trace_vm) {
				printf("INSTR_INIT_LOCAL:\n");
				value_print(l);
				printf("\n");
			}
#endif
			activation_initialize_value(vm->current_ar,
			    *(vm->pc + 1), l);
			vm->pc += sizeof(unsigned char) * 2;
			break;

		case INSTR_JMP:
			label = *(vm_label_t *)(vm->pc + 1);
#ifdef DEBUG
			if (trace_vm) {
				printf("INSTR_JMP -> #%d:\n", label - vm->program);
			}
#endif
			vm->pc = label - 1;
			break;

		case INSTR_JZ:
			POP_VALUE(l);
			label = *(vm_label_t *)(vm->pc + 1);
#ifdef DEBUG
			if (trace_vm) {
				printf("INSTR_JZ -> ");
				value_print(l);
				printf(", #%d:\n", label - vm->program);
			}
#endif
			if (!l.v.b) {
				vm->pc = label - 1;
			} else {
				vm->pc += sizeof(vm_label_t);
			}
			break;

		case INSTR_CALL:
			POP_VALUE(l);
			label = l.v.s->v.k->label;
			if (l.v.s->v.k->cc > 0) {
				/*
				 * Create a new activation record
				 * on the heap for this call.
				 */
				ar = activation_new_on_heap(
				    l.v.s->v.k->arity +
				    l.v.s->v.k->locals,
				    vm->current_ar, l.v.s->v.k->ar);
			} else {
				/*
				 * Optimize by placing it on a stack.
				 */
				ar = activation_new_on_stack(
				    l.v.s->v.k->arity +
				    l.v.s->v.k->locals,
				    vm->current_ar, l.v.s->v.k->ar, vm);
			}
			/*
			 * Fill out the activation record.
			 */
			for (i = l.v.s->v.k->arity - 1; i >= 0; i--) {
				POP_VALUE(r);
				activation_initialize_value(ar, i, r);
			}

			vm->current_ar = ar;
#ifdef DEBUG
			if (trace_vm) {
				printf("INSTR_CALL -> #%d:\n", label - vm->program);
			}
#endif
			/*
			printf("%% process %d pushing pc = %d\n",
			    current_process->number, vm->pc - vm->program);
			*/
			PUSH_PC(vm->pc + 1); /* + sizeof(vm_label_t)); */
			vm->pc = label - 1;
			break;

		case INSTR_GOTO:
			POP_VALUE(l);
			label = l.v.s->v.k->label;

			/*
			 * DON'T create a new activation record for this leap
			 * UNLESS the current activation record isn't large enough.
			 */
			/*
			printf("GOTOing a closure w/arity %d locals %d\n",
				l.v.s->v.k->arity, l.v.s->v.k->locals);
			printf("current ar size %d\n", current_ar->size);
			*/

			if (vm->current_ar->size < l.v.s->v.k->arity + l.v.s->v.k->locals) {
				/*
				 * REMOVE the current activation record, if on the stack.
				 */
				if (vm->current_ar->admin & AR_ADMIN_ON_STACK) {
					ar = vm->current_ar->caller;
					activation_free_from_stack(vm->current_ar, vm);
					vm->current_ar = ar;
				} else {
					vm->current_ar = vm->current_ar->caller;
				}

				/*
				 * Create a NEW activation record... wherever.
				 */
				if (l.v.s->v.k->cc > 0) {
					/*
					 * Create a new activation record
					 * on the heap for this call.
					 */
					vm->current_ar = activation_new_on_heap(
					    l.v.s->v.k->arity +
					    l.v.s->v.k->locals,
					    vm->current_ar, l.v.s->v.k->ar);
				} else {
					/*
					 * Optimize by placing it on a stack.
					 */
					vm->current_ar = activation_new_on_stack(
					    l.v.s->v.k->arity +
					    l.v.s->v.k->locals,
					    vm->current_ar, l.v.s->v.k->ar, vm);
				}
			}

			/*
			printf("NOW GOTOing a closure w/arity %d locals %d\n",
				l.v.s->v.k->arity, l.v.s->v.k->locals);
			printf("NOW current ar size %d\n", current_ar->size);
			*/

			/*
			 * Fill out the current activation record.
			 */
			for (i = l.v.s->v.k->arity - 1; i >= 0; i--) {
				POP_VALUE(r);
				activation_set_value(vm->current_ar, i, 0, r);
			}

#ifdef DEBUG
			if (trace_vm) {
				printf("INSTR_GOTO -> #%d:\n", label - vm->program);
			}
#endif
			/*PUSH_PC(pc + 1);*/ /* + sizeof(vm_label_t)); */
			vm->pc = label - 1;
			break;

		case INSTR_RET:
			vm->pc = POP_PC() - 1;
			/*
			printf("%% process %d popped pc = %d\n",
			    current_process->number, vm->pc - vm->program);
			*/
			if (vm->current_ar->admin & AR_ADMIN_ON_STACK) {
				ar = vm->current_ar->caller;
				activation_free_from_stack(vm->current_ar, vm);
				vm->current_ar = ar;
			} else {
				vm->current_ar = vm->current_ar->caller;
			}
			if (vm->current_ar == NULL)
				return(VM_RETURNED);
#ifdef DEBUG
			if (trace_vm) {
				printf("INSTR_RET -> #%d:\n", vm->pc - vm->program);
			}
#endif
			break;

		case INSTR_SET_ACTIVATION:
			POP_VALUE(l);
			l.v.s->v.k->ar = vm->current_ar;
#ifdef DEBUG
			if (trace_vm) {
				printf("INSTR_SET_ACTIVATION #%d\n",
				    l.v.s->v.k->label - vm->program);
			}
#endif
			PUSH_VALUE(l);
			break;

		case INSTR_COW_LOCAL:
			l = activation_get_value(vm->current_ar, *(vm->pc + 1), *(vm->pc + 2));

			if (l.v.s->refcount > 1) {
				/*
				printf("deep-copying ");
				value_print(l);
				printf("...\n");
				*/
				r = value_dup(l);
				activation_set_value(vm->current_ar, *(vm->pc + 1), *(vm->pc + 2), r);
			}

#ifdef DEBUG
			if (trace_vm) {
				printf("INSTR_COW_LOCAL:\n");
				value_print(l);
				printf("\n");
			}
#endif

			vm->pc += sizeof(unsigned char) * 2;
			break;

		case INSTR_EXTERNAL:
			ext_bi = *(struct builtin **)(vm->pc + 1);
#ifdef DEBUG
			if (trace_vm) {
				printf("INSTR_EXTERNAL(");
				fputsu8(stdout, ext_bi->name);
				printf("):\n");
			}
#endif
			varity = ext_bi->arity;
			if (varity == -1) {
				POP_VALUE(l);
				varity = l.v.i;
			}
			ar = activation_new_on_stack(varity, vm->current_ar, NULL, vm);
			for (i = varity - 1; i >= 0; i--) {
				POP_VALUE(l);
				activation_initialize_value(ar, i, l);
			}

			v = ext_bi->fn(ar);
			activation_free_from_stack(ar, vm);
#ifdef DEBUG
			if (trace_vm) {
				printf("result was:\n");
				value_print(v);
				printf("\n");
			}
#endif
			if (ext_bi->retval == 1)
				PUSH_VALUE(v);

			vm->pc += sizeof(struct builtin *);
			break;
		default:
			/*
			 * We assume it was a non-inline builtin.
			 */
#ifdef DEBUG
			if (trace_vm) {
				printf("INSTR_BUILTIN(#%d=", *vm->pc);
				fputsu8(stdout, builtins[*vm->pc].name);
				printf("):\n");
			}
#endif
			varity = builtins[*vm->pc].arity;
			if (varity == -1) {
				POP_VALUE(l);
				varity = l.v.i;
			}
			ar = activation_new_on_stack(varity, vm->current_ar, NULL, vm);
			for (i = varity - 1; i >= 0; i--) {
				POP_VALUE(l);
				activation_initialize_value(ar, i, l);
			}

			v = builtins[*vm->pc].fn(ar);
			activation_free_from_stack(ar, vm);
#ifdef DEBUG
			if (trace_vm) {
				printf("result was:\n");
				value_print(v);
				printf("\n");
			}
#endif
			if (builtins[*vm->pc].retval == 1)
				PUSH_VALUE(v);
		}
		vm->pc++;
	}

#ifdef DEBUG
	if (trace_vm) {
		printf("___ virtual machine finished ___\n");
	}
	/*printf("subs = %d\n", subs);*/
#endif
	return(VM_TERMINATED);
}