/** * * Terminate the current process (maybe). If the current process has * more than one running thread, only terminate the current thread. * The process is only completely terminated (as per process_join * wakeup and page table deallocation) when the final thread calls * process_finish(). * * @param The return value of the process. This is only used when the * final thread exits. * */ void process_finish(int retval) { interrupt_status_t intr_status; thread_table_t *thread = thread_get_current_thread_entry(); process_id_t pid = thread->process_id; if (retval < 0) { /* Not permitted! */ retval = 0; } intr_status = _interrupt_disable(); spinlock_acquire(&process_table_slock); /* Mark the stack as free so new threads can reuse it. */ process_free_stack(thread); if (--process_table[pid].threads == 0) { /* We are the last thread - kill process! */ vm_destroy_pagetable(thread->pagetable); finish_given_process(pid, retval); } thread->pagetable = NULL; spinlock_release(&process_table_slock); _interrupt_set_state(intr_status); thread_finish(); }
void process_run(process_id_t pid) { context_t user_context; thread_table_t *my_thread = thread_get_current_thread_entry(); /* If my process is a zombie, that means initialisation failed. */ if (process_table[pid].state == PROCESS_ZOMBIE) { if (my_thread->pagetable) { vm_destroy_pagetable(my_thread->pagetable); my_thread->pagetable = NULL; } thread_finish(); } process_set_pagetable(my_thread->pagetable); my_thread->process_id = pid; my_thread->pagetable = my_thread->pagetable; /* Initialize the user context. (Status register is handled by thread_goto_userland) */ memoryset(&user_context, 0, sizeof(user_context)); _context_set_ip(&user_context, process_table[pid].entry_point); _context_set_sp(&user_context, process_table[pid].stack_top); thread_goto_userland(&user_context); }
void init_startup_thread(uint32_t arg) { /* Threads have arguments for functions they run, we don't need any. Silence the compiler warning by using the argument. */ arg = arg; kprintf("Mounting filesystems\n"); vfs_mount_all(); kprintf("Initializing networking\n"); network_init(); if(bootargs_get("initprog") == NULL) { kprintf("No initial program (initprog), dropping to fallback\n"); init_startup_fallback(); } kprintf("Starting initial program '%s'\n", bootargs_get("initprog")); if (process_spawn(bootargs_get("initprog")) < 0) { KERNEL_PANIC("Cannot fit initial program in process table."); } thread_finish(); }
void process_finish(int retval) { interrupt_status_t intr_status; thread_table_t *thr = thread_get_current_thread_entry(); process_id_t pid = process_get_current_process(); int i; // remove parent references in other processes for (i = 0; i < PROCESS_MAX_PROCESSES; ++i) { intr_status = _interrupt_disable(); spinlock_acquire(&process_table_slock); if (process_table[i].parent_id == pid) process_table[i].parent_id = -1; spinlock_release(&process_table_slock); _interrupt_set_state(intr_status); } intr_status = _interrupt_disable(); spinlock_acquire(&process_table_slock); process_table[pid].retval = retval; process_table[pid].state = PROCESS_ZOMBIE; spinlock_release(&process_table_slock); _interrupt_set_state(intr_status); // clean up virtual memory vm_destroy_pagetable(thr->pagetable); thr->pagetable = NULL; thread_finish(); }
/* Stop the process and the thread it runs in. Sets the return value as well */ void process_finish(int retval) { thread_table_t *thr; thr = thread_get_current_thread_entry(); process_table[process_get_current_process()].state = ZOMBIE; process_table[process_get_current_process()].retval = retval; vm_destroy_pagetable(thr->pagetable); thr->pagetable = NULL; thread_finish(); }
/* Stop the current process and the kernel thread in which it runs Argument: return value */ void process_exit(int retval){ process_id_t pid; thread_table_t * thr; kprintf("starten af exit. reval: %d \n",retval); if (retval < 0){ return; } // gets the process id pid = process_get_current_process(); thr = thread_get_current_thread_entry(); //spinlock spinlock_acquire(&process_table_slock); //Disbale interrupt _interrupt_set_state(_interrupt_disable()); // set the process state to ZOMBIE process_table[pid].state = STATE_ZOMBIE; // Set the process retval to given retval process_table[pid].retval = retval; //cleanup vm_destroy_pagetable(thr->pagetable); thr->pagetable = NULL; /* Wake process */ sleepq_wake_all(&process_table[pid]); /* Unlock the process table */ spinlock_release(&process_table_slock); //enable interrupts _interrupt_set_state(_interrupt_disable()); kprintf("slutningen af exit :O \n"); thread_finish(); }
void process_finish(int retval) { interrupt_status_t intr_status; process_id_t cur = process_get_current_process(); thread_table_t *thread = thread_get_current_thread_entry(); intr_status = _interrupt_disable(); spinlock_acquire(&process_table_slock); process_table[cur].state = PROCESS_ZOMBIE; process_table[cur].retval = retval; /* Remember to destroy the pagetable! */ vm_destroy_pagetable(thread->pagetable); thread->pagetable = NULL; sleepq_wake_all(&process_table[cur]); spinlock_release(&process_table_slock); _interrupt_set_state(intr_status); thread_finish(); }
/** * Terminates the current process and sets a return value */ void process_finish(uint32_t retval) { interrupt_status_t intr_status; process_id_t pid; thread_table_t *my_thread; // Find out who we are. pid = process_get_current_process(); my_thread = thread_get_current_thread_entry(); // Ensure that we're the only ones touching the process table. intr_status = _interrupt_disable(); spinlock_acquire(&process_table_slock); // Mark the stack as free so new threads can reuse it. process_free_stack(my_thread); if(--process_table[pid].threads == 0) { // Last thread in process; now we die. // Mark ourself as dying. process_table[pid].retval = retval; process_table[pid].state = PROCESS_DYING; vm_destroy_pagetable(my_thread->pagetable); // Wake whomever may be sleeping for the process sleepq_wake(&process_table[pid]); } // Free our locks. spinlock_release(&process_table_slock); _interrupt_set_state(intr_status); my_thread->pagetable = NULL; // Kill the thread. thread_finish(); }
/** * * Terminate the current process (maybe). If the current process has * more than one running thread, only terminate the current thread. * The process is only completely terminated (as per process_join * wakeup and page table deallocation) when the final thread calls * process_finish(). * * @param The return value of the process. This is only used when the * final thread exits. * */ void process_finish(int retval) { interrupt_status_t intr_status; thread_table_t *thread = thread_get_current_thread_entry(); process_id_t pid = thread->process_id; if (retval < 0) { /* Not permitted! */ retval = 0; } intr_status = _interrupt_disable(); spinlock_acquire(&process_table_slock); vm_destroy_pagetable(thread->pagetable); finish_given_process(pid, retval); thread->pagetable = NULL; spinlock_release(&process_table_slock); _interrupt_set_state(intr_status); thread_finish(); }
int server_main(char *home, char *dev, char *port, int udp, int ipv4, int log) { int lfd = -1, kdpfd, nfds, nfd, curfds, efd[2], refd[2], tunfd, i; unsigned int cpus = 0, threads, udp_cpu = 0; ssize_t ret; struct epoll_event *events; struct addrinfo hints, *ahead, *ai; auth_log = !!log; openlog("curvetun", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_DAEMON); syslog(LOG_INFO, "curvetun server booting!\n"); syslog_maybe(!auth_log, LOG_INFO, "curvetun user logging disabled!\n"); parse_userfile_and_generate_user_store_or_die(home); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM; hints.ai_protocol = udp ? IPPROTO_UDP : IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; ret = getaddrinfo(NULL, port, &hints, &ahead); if (ret < 0) syslog_panic("Cannot get address info!\n"); for (ai = ahead; ai != NULL && lfd < 0; ai = ai->ai_next) { lfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (lfd < 0) continue; if (ai->ai_family == AF_INET6) { #ifdef IPV6_V6ONLY ret = set_ipv6_only(lfd); if (ret < 0) { close(lfd); lfd = -1; continue; } #else close(lfd); lfd = -1; continue; #endif /* IPV6_V6ONLY */ } set_reuseaddr(lfd); set_mtu_disc_dont(lfd); ret = bind(lfd, ai->ai_addr, ai->ai_addrlen); if (ret < 0) { close(lfd); lfd = -1; continue; } if (!udp) { ret = listen(lfd, 5); if (ret < 0) { close(lfd); lfd = -1; continue; } } if (ipv4 == -1) { ipv4 = (ai->ai_family == AF_INET6 ? 0 : (ai->ai_family == AF_INET ? 1 : -1)); } syslog_maybe(auth_log, LOG_INFO, "curvetun on IPv%d via %s " "on port %s!\n", ai->ai_family == AF_INET ? 4 : 6, udp ? "UDP" : "TCP", port); syslog_maybe(auth_log, LOG_INFO, "Allowed overlay proto is " "IPv%d!\n", ipv4 ? 4 : 6); } freeaddrinfo(ahead); if (lfd < 0 || ipv4 < 0) syslog_panic("Cannot create socket!\n"); tunfd = tun_open_or_die(dev ? dev : DEVNAME_SERVER, IFF_TUN | IFF_NO_PI); pipe_or_die(efd, O_NONBLOCK); pipe_or_die(refd, O_NONBLOCK); set_nonblocking(lfd); events = xzmalloc(MAX_EPOLL_SIZE * sizeof(*events)); for (i = 0; i < MAX_EPOLL_SIZE; ++i) events[i].data.fd = -1; kdpfd = epoll_create(MAX_EPOLL_SIZE); if (kdpfd < 0) syslog_panic("Cannot create socket!\n"); set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, lfd, udp ? EPOLLIN | EPOLLET | EPOLLONESHOT : EPOLLIN); set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, efd[0], EPOLLIN); set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, refd[0], EPOLLIN); set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, tunfd, EPOLLIN | EPOLLET | EPOLLONESHOT); curfds = 4; trie_init(); cpus = get_number_cpus_online(); threads = cpus * THREADS_PER_CPU; if (!ispow2(threads)) syslog_panic("Thread number not power of two!\n"); threadpool = xzmalloc(sizeof(*threadpool) * threads); thread_spawn_or_panic(cpus, efd[1], refd[1], tunfd, ipv4, udp); init_cpusched(threads); register_socket(tunfd); register_socket(lfd); syslog(LOG_INFO, "curvetun up and running!\n"); while (likely(!sigint)) { nfds = epoll_wait(kdpfd, events, curfds, -1); if (nfds < 0) { syslog(LOG_ERR, "epoll_wait error: %s\n", strerror(errno)); break; } for (i = 0; i < nfds; ++i) { if (unlikely(events[i].data.fd < 0)) continue; if (events[i].data.fd == lfd && !udp) { int ncpu; char hbuff[256], sbuff[256]; struct sockaddr_storage taddr; socklen_t tlen; tlen = sizeof(taddr); nfd = accept(lfd, (struct sockaddr *) &taddr, &tlen); if (nfd < 0) { syslog(LOG_ERR, "accept error: %s\n", strerror(errno)); continue; } if (curfds + 1 > MAX_EPOLL_SIZE) { close(nfd); continue; } curfds++; ncpu = register_socket(nfd); memset(hbuff, 0, sizeof(hbuff)); memset(sbuff, 0, sizeof(sbuff)); getnameinfo((struct sockaddr *) &taddr, tlen, hbuff, sizeof(hbuff), sbuff, sizeof(sbuff), NI_NUMERICHOST | NI_NUMERICSERV); syslog_maybe(auth_log, LOG_INFO, "New connection " "from %s:%s (%d active client connections) - id %d on CPU%d", hbuff, sbuff, curfds-4, nfd, ncpu); set_nonblocking(nfd); set_socket_keepalive(nfd); set_tcp_nodelay(nfd); ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_ADD, nfd, EPOLLIN | EPOLLET | EPOLLONESHOT); if (ret < 0) { close(nfd); curfds--; continue; } } else if (events[i].data.fd == refd[0]) { int fd_one; ret = read_exact(refd[0], &fd_one, sizeof(fd_one), 1); if (ret != sizeof(fd_one) || fd_one <= 0) continue; ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_MOD, fd_one, EPOLLIN | EPOLLET | EPOLLONESHOT); if (ret < 0) { close(fd_one); continue; } } else if (events[i].data.fd == efd[0]) { int fd_del, test; ret = read_exact(efd[0], &fd_del, sizeof(fd_del), 1); if (ret != sizeof(fd_del) || fd_del <= 0) continue; ret = read(fd_del, &test, sizeof(test)); if (ret < 0 && errno == EBADF) continue; ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_DEL, fd_del, 0); if (ret < 0) { close(fd_del); continue; } close(fd_del); curfds--; unregister_socket(fd_del); syslog_maybe(auth_log, LOG_INFO, "Closed connection " "with id %d (%d active client connections remain)\n", fd_del, curfds-4); } else { int cpu, fd_work = events[i].data.fd; if (!udp) cpu = socket_to_cpu(fd_work); else udp_cpu = (udp_cpu + 1) & (threads - 1); write_exact(threadpool[udp ? udp_cpu : cpu].efd[1], &fd_work, sizeof(fd_work), 1); } } } syslog(LOG_INFO, "curvetun prepare shut down!\n"); close(lfd); close(efd[0]); close(efd[1]); close(refd[0]); close(refd[1]); close(tunfd); thread_finish(cpus); xfree(threadpool); xfree(events); unregister_socket(lfd); unregister_socket(tunfd); destroy_cpusched(); trie_cleanup(); destroy_user_store(); syslog(LOG_INFO, "curvetun shut down!\n"); closelog(); return 0; }