Exemplo n.º 1
0
/**
 *
 * 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();
}
Exemplo n.º 2
0
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);
}
Exemplo n.º 3
0
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();
}
Exemplo n.º 4
0
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();
}
Exemplo n.º 5
0
/* 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();
}
Exemplo n.º 6
0
/* 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();
}
Exemplo n.º 7
0
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();
}
Exemplo n.º 8
0
/**
 * 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();
}
Exemplo n.º 9
0
/**
 *
 * 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();
}
Exemplo n.º 10
0
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;
}