From ccd770ba2441ec1c6f64978698a83ff97c781fce Mon Sep 17 00:00:00 2001 From: "Balazs Gerofi bgerofi@riken.jp" Date: Thu, 27 Mar 2014 19:31:42 +0900 Subject: [PATCH] use per-process wait queues for system call request processing in mcexec so that multiple processes can share the per-core system call channels --- executer/include/uprotocol.h | 1 + executer/kernel/control.c | 76 +++++++++++++++++++++++++++++++++--- executer/kernel/ikc.c | 12 ++++-- executer/kernel/mcctrl.h | 10 ++++- executer/kernel/syscall.c | 41 +++++++++++++++++-- executer/user/mcexec.c | 3 +- kernel/include/syscall.h | 1 + kernel/syscall.c | 10 ++++- 8 files changed, 138 insertions(+), 16 deletions(-) diff --git a/executer/include/uprotocol.h b/executer/include/uprotocol.h index 34247103..bcb2681f 100644 --- a/executer/include/uprotocol.h +++ b/executer/include/uprotocol.h @@ -93,6 +93,7 @@ struct syscall_request { struct syscall_wait_desc { unsigned long cpu; struct syscall_request sr; + int pid; }; struct syscall_load_desc { diff --git a/executer/kernel/control.c b/executer/kernel/control.c index 671b81a5..cfd03bf6 100644 --- a/executer/kernel/control.c +++ b/executer/kernel/control.c @@ -267,10 +267,37 @@ static long mcexec_get_cpu(ihk_os_t os) return info->n_cpus; } -int mcexec_syscall(struct mcctrl_channel *c, unsigned long arg) +int mcexec_syscall(struct mcctrl_channel *c, int pid, unsigned long arg) { + struct wait_queue_head_list_node *wqhln = NULL; + struct wait_queue_head_list_node *wqhln_iter; + unsigned long flags; + + /* Look up per-process wait queue head with pid */ + flags = ihk_ikc_spinlock_lock(&c->wq_list_lock); + list_for_each_entry(wqhln_iter, &c->wq_list, list) { + if (wqhln_iter->pid == pid) { + wqhln = wqhln_iter; + break; + } + } + + if (!wqhln) { +retry_alloc: + wqhln = kmalloc(sizeof(*wqhln), GFP_KERNEL); + if (!wqhln) { + printk("WARNING: coudln't alloc wait queue head, retrying..\n"); + goto retry_alloc; + } + + wqhln->pid = pid; + init_waitqueue_head(&wqhln->wq_syscall); + list_add_tail(&wqhln->list, &c->wq_list); + } + ihk_ikc_spinlock_unlock(&c->wq_list_lock, flags); + c->req = 1; - wake_up(&c->wq_syscall); + wake_up(&wqhln->wq_syscall); return 0; } @@ -287,16 +314,21 @@ int mcexec_wait_syscall(ihk_os_t os, struct syscall_wait_desc *__user req) struct syscall_wait_desc swd; struct mcctrl_channel *c; struct mcctrl_usrdata *usrdata = ihk_host_os_get_usrdata(os); + struct wait_queue_head_list_node *wqhln; + struct wait_queue_head_list_node *wqhln_iter; + int ret = 0; + unsigned long irqflags; #ifndef DO_USER_MODE unsigned long s, w, d; #endif //printk("mcexec_wait_syscall swd=%p req=%p size=%d\n", &swd, req, sizeof(swd.cpu)); - if (copy_from_user(&swd, req, sizeof(swd.cpu))) { + if (copy_from_user(&swd, req, sizeof(swd))) { return -EFAULT; } -if(swd.cpu >= usrdata->num_channels)return -EINVAL; + if (swd.cpu >= usrdata->num_channels) + return -EINVAL; c = get_peer_channel(usrdata, current); if (c) { @@ -308,9 +340,43 @@ if(swd.cpu >= usrdata->num_channels)return -EINVAL; #ifdef DO_USER_MODE retry: - if (wait_event_interruptible(c->wq_syscall, c->req)) { + /* Prepare per-process wait queue head */ +retry_alloc: + wqhln = kmalloc(sizeof(*wqhln), GFP_KERNEL); + if (!wqhln) { + printk("WARNING: coudln't alloc wait queue head, retrying..\n"); + goto retry_alloc; + } + + wqhln->pid = swd.pid; + init_waitqueue_head(&wqhln->wq_syscall); + + irqflags = ihk_ikc_spinlock_lock(&c->wq_list_lock); + /* First see if there is one wait queue already */ + list_for_each_entry(wqhln_iter, &c->wq_list, list) { + if (wqhln_iter->pid == current->tgid) { + kfree(wqhln); + wqhln = wqhln_iter; + list_del(&wqhln->list); + printk("DEBUG: wait queue head was already available in syscall wait\n"); + break; + } + } + list_add_tail(&wqhln->list, &c->wq_list); + ihk_ikc_spinlock_unlock(&c->wq_list_lock, irqflags); + + ret = wait_event_interruptible(wqhln->wq_syscall, c->req); + + /* Remove per-process wait queue head */ + irqflags = ihk_ikc_spinlock_lock(&c->wq_list_lock); + list_del(&wqhln->list); + ihk_ikc_spinlock_unlock(&c->wq_list_lock, irqflags); + kfree(wqhln); + + if (ret) { return -EINTR; } + c->req = 0; #if 1 mb(); diff --git a/executer/kernel/ikc.c b/executer/kernel/ikc.c index 91e46647..2f263041 100644 --- a/executer/kernel/ikc.c +++ b/executer/kernel/ikc.c @@ -40,7 +40,7 @@ void mcexec_prepare_ack(ihk_os_t os, unsigned long arg, int err); static void mcctrl_ikc_init(ihk_os_t os, int cpu, unsigned long rphys, struct ihk_ikc_channel_desc *c); -int mcexec_syscall(struct mcctrl_channel *c, unsigned long arg); +int mcexec_syscall(struct mcctrl_channel *c, int pid, unsigned long arg); static int syscall_packet_handler(struct ihk_ikc_channel_desc *c, void *__packet, void *__os) @@ -62,7 +62,7 @@ static int syscall_packet_handler(struct ihk_ikc_channel_desc *c, break; case SCD_MSG_SYSCALL_ONESIDE: - mcexec_syscall(usrdata->channels + pisp->ref, pisp->arg); + mcexec_syscall(usrdata->channels + pisp->ref, pisp->pid, pisp->arg); break; } @@ -219,7 +219,9 @@ static int connect_handler(struct ihk_ikc_channel_info *param) return 1; } param->packet_handler = syscall_packet_handler; - init_waitqueue_head(&usrdata->channels[cpu].wq_syscall); + + INIT_LIST_HEAD(&usrdata->channels[cpu].wq_list); + spin_lock_init(&usrdata->channels[cpu].wq_list_lock); usrdata->channels[cpu].c = c; kprintf("syscall: MC CPU %d connected. c=%p\n", cpu, c); @@ -238,7 +240,9 @@ static int connect_handler2(struct ihk_ikc_channel_info *param) cpu = usrdata->num_channels - 1; param->packet_handler = syscall_packet_handler; - init_waitqueue_head(&usrdata->channels[cpu].wq_syscall); + + INIT_LIST_HEAD(&usrdata->channels[cpu].wq_list); + spin_lock_init(&usrdata->channels[cpu].wq_list_lock); usrdata->channels[cpu].c = c; kprintf("syscall: MC CPU %d connected. c=%p\n", cpu, c); diff --git a/executer/kernel/mcctrl.h b/executer/kernel/mcctrl.h index ce79fb90..e03978b6 100644 --- a/executer/kernel/mcctrl.h +++ b/executer/kernel/mcctrl.h @@ -56,6 +56,7 @@ struct ikc_scd_packet { int msg; int ref; + int pid; int err; unsigned long arg; }; @@ -88,6 +89,12 @@ struct syscall_params { unsigned long *doorbell_va; }; +struct wait_queue_head_list_node { + struct list_head list; + wait_queue_head_t wq_syscall; + int pid; +}; + struct mcctrl_channel { struct ihk_ikc_channel_desc *c; struct syscall_params param; @@ -95,7 +102,8 @@ struct mcctrl_channel { void *dma_buf; int req; - wait_queue_head_t wq_syscall; + struct list_head wq_list; + ihk_spinlock_t wq_list_lock; }; struct mcctrl_usrdata { diff --git a/executer/kernel/syscall.c b/executer/kernel/syscall.c index 2418b198..682e23bc 100644 --- a/executer/kernel/syscall.c +++ b/executer/kernel/syscall.c @@ -57,7 +57,7 @@ static long pager_call(ihk_os_t os, struct syscall_request *req); #ifdef SC_DEBUG -//static struct ihk_dma_request last_request; +static struct ihk_dma_request last_request; static void print_dma_lastreq(void) { @@ -215,7 +215,7 @@ static int remote_page_fault(struct mcctrl_usrdata *usrdata, void *fault_addr, u struct syscall_request *req; struct syscall_response *resp; int error; - + dprintk("remote_page_fault(%p,%p,%llx)\n", usrdata, fault_addr, reason); channel = get_peer_channel(usrdata, current); @@ -241,8 +241,43 @@ static int remote_page_fault(struct mcctrl_usrdata *usrdata, void *fault_addr, u resp->status = STATUS_PAGE_FAULT; for (;;) { + struct wait_queue_head_list_node *wqhln; + struct wait_queue_head_list_node *wqhln_iter; + unsigned long irqflags; + +retry_alloc: + wqhln = kmalloc(sizeof(*wqhln), GFP_KERNEL); + if (!wqhln) { + printk("WARNING: coudln't alloc wait queue head, retrying..\n"); + goto retry_alloc; + } + + /* Prepare per-process wait queue head */ + wqhln->pid = current->tgid; + init_waitqueue_head(&wqhln->wq_syscall); + + irqflags = ihk_ikc_spinlock_lock(&channel->wq_list_lock); + /* First see if there is a wait queue already */ + list_for_each_entry(wqhln_iter, &channel->wq_list, list) { + if (wqhln_iter->pid == current->tgid) { + kfree(wqhln); + wqhln = wqhln_iter; + list_del(&wqhln->list); + break; + } + } + list_add_tail(&wqhln->list, &channel->wq_list); + ihk_ikc_spinlock_unlock(&channel->wq_list_lock, irqflags); + /* wait for response */ - error = wait_event_interruptible(channel->wq_syscall, channel->req); + error = wait_event_interruptible(wqhln->wq_syscall, channel->req); + + /* Remove per-process wait queue head */ + irqflags = ihk_ikc_spinlock_lock(&channel->wq_list_lock); + list_del(&wqhln->list); + ihk_ikc_spinlock_unlock(&channel->wq_list_lock, irqflags); + kfree(wqhln); + if (error) { printk("remote_page_fault:interrupted. %d\n", error); goto out; diff --git a/executer/user/mcexec.c b/executer/user/mcexec.c index c22b34de..15bc344e 100644 --- a/executer/user/mcexec.c +++ b/executer/user/mcexec.c @@ -664,7 +664,7 @@ int main(int argc, char **argv) argv[optind + 2] = NULL; argc -= (optind - 1); - printf("target_core: %d, device: %s, command: ", target_core, dev); + __dprintf("target_core: %d, device: %s, command: ", target_core, dev); for (i = 1; i < argc; ++i) { printf("%s ", argv[i]); } @@ -966,6 +966,7 @@ int main_loop(int fd, int cpu, pthread_mutex_t *lock) struct timeval tv; w.cpu = cpu; + w.pid = getpid(); while (((ret = ioctl(fd, MCEXEC_UP_WAIT_SYSCALL, (unsigned long)&w)) == 0) || (ret == -1 && errno == EINTR)) { diff --git a/kernel/include/syscall.h b/kernel/include/syscall.h index 68c26853..6a8c86ed 100644 --- a/kernel/include/syscall.h +++ b/kernel/include/syscall.h @@ -87,6 +87,7 @@ struct user_desc { struct ikc_scd_packet { int msg; int ref; + int pid; int err; unsigned long arg; }; diff --git a/kernel/syscall.c b/kernel/syscall.c index 515b9411..4c99860d 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -116,6 +116,9 @@ static void send_syscall(struct syscall_request *req, int cpu) scp = &get_cpu_local_var(0)->scp2; syscall_channel = get_cpu_local_var(0)->syscall_channel2; + + /* XXX: is this really going to work if multiple processes + * exit/receive signals at the same time?? */ cpu = num_processors; } else{ @@ -144,8 +147,9 @@ static void send_syscall(struct syscall_request *req, int cpu) #ifdef SYSCALL_BY_IKC packet.msg = SCD_MSG_SYSCALL_ONESIDE; packet.ref = cpu; - packet.arg = scp->request_rpa; - + packet.pid = cpu_local_var(current)->pid; + packet.arg = scp->request_rpa; + dkprintf("send syscall, nr: %d, pid: %d\n", req->number, packet.pid); ihk_ikc_send(syscall_channel, &packet, 0); #endif } @@ -186,6 +190,8 @@ long do_syscall(struct syscall_request *req, ihk_mc_user_context_t *ctx, int cpu } if (res->status == STATUS_PAGE_FAULT) { + dkprintf("STATUS_PAGE_FAULT in syscall, pid: %d\n", + cpu_local_var(current)->pid); error = page_fault_process(get_cpu_local_var(cpu)->current, (void *)res->fault_address, res->fault_reason);