static int ipc_thread_exit (IDTYPE vmid, IDTYPE tid, unsigned int exitcode) { assert(vmid != cur_process.vmid); struct shim_thread * thread = __lookup_thread(tid); if (thread) { int ret = 0; //assert(thread->vmid == vmid && !thread->in_vm); thread->exit_code = -exitcode; ret = thread_exit(thread, false); put_thread(thread); return ret; } struct shim_simple_thread * sthread = __lookup_simple_thread(tid); if (!sthread) { sthread = get_new_simple_thread(); sthread->vmid = vmid; sthread->tid = tid; add_simple_thread(sthread); } sthread->is_alive = 0; sthread->exit_code = -exitcode; DkEventSet(sthread->exit_event); put_simple_thread(sthread); return 0; }
static int msg_balance_migrate (struct shim_handle * hdl, struct sysv_client * src) { struct shim_msg_handle * msgq = &hdl->info.msg; int ret = 0; debug("trigger msg queue balancing, migrate to process %u\n", src->vmid); if ((ret = __store_msg_persist(msgq)) < 0) return 0; struct shim_ipc_info * info = discover_client(src->port, src->vmid); if (!info) goto failed; ipc_sysv_sublease_send(src->vmid, msgq->msqid, qstrgetstr(&info->uri), &msgq->lease); ret = ipc_sysv_msgmov_send(src->port, src->vmid, msgq->msqid, msgq->lease, msgq->scores, MAX_SYSV_CLIENTS); if (ret < 0) goto failed_info; msgq->owner = info; for (struct msg_type * mtype = msgq->types ; mtype < &msgq->types[msgq->ntypes] ; mtype++) { struct msg_req * req = mtype->reqs; mtype->reqs = mtype->req_tail = NULL; while (req) { struct msg_req * next = req->next; ipc_sysv_movres_send(&req->dest, info->vmid, qstrgetstr(&info->uri), msgq->lease, msgq->msqid, SYSV_MSGQ); put_ipc_port(req->dest.port); __free_msg_qobj(msgq, req); req = next; } } ret = 0; DkEventSet(msgq->event); goto out; failed_info: put_ipc_info(info); failed: ret = __load_msg_persist(msgq, true); out: return ret; }
int remove_child_thread (IDTYPE vmid, unsigned int exitcode) { assert(vmid != cur_process.vmid); struct thread_info { IDTYPE vmid; unsigned int exitcode; }; int child_sthread_exit (struct shim_simple_thread * thread, void * arg, bool * unlocked) { struct thread_info * info = (struct thread_info *) arg; if (thread->vmid == info->vmid) { if (thread->is_alive) { thread->exit_code = -info->exitcode; thread->is_alive = false; DkEventSet(thread->exit_event); } return 1; } return 0; } int child_thread_exit (struct shim_thread * thread, void * arg, bool * unlocked) { struct thread_info * info = (struct thread_info *) arg; if (thread->vmid == info->vmid) { if (thread->is_alive) { thread->exit_code = -info->exitcode; thread_exit(thread, false); } return 1; } return 0; } struct thread_info info = { .vmid = vmid, .exitcode = exitcode }; int nkilled = 0, ret; if ((ret = walk_thread_list(&child_thread_exit, &info, false)) > 0) nkilled += ret; if ((ret = walk_simple_thread_list(&child_sthread_exit, &info, false)) > 0) nkilled += ret; if (!nkilled) debug("child port closed, no thread exited\n"); return 0; }
int thread_1(void* args) { DkThreadDelayExecution(1000); pal_printf("In Thread 1\n"); while (count < 100) count++; DkEventSet(event1); DkThreadExit(); return 0; }
int recover_msg_ownership (struct shim_msg_handle * msgq) { struct shim_handle * hdl = MSG_TO_HANDLE(msgq); lock(hdl->lock); assert(!msgq->owned); int ret = __load_msg_persist(msgq, true); if (ret < 0) { ret = (ret == -ENOENT) ? -EIDRM : ret; goto out; } msgq->owned = true; DkEventSet(msgq->event); out: unlock(hdl->lock); return 0; }
int add_sysv_msg (struct shim_msg_handle * msgq, long type, int size, const void * data, struct sysv_client * src) { BEGIN_PROFILE_INTERVAL(); struct shim_handle * hdl = MSG_TO_HANDLE(msgq); int ret = 0; lock(hdl->lock); if (msgq->deleted) { ret = -EIDRM; goto out_locked; } if (!msgq->owned) { unlock(hdl->lock); ret = ipc_sysv_msgsnd_send(src->port, src->vmid, msgq->msqid, type, data, size, src->seq); goto out; } struct msg_type * mtype = __add_msg_type(type, &msgq->types, &msgq->ntypes, &msgq->maxtypes); if ((ret = __store_msg_qobjs(msgq, mtype, size, data)) < 0) goto out_locked; if (msgq->owned) __balance_sysv_score(&msg_policy, hdl, msgq->scores, MAX_SYSV_CLIENTS, src, MSG_SND_SCORE); DkEventSet(msgq->event); ret = 0; out_locked: unlock(hdl->lock); out: SAVE_PROFILE_INTERVAL(add_sysv_msg); return ret; }
static int __store_msg_persist (struct shim_msg_handle * msgq) { int ret = 0; if (msgq->deleted) goto out; debug("store msgq %d to persistent store\n", msgq->msqid); char fileuri[20]; snprintf(fileuri, 20, "file:msgq.%08x", msgq->msqid); PAL_HANDLE file = DkStreamOpen(fileuri, PAL_ACCESS_RDWR, 0600, PAL_CREAT_TRY, 0); if (!file) { ret = -PAL_ERRNO; goto out; } int expected_size = sizeof(struct msg_handle_backup) + sizeof(struct msg_backup) * msgq->nmsgs + msgq->currentsize; if (DkStreamSetLength(file, expected_size) != expected_size) goto err_file; void * mem = (void *) DkStreamMap(file, NULL, PAL_PROT_READ|PAL_PROT_WRITE, 0, ALIGN_UP(expected_size)); if (!mem) { ret = -EFAULT; goto err_file; } struct msg_handle_backup * mback = mem; mem += sizeof(struct msg_handle_backup); mback->perm = msgq->perm; mback->nmsgs = msgq->nmsgs; mback->currentsize = msgq->currentsize; struct msg_type * mtype; for (mtype = msgq->types ; mtype < &msgq->types[msgq->ntypes] ; mtype++) { while (mtype->msgs) { struct msg_backup * msg = mem; mem += sizeof(struct msg_backup) + mtype->msgs->size; msg->type = mtype->type; msg->size = mtype->msgs->size; __load_msg_qobjs(msgq, mtype, mtype->msgs, msg->data); } mtype->msgs = mtype->msg_tail = NULL; } DkStreamUnmap(mem, ALIGN_UP(expected_size)); if (msgq->owned) for (mtype = msgq->types ; mtype < &msgq->types[msgq->ntypes] ; mtype++) { struct msg_req * req = mtype->reqs; mtype->reqs = mtype->req_tail = NULL; while (req) { struct sysv_client * c = &req->dest; struct msg_req * next = req->next; __response_ipc_message(c->port, c->vmid, -EIDRM, c->seq); put_ipc_port(c->port); __free_msg_qobj(msgq, req); req = next; } } msgq->owned = false; ret = 0; goto out; err_file: DkStreamDelete(file, 0); DkObjectClose(file); out: // To wake up any receiver waiting on local message which must // now be requested from new owner. DkEventSet(msgq->event); return ret; }
int thread_exit(struct shim_thread * self, bool send_ipc) { /* Chia-Che: Broadcast exit message as early as possible, so other process can start early on responding. */ if (self->in_vm && send_ipc) ipc_cld_exit_send(self->ppid, self->tid, self->exit_code, self->term_signal); lock(&self->lock); if (!self->is_alive) { debug("thread %d is dead\n", self->tid); out: unlock(&self->lock); return 0; } #ifdef PROFILE self->exit_time = GET_PROFILE_INTERVAL(); #endif int exit_code = self->exit_code; self->is_alive = false; if (is_internal(self)) goto out; struct shim_handle_map * handle_map = self->handle_map; struct shim_handle * exec = self->exec; struct shim_thread * parent = self->parent; self->handle_map = NULL; self->exec = NULL; if (parent) { assert(parent != self); assert(parent->child_exit_event); debug("thread exits, notifying thread %d\n", parent->tid); lock(&parent->lock); LISTP_DEL_INIT(self, &parent->children, siblings); LISTP_ADD_TAIL(self, &parent->exited_children, siblings); if (!self->in_vm) { debug("deliver SIGCHLD (thread = %d, exitval = %d)\n", self->tid, exit_code); siginfo_t info; memset(&info, 0, sizeof(siginfo_t)); info.si_signo = SIGCHLD; info.si_pid = self->tid; info.si_uid = self->uid; info.si_status = (exit_code & 0xff) << 8; append_signal(parent, SIGCHLD, &info, true); } unlock(&parent->lock); DkEventSet(parent->child_exit_event); } else { debug("parent not here, need to tell another process\n"); ipc_cld_exit_send(self->ppid, self->tid, self->exit_code, self->term_signal); } struct robust_list_head * robust_list = (void *) self->robust_list; self->robust_list = NULL; unlock(&self->lock); if (handle_map) put_handle_map(handle_map); if (exec) put_handle(exec); if (robust_list) release_robust_list(robust_list); if (self->clear_child_tid) release_clear_child_id (self->clear_child_tid); DkEventSet(self->exit_event); return 0; }