void rs_release_resources() { gfx_delayed_release(); /* wait for load task to finish */ if (g_rs.load_jobid != 0) { tsk_wait(g_rs.load_jobid); tsk_destroy(g_rs.load_jobid); } /* unload everything in queued loads */ for (uint i = 0; i < g_rs.job_params.cnt; i++) { reshandle_t hdl = g_rs.job_params.load_items[i]->hdl; void* ptr = g_rs.job_result.ptrs[i]; if (ptr != NULL) { struct rs_resource* r = rs_resource_get(hdl); r->unload_func(ptr); } } if (g_rs.blank_tex != NULL) { gfx_destroy_texture(g_rs.blank_tex); g_rs.blank_tex = NULL; } }
/* Invoked when swap has been freed for the task */ INT32 cmd_swap_freed_callback(struct fsio_event_source *iosrc, INT32 ioret) { struct pm_msg_finished pm_finished; struct pm_task *task = tsk_get(iosrc->id); // if there is a destroy sender, send an ok to the task if( task->command_inf.command_sender_id != 0) { struct pm_msg_response msg_ans; msg_ans.pm_type = PM_DESTROY_TASK; msg_ans.req_id = task->command_inf.command_req_id; msg_ans.status = PM_OK; msg_ans.new_id = task->id; msg_ans.new_id_aux = -1; send_msg(task->command_inf.command_sender_id, task->command_inf.command_ret_port, &msg_ans); } if(task->creator_task != 0xFFFF) { // inform the creating task pm_finished.pm_type = PM_TASK_FINISHED; pm_finished.req_id = 0; pm_finished.taskid = task->id; pm_finished.ret_value = task->command_inf.ret_value; send_msg(task->creator_task, task->creator_task_port, &pm_finished); } if(task->dbg_task != 0xFFFF) { struct dbg_message dbg_msg; // inform the creating task dbg_msg.command = DEBUG_TASK_FINISHED; dbg_msg.task = task->id; send_msg(task->dbg_task, task->dbg_port, &dbg_msg); } task->command_inf.command_sender_id = 0xFFFF; task->creator_task = 0xFFFF; task->dbg_task = 0xFFFF; if(shuttingDown()) shutdown_tsk_unloaded(task->id); if(!tsk_destroy(task)) pman_print("PMAN: Could not destroy task"); return 1; }
/* Runs in main thread, syncs resources */ void rs_update() { uint job_id = g_rs.load_jobid; if (job_id != 0) { if (!tsk_check_finished(job_id)) { gfx_delayed_createobjects(); return; } else { gfx_delayed_finalizeobjects(); } } struct rs_load_job_params* params = &g_rs.job_params; struct rs_load_job_result* result = &g_rs.job_result; /* if we already have a job_id, it means that the job is finished * update the database and destroy the task */ if (job_id != 0) { struct rs_load_job_params* params = (struct rs_load_job_params*)tsk_get_params(job_id); struct rs_load_job_result* result = (struct rs_load_job_result*)tsk_get_result(job_id); for (uint i = 0; i < params->cnt; i++) { struct rs_load_data* ldata = params->load_items[i]; reshandle_t hdl = ldata->hdl; /* check the handle in unload list and unload immediately */ int must_unload = rs_search_in_unloads(hdl); struct rs_resource* r = rs_resource_get(hdl); if (result->ptrs[i] != NULL) { r->ptr = result->ptrs[i]; if (!must_unload) { /* register hot-loading */ if (BIT_CHECK(g_rs.flags, RS_FLAG_HOTLOADING) && !ldata->reload) rs_register_hotload(ldata); /* apply reload funcs */ rs_resource_manualreload(ldata); } else { rs_remove_fromdb(hdl); } } else if (must_unload) { rs_remove_fromdb(hdl); } mem_pool_free(&g_rs.load_data_pool, params->load_items[i]); } /* cleanup */ tsk_destroy(job_id); } /* fill new params and dispatch the job */ struct linked_list* lnode = g_rs.load_list; uint qcnt = 0; while (qcnt < g_rs.load_threads_max && lnode != NULL) { params->load_items[qcnt++] = (struct rs_load_data*)lnode->data; list_remove(&g_rs.load_list, lnode); lnode = g_rs.load_list; } params->cnt = qcnt; /* dispatch to first thread only (exclusive mode) */ if (qcnt > 0) { int thread_cnt = (int)g_rs.load_threads_max; struct allocator* tmp_alloc = tsk_get_tmpalloc(0); int* thread_idxs = (int*)A_ALLOC(tmp_alloc, sizeof(uint)*thread_cnt, MID_RES); ASSERT(thread_idxs); for (int i = 0; i < thread_cnt; i++) thread_idxs[i] = i; g_rs.load_jobid = tsk_dispatch_exclusive(rs_threaded_load_fn, thread_idxs, thread_cnt, params, result); A_FREE(tmp_alloc, thread_idxs); } else { g_rs.load_jobid = 0; } }
INT32 elf_fileclosed_callback(struct fsio_event_source *iosrc, INT32 ioret) { // file was closed because of an error, destroy the task tsk_destroy(tsk_get(iosrc->id)); }
void cmd_create_task(struct pm_msg_create_task *msg, struct pm_task *ctask) { struct pm_task *tsk = NULL; UINT16 new_task_id = msg->new_task_id; UINT16 flags = msg->flags; UINT16 type = (flags & SERVER_TASK) / SERVER_TASK; UINT32 psize, ret; char *path = NULL; if(pman_stage == PMAN_STAGE_INITIALIZING) { cmd_inform_result(msg, ctask->id, PM_IS_INITIALIZING, 0, 0); return; } if(new_task_id != 0xFFFF) { if (tsk_lower_bound[type] <= new_task_id && new_task_id <= tsk_upper_bound[type]) { tsk = tsk_get(new_task_id); if(tsk != NULL) { /* new_task_id is not free to be used */ cmd_inform_result(msg, ctask->id, PM_TASK_ID_TAKEN, 0, 0); return; } } else { /* new_task_id is out of range */ cmd_inform_result(msg, ctask->id, PM_TASK_ID_INVALID, 0, 0); return; } } else { /* search for a free task id */ new_task_id = tsk_get_id(tsk_lower_bound[type], tsk_upper_bound[type]); if(new_task_id == 0xFFFF) { cmd_inform_result(msg, ctask->id, PM_NO_FREE_ID, 0, 0); return; } } tsk = tsk_create(new_task_id); if(tsk == NULL) { cmd_inform_result(msg, ctask->id, PM_NOT_ENOUGH_MEM, 0, 0); return; } path = NULL; psize = mem_size(msg->path_smo_id); if(psize < 1) { tsk_destroy(tsk); cmd_inform_result(msg, ctask->id, PM_BAD_SMO, 0, 0); return; } path = kmalloc(psize); if(path == NULL) { tsk_destroy(tsk); cmd_inform_result(msg, ctask->id, PM_NOT_ENOUGH_MEM, 0, 0); return; } /* Read Path */ if(read_mem(msg->path_smo_id, 0, psize, path) != SUCCESS) { tsk_destroy(tsk); cmd_inform_result(msg, ctask->id, PM_BAD_SMO, 0, 0); return; } tsk->flags = (flags & SERVER_TASK)? TSK_FLAG_SERVICE : 0; if(path[psize-1] == '\0') psize--; tsk->creator_task = ctask->id; tsk->creator_task_port = msg->response_port; tsk->command_inf.command_req_id = msg->req_id; tsk->command_inf.command_ret_port = -1; tsk->command_inf.command_sender_id = -1; ret = loader_create_task(tsk, path, psize, msg->param, type, LOADER_CTASK_TYPE_PRG); if(ret != PM_OK) { tsk_destroy(tsk); kfree(path); cmd_inform_result(msg, ctask->id, ret, 0, 0); } }
/* Unload the specified lib. */ BOOL vmm_lib_unload(struct pm_task *task, struct vmm_memory_region *mreg) { struct vmm_slib_descriptor *lib = (struct vmm_slib_descriptor*)mreg->descriptor; if(lib == NULL) { ma_remove(&task->vmm_info.regions, &mreg->tsk_node); rb_remove(&task->vmm_info.regions_id, &mreg->tsk_id_node); kfree(mreg); pman_print_dbg("PMAN vmm_lib_unload: Lib is LD\n"); return TRUE; // this can only happen on the LD mapping } pman_print_dbg("PMAN vmm_lib_unload: Claim memory from task.\n"); // claim memory from the referencing task vmm_claim_region(task, mreg); ma_remove(&task->vmm_info.regions, &mreg->tsk_node); rb_remove(&task->vmm_info.regions_id, &mreg->tsk_id_node); // fix regions list on the descriptor if(mreg->prev == NULL) lib->regions = mreg->next; else mreg->prev->next = mreg->next; if(mreg->next) mreg->next->prev = mreg->prev; kfree(mreg); lib->references--; pman_print_dbg("PMAN vmm_lib_unload: Lib references %i\n", lib->references); if(!lib->references && lib->loaded) { struct pm_task *ltask = tsk_get(lib->task); pman_print_dbg("PMAN vmm_lib_unload: Lib UNLOADING\n"); /* Close the file but dont wait for a callback */ struct stdfss_close msg_close; msg_close.command = STDFSS_CLOSE; msg_close.thr_id = -1; msg_close.file_id = ltask->io_event_src.file_id; msg_close.ret_port = 50; // this port is clearly not open send_msg(ltask->io_event_src.fs_service, STDFSS_PORT, &msg_close); // destroy the task tsk_destroy(ltask); // this should also free the path! // remove it from the loaded list if(lib->prev == NULL) { vmm.slibs = lib->next; vmm.slibs->prev = NULL; } else { lib->prev->next = lib->next; } if(lib->next != NULL) lib->next->prev = lib->prev; kfree(lib); pman_print_dbg("PMAN vmm_lib_unload: Lib FREED\n"); } return TRUE; }
int vmm_lib_load(struct pm_task *task, char *path, int plength, UINT32 vlow, UINT32 vhigh) { struct vmm_slib_descriptor *lib = (struct vmm_slib_descriptor*)vmm_lib_get(path); struct vmm_memory_region *mreg = NULL; UINT16 libtask; int ret; struct pm_task *libtsk = NULL; pman_print_dbg("PM: vmm_lib_load %s l: %x h: %x\n", path, vlow, vhigh); vlow = TRANSLATE_ADDR(vlow,UINT32); vhigh = TRANSLATE_ADDR(vhigh,UINT32); if(ma_collition(&task->vmm_info.regions, vlow, vhigh)) return FALSE; pman_print_dbg("PM: vmm_lib_load no collition\n"); mreg = kmalloc(sizeof(struct vmm_memory_region)); if(!mreg) return 0; if(!rb_free_value(&task->vmm_info.regions_id, &mreg->tsk_id_node.value)) { kfree(mreg); return FALSE; } pman_print_dbg("PM: vmm_lib_load id %i\n", &mreg->tsk_id_node.value); if(!lib) { pman_print_dbg("PM: vmm_lib_load loading lib for the first time\n"); lib = kmalloc(sizeof(struct vmm_slib_descriptor)); if(!lib) { kfree(mreg); return 0; } /* search for a free task id */ libtask = tsk_get_id(tsk_lower_bound[1], tsk_upper_bound[1]); if(libtask == 0xFFFF) { kfree(mreg); return 0; } libtsk = tsk_create(libtask); if(libtsk == NULL) { kfree(mreg); return 0; } pman_print_dbg("PM: vmm_lib_load task created %i\n", libtask); libtsk->flags = TSK_SHARED_LIB; libtsk->state = TSK_NORMAL; if(path[plength-1] == '\0') plength--; lib->path = path; lib->references = 1; lib->regions = NULL; lib->task = libtask; lib->loaded = 0; // add it to the global loaded libs list if(vmm.slibs) vmm.slibs->prev = lib; lib->next = vmm.slibs; lib->prev = NULL; vmm.slibs = lib; mreg->owner_task = task->id; mreg->next = mreg->prev = NULL; mreg->tsk_node.high = vhigh; mreg->tsk_node.low = vlow; mreg->flags = VMM_MEM_REGION_FLAG_NONE; mreg->type = VMM_MEMREGION_LIB; mreg->descriptor = lib; lib->regions = mreg; pman_print_dbg("PM: vmm_lib_load invoke loader reg: %x\n", mreg); ret = loader_create_task(libtsk, path, plength, (unsigned int)lib, 1, LOADER_CTASK_TYPE_LIB); if(ret != PM_OK) { tsk_destroy(libtsk); kfree(mreg); return 0; } pman_print_dbg("PM: vmm_lib_load loader create task ret OK\n"); return 1; } pman_print_dbg("PM: vmm_lib_load lib is already loaded! ref: %i \n", lib->references); lib->references++; // complete the memory region for this task mreg->owner_task = task->id; mreg->tsk_node.high = vhigh; mreg->tsk_node.low = vlow; mreg->flags = VMM_MEM_REGION_FLAG_NONE; mreg->type = VMM_MEMREGION_LIB; mreg->descriptor = lib; lib->regions->next = mreg; mreg->prev = lib->regions; mreg->next = NULL; if(!lib->loaded) { pman_print_dbg("PM: vmm_lib_load lib is not loaded yet\n"); return 1; } else { pman_print_dbg("PM: vmm_lib_load lib is loaded!\n"); /* Add new_mreg on the task lists */ ma_insert(&task->vmm_info.regions, &mreg->tsk_node); rb_search(&task->vmm_info.regions_id, mreg->tsk_id_node.value); } return 2; }