void workerpool_run_single(workerpool_t *wp) { for (int i = 0; i < zarray_size(wp->tasks); i++) { struct task *task; zarray_get_volatile(wp->tasks, i, &task); task->f(task->p); } zarray_clear(wp->tasks); }
// Do a quick swap: void vx_buffer_swap(vx_buffer_t * buffer) { pthread_mutex_lock(&buffer->mutex); { // It's possible that the serialization is running behind, // and may not have already serialized the pending_objs // In that case, they are discarded here, momentarily blocking // the calling thread. if (zarray_size(buffer->pending_objs) > 0) { // *+*+ corresponding decrement (if falling behind) zarray_vmap(buffer->pending_objs, vx_object_dec_destroy); zarray_clear(buffer->pending_objs); static int once = 1; if (once) { once = 0; printf("NFO: World serialization fell behind\n"); } } // swap zarray_t * tmp = buffer->pending_objs; buffer->pending_objs = buffer->back_objs; buffer->back_objs = tmp; } pthread_mutex_unlock(&buffer->mutex); // Now flag a swap on the serialization thread pthread_mutex_lock(&buffer->world->queue_mutex); { // Ensure that the string is already in the queue, or add it if // it isn't. Duplicates are prohibited int index = -1; for (int i = 0, sz = zarray_size(buffer->world->buffer_queue); i < sz; i++) { char * test = NULL; zarray_get(buffer->world->buffer_queue, i, &test); if (strcmp(test, buffer->name) == 0) { index = i; break; } } if (index < 0) { zarray_add(buffer->world->buffer_queue, &buffer->name); pthread_cond_signal(&buffer->world->queue_cond); } } pthread_mutex_unlock(&buffer->world->queue_mutex); }
// runs all added tasks, waits for them to complete. void workerpool_run(workerpool_t *wp) { if (wp->nthreads > 1) { wp->end_count = 0; pthread_mutex_lock(&wp->mutex); pthread_cond_broadcast(&wp->startcond); while (wp->end_count < wp->nthreads) { // printf("caught %d\n", wp->end_count); pthread_cond_wait(&wp->endcond, &wp->mutex); } pthread_mutex_unlock(&wp->mutex); wp->taskspos = 0; zarray_clear(wp->tasks); } else { workerpool_run_single(wp); } }
static void * movie_run(void * params) { state_t * state = params; zarray_t * frames = zarray_create(sizeof(movie_frame_t*)); char * last_filename = NULL; char * current_filename = NULL; gzFile gzMovie = NULL; int movie_frames = 0; int lost_frames = 0; uint64_t movie_start_mtime = 0; while (state->rendering) { pthread_mutex_lock(&state->movie_mutex); while (state->rendering && current_filename == state->movie_file && zarray_size(state->movie_pending) == 0) pthread_cond_wait(&state->movie_cond, &state->movie_mutex); if (!state->rendering) // exit signaled while waiting on cond break; for (int i = 0; i < zarray_size(state->movie_pending); i++) { movie_frame_t * tmp = NULL; zarray_get(state->movie_pending, i, &tmp); zarray_add(frames, &tmp); } zarray_clear(state->movie_pending); current_filename = state->movie_file; pthread_mutex_unlock(&state->movie_mutex); // Depending on setup, execute different actions // 1) Open 2) Close 3) Write a frame if (zarray_size(frames) > 0 && current_filename != NULL) { // Write the most recent frame, dump the rest movie_frame_t * movie_img = NULL; zarray_get(frames, zarray_size(frames)-1, &movie_img); zarray_remove_index(frames, zarray_size(frames)-1, 0); char header[256]; sprintf(header, "#mtime=%"PRIu64"\nP6 %d %d %d\n", movie_img->mtime, movie_img->width, movie_img->height, 255); int header_len = strlen(header); int imglen = movie_img->stride*movie_img->height;// RGB format gzwrite(gzMovie, header, header_len); gzwrite(gzMovie, movie_img->buf, imglen); int res = gzflush(gzMovie, Z_SYNC_FLUSH); if (res != Z_OK) { int errval = 0; printf("Error writing movie %s. Closing file\n", gzerror(gzMovie, &errval)); gzclose(gzMovie); free(current_filename); current_filename = NULL; } movie_frames++; movie_frame_destroy (movie_img); } // cleanup the frames: lost_frames += zarray_size(frames); zarray_vmap(frames, movie_frame_destroy); zarray_clear(frames); // Got a new filename, need to start recording if (current_filename != NULL && last_filename == NULL) { gzMovie = gzopen(current_filename, "w3"); movie_frames = 0; lost_frames = 0; movie_start_mtime = vx_mtime(); printf("NFO: Starting movie at %s\n", current_filename); if (gzMovie == NULL) { printf("WRN: Unable to start movie at %s\n", current_filename); free(current_filename); // XXX Would need to edit // state->movie_file ? current_filename = NULL; } } if (current_filename == NULL && last_filename != NULL) { gzclose(gzMovie); printf("NFO: Wrote/lost %d/%d movie frames at %.2f fps to %s\n", movie_frames, lost_frames, 1e3 * movie_frames / (vx_mtime() - movie_start_mtime), last_filename); free(last_filename); } last_filename = current_filename; } // XXX Cleanup? might shutdown while recording? return NULL; }
// Call this only from the serialization thread // static void delayed_swap(vx_buffer_t * buffer) { if (!buffer->front_objs) return; // buffer has not yet finished initialization if (verbose) printf("DBG: swap %s\n", buffer->name); pthread_mutex_lock(&buffer->mutex); { // clear existing front buffer->front_codes->pos = 0; // reset // *+*+ corresponding decrement (if keeping up) zarray_vmap(buffer->front_objs, vx_object_dec_destroy); zarray_clear(buffer->front_objs); // swap out the pending objects without tying up this mutex for too long zarray_t * tmp = buffer->front_objs; buffer->front_objs = buffer->pending_objs; buffer->pending_objs = tmp; // empty } pthread_mutex_unlock(&buffer->mutex); vx_world_t * world = buffer->world; zhash_t * old_resources = buffer->front_resc; // Serialize each object into resources and opcodes vx_code_output_stream_t * codes = buffer->front_codes; codes->write_uint32(codes, OP_BUFFER_CODES); codes->write_uint32(codes, world->worldID); codes->write_str(codes, buffer->name); codes->write_uint32(codes, buffer->draw_order); // XXX We should move this op code elsewhere zhash_t * resources = zhash_create(sizeof(uint64_t),sizeof(vx_resc_t*), zhash_uint64_hash, zhash_uint64_equals); for (int i = 0; i < zarray_size(buffer->front_objs); i++) { vx_object_t * obj = NULL; zarray_get(buffer->front_objs, i, &obj); obj->append(obj, resources, codes); } // *&&* we will hold on to these until next swap() call zhash_vmap_values(resources, vx_resc_inc_ref); zhash_t * all_resources = zhash_copy(resources); addAll(all_resources, old_resources); // Claim use of the union of the last frame, and the current frame // this avoids a race condition where another buffer (maybe in another world) // could force deallocation of some resources before the new render codes arrive if (verbose) printf("DBG: claim union via codes\n"); if (verbose > 1) { printf(" claimed %d IDS ", zhash_size(all_resources)); zhash_vmap_values(all_resources, _print_id); printf("\n"); } send_buffer_resource_codes(buffer, all_resources); if (verbose) printf("DBG: Send actual resources\n"); if (verbose > 1) { printf(" send %d IDS ", zhash_size(all_resources)); zhash_vmap_values(all_resources, _print_id); printf("\n"); } notify_listeners_send_resources(world, all_resources); if (verbose) printf("DBG: send render codes\n"); notify_listeners_codes(world, codes); // Claim the actual set of resources which are in use now, which may result in some // resources being deleted from the gl context if (verbose) printf("DBG: reduce claim to actual in use\n"); if (verbose > 1) { printf(" actual %d IDS ", zhash_size(resources)); zhash_vmap_values(resources, _print_id); printf("\n\n"); } send_buffer_resource_codes(buffer, resources); buffer->front_resc = resources; // set of current resources zhash_destroy(all_resources); // *&&* corresponding decrement of resources zhash_vmap_values(old_resources, vx_resc_dec_destroy); zhash_destroy(old_resources); }