BNX2X: spatch signed typedefs
[akaros.git] / kern / src / syscall.c
index fce4e51..7f9e80a 100644 (file)
@@ -35,6 +35,7 @@
 #include <arsc_server.h>
 #include <event.h>
 #include <termios.h>
+#include <manager.h>
 
 /* Tracing Globals */
 int systrace_flags = 0;
@@ -65,11 +66,19 @@ static bool __trace_this_proc(struct proc *p)
 static size_t systrace_fill_pretty_buf(struct systrace_record *trace)
 {
        size_t len = 0;
+       struct timespec ts_start;
+       struct timespec ts_end;
+       tsc2timespec(trace->start_timestamp, &ts_start);
+       tsc2timespec(trace->end_timestamp, &ts_end);
+
        len = snprintf(trace->pretty_buf, SYSTR_PRETTY_BUF_SZ - len,
-                  "[%16llu] [%16lu] Syscall %3d (%12s):(0x%x, 0x%x, 0x%x, 0x%x, "
-                  "0x%x, 0x%x) ret: %p proc: %d core: %d vcore: %d data: ",
-                  trace->start_timestamp,
-                  trace->end_timestamp,
+                  "[%7d.%09d]-[%7d.%09d] Syscall %3d (%12s):(0x%llx, 0x%llx, "
+                  "0x%llx, 0x%llx, 0x%llx, 0x%llx) ret: 0x%llx proc: %d core: %d "
+                  "vcore: %d data: ",
+                  ts_start.tv_sec,
+                  ts_start.tv_nsec,
+                  ts_end.tv_sec,
+                  ts_end.tv_nsec,
                   trace->syscallno,
                   syscall_table[trace->syscallno].name,
                   trace->arg0,
@@ -82,6 +91,12 @@ static size_t systrace_fill_pretty_buf(struct systrace_record *trace)
                   trace->pid,
                   trace->coreid,
                   trace->vcoreid);
+       /* if we have extra data, print it out on the next line, lined up nicely.
+        * this is only useful for looking at the dump in certain terminals.  if we
+        * have a tool that processes the info, we shouldn't do this. */
+       if (trace->datalen)
+               len += snprintf(trace->pretty_buf + len, SYSTR_PRETTY_BUF_SZ - len,
+                               "\n%67s", "");
        len += printdump(trace->pretty_buf + len,
                         MIN(trace->datalen, SYSTR_PRETTY_BUF_SZ - len - 1),
                         trace->data);
@@ -101,8 +116,9 @@ static void systrace_start_trace(struct kthread *kthread, struct syscall *sysc)
        coreid = core_id();
        vcoreid = proc_get_vcoreid(p);
        if (systrace_flags & SYSTRACE_LOUD) {
-               printk("ENTER [%16llu] Syscall %3d (%12s):(0x%x, 0x%x, 0x%x, 0x%x, "
-                      "0x%x, 0x%x) proc: %d core: %d vcore: %d\n", read_tsc(),
+               printk("ENTER [%16llu] Syscall %3d (%12s):(0x%llx, 0x%llx, 0x%llx, "
+                      "0x%llx, 0x%llx, 0x%llx) proc: %d core: %d vcore: %d\n",
+                      read_tsc(),
                       sysc->num, syscall_table[sysc->num].name,
                           sysc->arg0, sysc->arg1, sysc->arg2, sysc->arg3, sysc->arg4,
                           sysc->arg5, p->pid, coreid, vcoreid);
@@ -148,6 +164,7 @@ static void systrace_finish_trace(struct kthread *kthread, long retval)
 static void alloc_sysc_str(struct kthread *kth)
 {
        kth->name = kmalloc(SYSCALL_STRLEN, KMALLOC_WAIT);
+       kth->name[0] = 0;
 }
 
 static void free_sysc_str(struct kthread *kth)
@@ -240,7 +257,7 @@ void unset_errno(void)
        pcpui->cur_kthread->sysc->errstr[0] = '\0';
 }
 
-void set_errstr(char *fmt, ...)
+void set_errstr(const char *fmt, ...)
 {
        va_list ap;
        int rc;
@@ -311,14 +328,9 @@ static int sys_null(void)
  * async I/O handling. */
 static int sys_block(struct proc *p, unsigned int usec)
 {
-       struct timer_chain *tchain = &per_cpu_info[core_id()].tchain;
-       struct alarm_waiter a_waiter;
-       init_awaiter(&a_waiter, 0);
        /* Note printing takes a few ms, so your printds won't be perfect. */
        printd("[kernel] sys_block(), sleeping at %llu\n", read_tsc());
-       set_awaiter_rel(&a_waiter, usec);
-       set_alarm(tchain, &a_waiter);
-       sleep_on_awaiter(&a_waiter);
+       kthread_usleep(usec);
        printd("[kernel] sys_block(), waking up at %llu\n", read_tsc());
        return 0;
 }
@@ -483,7 +495,6 @@ static int sys_proc_create(struct proc *p, char *path, size_t path_l,
                set_errstr("Failed to alloc new proc");
                goto mid_error;
        }
-       proc_set_progname(new_p, file_name(program));
        /* close the CLOEXEC ones, even though this isn't really an exec */
        close_9ns_files(new_p, TRUE);
        close_all_files(&new_p->open_files, TRUE);
@@ -502,6 +513,8 @@ static int sys_proc_create(struct proc *p, char *path, size_t path_l,
                set_errstr("Failed to load elf");
                goto late_error;
        }
+       /* progname is argv0, which accounts for symlinks */
+       proc_set_progname(p, p->procinfo->argbuf);
        kref_put(&program->f_kref);
        __proc_ready(new_p);
        pid = new_p->pid;
@@ -731,7 +744,8 @@ static int sys_exec(struct proc *p, char *path, size_t path_l,
                                   sizeof(pi->argbuf)))
                goto mid_error;
        /* This is the point of no return for the process. */
-       proc_set_progname(p, file_name(program));
+       /* progname is argv0, which accounts for symlinks */
+       proc_set_progname(p, p->procinfo->argbuf);
        #ifdef CONFIG_X86
        /* clear this, so the new program knows to get an LDT */
        p->procdata->ldt = 0;
@@ -1073,31 +1087,52 @@ static int sys_vc_entry(struct proc *p)
        return 0;
 }
 
-/* This will set a local timer for usec, then shut down the core.  There's a
- * slight race between spinner and halt.  For now, the core will wake up for
- * other interrupts and service them, but will not process routine messages or
- * do anything other than halt until the alarm goes off.  We could just unset
- * the alarm and return early.  On hardware, there are a lot of interrupts that
- * come in.  If we ever use this, we can take a closer look.  */
+/* This will halt the core, waking on an IRQ.  These could be kernel IRQs for
+ * things like timers or devices, or they could be IPIs for RKMs (__notify for
+ * an evq with IPIs for a syscall completion, etc).
+ *
+ * We don't need to finish the syscall early (worried about the syscall struct,
+ * on the vcore's stack).  The syscall will finish before any __preempt RKM
+ * executes, so the vcore will not restart somewhere else before the syscall
+ * completes (unlike with yield, where the syscall itself adjusts the vcore
+ * structures).
+ *
+ * In the future, RKM code might avoid sending IPIs if the core is already in
+ * the kernel.  That code will need to check the CPU's state in some manner, and
+ * send if the core is halted/idle.
+ *
+ * The core must wake up for RKMs, including RKMs that arrive while the kernel
+ * is trying to halt.  The core need not abort the halt for notif_pending for
+ * the vcore, only for a __notify or other RKM.  Anyone setting notif_pending
+ * should then attempt to __notify (o/w it's probably a bug). */
 static int sys_halt_core(struct proc *p, unsigned int usec)
 {
-       struct timer_chain *tchain = &per_cpu_info[core_id()].tchain;
-       struct alarm_waiter a_waiter;
-       bool spinner = TRUE;
-       void unblock(struct alarm_waiter *waiter)
-       {
-               spinner = FALSE;
-       }
-       init_awaiter(&a_waiter, unblock);
-       set_awaiter_rel(&a_waiter, MAX(usec, 100));
-       set_alarm(tchain, &a_waiter);
-       enable_irq();
-       /* Could wake up due to another interrupt, but we want to sleep still. */
-       while (spinner) {
-               cpu_halt();     /* slight race between spinner and halt */
-               cpu_relax();
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       struct preempt_data *vcpd;
+       /* The user can only halt CG cores!  (ones it owns) */
+       if (management_core())
+               return -1;
+       disable_irq();
+       /* both for accounting and possible RKM optimizations */
+       __set_cpu_state(pcpui, CPU_STATE_IDLE);
+       wrmb();
+       if (has_routine_kmsg()) {
+               __set_cpu_state(pcpui, CPU_STATE_KERNEL);
+               enable_irq();
+               return 0;
        }
-       printd("Returning from halting\n");
+       /* This situation possible, though the check is not necessary.  We can't
+        * assert notif_pending isn't set, since another core may be in the
+        * proc_notify.  Thus we can't tell if this check here caught a bug, or just
+        * aborted early. */
+       vcpd = &p->procdata->vcore_preempt_data[pcpui->owning_vcoreid];
+       if (vcpd->notif_pending) {
+               __set_cpu_state(pcpui, CPU_STATE_KERNEL);
+               enable_irq();
+               return 0;
+       }
+       /* CPU_STATE is reset to KERNEL by the IRQ handler that wakes us */
+       cpu_halt();
        return 0;
 }
 
@@ -1205,6 +1240,7 @@ static intreg_t sys_write(struct proc *p, int fd, const void *buf, int len)
        struct systrace_record *t = pcpui->cur_kthread->trace;
        ssize_t ret;
        struct file *file = get_file_from_fd(&p->open_files, fd);
+       sysc_save_str("write on fd %d", fd);
        /* VFS */
        if (file) {
                if (!file->f_op->write) {
@@ -1262,7 +1298,7 @@ static intreg_t sys_open(struct proc *p, const char *path, size_t path_l,
        /* VFS */
        if (file) {
                /* stores the ref to file */
-               fd = insert_file(&p->open_files, file, 0, FALSE);
+               fd = insert_file(&p->open_files, file, 0, FALSE, oflag & O_CLOEXEC);
                kref_put(&file->f_kref);        /* drop our ref */
                if (fd < 0)
                        warn("File insertion failed");
@@ -1428,9 +1464,10 @@ intreg_t sys_fcntl(struct proc *p, int fd, int cmd, int arg)
                return -1;
        }
 
+       /* TODO: these are racy */
        switch (cmd) {
                case (F_DUPFD):
-                       retval = insert_file(&p->open_files, file, arg, FALSE);
+                       retval = insert_file(&p->open_files, file, arg, FALSE, FALSE);
                        if (retval < 0) {
                                set_errno(-retval);
                                retval = -1;
@@ -1440,8 +1477,13 @@ intreg_t sys_fcntl(struct proc *p, int fd, int cmd, int arg)
                        retval = p->open_files.fd[fd].fd_flags;
                        break;
                case (F_SETFD):
-                       if (arg == FD_CLOEXEC)
-                               file->f_flags |= O_CLOEXEC;
+                       /* I'm considering not supporting this at all.  They must do it at
+                        * open time or fix their buggy/racy code. */
+                       spin_lock(&p->open_files.lock);
+                       if (arg & FD_CLOEXEC)
+                               p->open_files.fd[fd].fd_flags |= FD_CLOEXEC;
+                       retval = p->open_files.fd[fd].fd_flags;
+                       spin_unlock(&p->open_files.lock);
                        break;
                case (F_GETFL):
                        retval = file->f_flags;
@@ -2133,7 +2175,8 @@ static intreg_t sys_dup_fds_to(struct proc *p, unsigned int pid,
                map[i].ok = -1;
                file = get_file_from_fd(&p->open_files, map[i].parentfd);
                if (file) {
-                       slot = insert_file(&child->open_files, file, map[i].childfd, TRUE);
+                       slot = insert_file(&child->open_files, file, map[i].childfd, TRUE,
+                                          FALSE);
                        if (slot == map[i].childfd) {
                                map[i].ok = 0;
                                ret++;
@@ -2397,6 +2440,14 @@ int systrace_reg(bool all, struct proc *p)
        return retval;
 }
 
+int systrace_trace_pid(struct proc *p)
+{
+       if (systrace_reg(false, p))
+               error("no more processes");
+       systrace_start(true);
+       return 0;
+}
+
 void systrace_stop(void)
 {
        spin_lock_irqsave(&systrace_lock);