void * philosopher (void *num) { int id; int left_fork, right_fork, f; id = (int)num; printf ("Philosopher %d sitting down to dinner.\n", id); right_fork = id; left_fork = id + 1; /* Wrap around the forks - somewhat more complicated */ if (left_fork == PHILO) { left_fork = right_fork; right_fork=0; } while (f = food_on_table ()) { printf ("Philosopher %d: get dish %d.\n", id, f); get_fork (id, right_fork, "right"); get_fork (id, left_fork, "left"); printf ("Philosopher %d: eating.\n", id); usleep (DELAY * (FOOD - f + 1)); down_forks (left_fork, right_fork); } printf ("Philosopher %d is done eating.\n", id); return (NULL); }
request* std2_new_request(int fork_id, int mod, int func) { fork_state* fs = get_fork(fork_id); /* Make request and add it to list. */ request* req = malloc(sizeof(request)); memset(req, 0, sizeof(request)); req->fork_id = fork_id; req->id = fs->next_id++; req->next = fs->first_request; fs->first_request = req; /* Output request header. */ buffer_append_32(&fs->out_buffer, 'c'); buffer_append_32(&fs->out_buffer, req->id); buffer_append_32(&fs->out_buffer, mod); buffer_append_32(&fs->out_buffer, func); yield_callbacks(fork_id); return req; }
static void yield_callbacks(int fork_id) { fork_state* fs = get_fork(fork_id); if (!fs->has_yielded_reader) { struct std2_callback cb; cb.flags = STD2_CALLBACK_READ | STD2_CALLBACK_ERROR | STD2_CALLBACK_ABORT; cb.fd = fs->to_host_fd[0]; cb.user = (void*)fork_id; cb.func = read_cb; std2_yield_callback(&cb); fs->has_yielded_reader = 1; } if (!fs->has_yielded_writer && fs->out_buffer.pos < fs->out_buffer.size) { struct std2_callback cb; cb.flags = STD2_CALLBACK_WRITE | STD2_CALLBACK_ABORT; cb.fd = fs->to_client_fd[1]; cb.user = (void*)fork_id; cb.func = write_cb; std2_yield_callback(&cb); fs->has_yielded_writer = 1; } }
static void write_cb(int fd, int mask, void* user) { int fork_id = (int)user; fork_state* fs = get_fork(fork_id); fs->has_yielded_writer = 0; if (mask & STD2_CALLBACK_ABORT) { assert(!"abort not implemented"); abort(); return; } int r = write_buffer(fd, &fs->out_buffer); if (r < 0) { // TODO: abort requests and stuff fprintf(stderr, "std2: write error: %s\n", strerror(errno)); abort(); } buffer_compact(&fs->out_buffer); yield_callbacks(fork_id); }
static void return_func(int id, void* ret, void* arg0, void* arg1) { (void)arg0; request* req = arg1; fork_state* fs = get_fork(req->fork_id); int ret_id = buffer_read_32(&fs->in_buffer); int ret_size = buffer_read_32(&fs->in_buffer); buffer_compact(&fs->in_buffer); assert(req->id == ret_id); assert(req->return_id == id); char* p = buffer_cursor(&fs->in_buffer); char* start = p; switch (req->ret_type.type) { case STD2_VOID: break; case STD2_INT32: *(std2_int32*)ret = *(std2_int32*)p; p += 4; break; case STD2_C_STRING: { int size = *(int*)p; p += 4; *(const char**)ret = p; p += size; } break; case STD2_INSTANCE: *(void**)ret = *(void**)p; p += sizeof(void*); break; default: fprintf(stderr, "std2: todo return type %d\n", req->ret_type.type); abort(); } assert(p - start == ret_size); fs->in_buffer.pos += ret_size; fs->return_processed = 1; request** prev = &fs->first_request; while (*prev != req && *prev) prev = &(*prev)->next; assert(*prev); *prev = (*prev)->next; free(req); }
static void read_cb(int fd, int mask, void* user) { int fork_id = (int)user; fork_state* fs = get_fork(fork_id); assert(fd == fs->to_host_fd[0]); fs->has_yielded_reader = 0; if (mask & STD2_CALLBACK_ABORT) { assert(!"abort not implemented"); abort(); return; } buffer_reserve(&fs->in_buffer, 1024); int closed = read_buffer_append(fd, &fs->in_buffer, 1); /* If fd was closed, abort all returns. */ if (closed) { request* req; for (req = fs->first_request; req; req = req->next) std2_abort_return(req->return_id); return; } /* fd wasn't closed so yield new read callback. */ yield_callbacks(fork_id); if (!fs->return_processed) return; fprintf(stderr, "NAH\n"); if (buffer_avail(&fs->in_buffer) < 8) return; int ret_id = *(std2_int32*)buffer_cursor(&fs->in_buffer); int ret_size = *((std2_int32*)buffer_cursor(&fs->in_buffer) + 1); if (buffer_avail(&fs->in_buffer) < 8 + ret_size) return; fprintf(stderr, "std2: got return from fork, id %d, size %d\n", ret_id, ret_size); request* req; for (req = fs->first_request; req; req = req->next) if (req->id == ret_id) { fs->return_processed = 0; std2_continue_return(req->return_id, return_func, req); return; } fprintf(stderr, "std2: bad request id\n"); }
void std2_new_unrefer_request(int fork_id, int mod, int clas, void* ptr) { fork_state* fs = get_fork(fork_id); buffer_append_32(&fs->out_buffer, 'u'); buffer_append_32(&fs->out_buffer, 0); buffer_append_32(&fs->out_buffer, mod); buffer_append_32(&fs->out_buffer, clas); buffer_append_data(&fs->out_buffer, &ptr, sizeof(void*)); yield_callbacks(fork_id); }
void std2_process_request() { fork_state* fs = get_fork(current_fork_id); if (read_buffer_append(fs->to_client_fd[0], &fs->in_buffer, 20)) { fprintf(stderr, "std2: child got disconnection\n"); exit(1); } int marker = buffer_read_32(&fs->in_buffer); int req_id = buffer_read_32(&fs->in_buffer); if (marker == 'c') { int m = buffer_read_32(&fs->in_buffer); int f = buffer_read_32(&fs->in_buffer); int params_size = buffer_read_32(&fs->in_buffer); read_buffer_append(fs->to_client_fd[0], &fs->in_buffer, params_size); fprintf(stderr, "call id=%d, %d, %d, %d\n", req_id, m, f, params_size); // Construct parameters. void* start_ptr = buffer_cursor(&fs->in_buffer); void* end_ptr = (char*)buffer_cursor(&fs->in_buffer) + params_size; void* p = start_ptr; void* args[16]; int param_count = std2_get_param_count(m, f); int i; for (i = 0; i < param_count; i++) { struct std2_param t = std2_get_param_type(m, f, i); switch (t.type) { case STD2_INT32: args[i] = p; p = (char*)p + 4; break; case STD2_C_STRING: { int size = *(int*)p; p = (char*)p + 4; args[i] = p; p = (char*)p + size; } break; case STD2_INSTANCE: args[i] = *(void**)p; p = (char*)p + sizeof(void*); break; default: fprintf(stderr, "std2: (c) unknown type %d\n", t.type); abort(); } assert(p <= end_ptr); } fs->in_buffer.pos += (char*)p - (char*)start_ptr; // Do the call. struct std2_param ret_type = std2_get_return_type(m, f); buffer_append_32(&fs->out_buffer, req_id); // size will be filled afterwards int size_pos = fs->out_buffer.size; buffer_append_32(&fs->out_buffer, 0); // size will be filled afterwards int ret; switch (ret_type.type) { case STD2_VOID: ret = std2_call(0, m, f, 0, args); break; case STD2_INT32: { std2_int32 v; ret = std2_call(0, m, f, &v, args); if (!ret) buffer_append_32(&fs->out_buffer, v); } break; case STD2_C_STRING: { const char* v; ret = std2_call(0, m, f, &v, args); if (!ret) { int l = strlen(v) + 1; int n = (l + 3) & ~3; buffer_append_32(&fs->out_buffer, n); buffer_append_data(&fs->out_buffer, v, l); buffer_append_alignment(&fs->out_buffer, 4); } } break; case STD2_INSTANCE: { void* v; ret = std2_call(0, m, f, &v, args); if (!ret) buffer_append_data(&fs->out_buffer, &v, sizeof(void*)); } break; default: fprintf(stderr, "std2: (a) unknown type %d\n", ret_type.type); abort(); } if (ret) { fprintf(stderr, "delayed return\n"); fs->out_buffer.size -= 8; // req_id and size return; } *(int*)((char*)fs->out_buffer.data + size_pos) = fs->out_buffer.size - size_pos - 4; while (buffer_avail(&fs->out_buffer)) write_buffer(fs->to_host_fd[1], &fs->out_buffer); fprintf(stderr, "response written\n"); buffer_compact(&fs->in_buffer); buffer_compact(&fs->out_buffer); } else if (marker == 'u') { assert(!"todo unrefer"); } else { fprintf(stderr, "std2: protocol error, bad marker %d\n", marker); abort(); } }