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); } } }
/** * 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); }
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; }
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; }
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); }
/** * 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); }
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; }
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; }
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); }