Logo Search packages:      
Sourcecode: faumachine version File versions  Download package

glue-main.c

/* $Id: glue-main.c,v 1.150 2009-02-03 17:49:16 potyra Exp $ 
 *
 * Copyright (C) 2007-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

/* set this to '1' to enable profiling */
#define PROFILING 0

#define NSCHEDULES      128

#include "config.h"

#include "compiler.h"

#include <sys/time.h>
#include <sys/resource.h>
#include <assert.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>

#if defined(LINUX)
#define __USE_GNU 1     /* Need REG_ definitions. */
#include <ucontext.h>
#undef __USE_GNU
#endif
#include <unistd.h>

#if defined(DARWIN)
#include <sys/ucontext.h>
#include <sys/types.h>
#include <sys/syslimits.h>
#endif

#include "bridge.h"
#include "glue-audio.h"
#include "glue-io.h"
#include "glue-log.h"
#include "glue-main.h"
#include "glue-proc.h"
#include "simnodes.h"
#include "umutil.h"
#include "../node-pc/gui.h"
#include "simsetup_expect.h"
#include "glue-setup.h"

const char *progname;
const char *basedir = "node.def";
int loglevel = 0;
const char *simulation_setup_name = "simulation.setup";

int failure = 0;

struct schedules {
      struct schedules *prev;
      struct schedules *next;

      unsigned long long time;
      void (*func)(void *);
      void *data;
};

static volatile int sigs = 0;

static struct schedules schedule[NSCHEDULES];
static struct schedules *schedule_free_first;
static struct schedules *schedule_free_last;
static struct schedules *schedule_active_first;
static struct schedules *schedule_active_last;

static struct timeval time_tv_start;
static struct timeval time_tv_stop;
static unsigned long long time_host;
static unsigned long long time_guest;
static unsigned long long time_sync;
static unsigned int time_shift;

static struct process *scheduler;
static struct process *current;
static struct process *proc_first;
static struct process *proc_last;

static struct process myself;


void
time_call_at(
      unsigned long long tsc,
      void (*func)(void *),
      void *data
)
{
      struct schedules *entry;

      assert(schedule_free_first);

      entry = schedule_free_first;

      /* Remove from free list. */
      schedule_free_first = entry->next;
      if (entry->next) {
            entry->next->prev = (struct schedules *) 0;
      } else {
            schedule_free_last = (struct schedules *) 0;
      }

      /* Fill entry. */
      entry->time = tsc;
      entry->func = func;
      entry->data = data;

      /* Insert into active list (sorted by time). */
      if (! schedule_active_first) {
            /* First and only entry. */
            entry->prev = (struct schedules *) 0;
            entry->next = (struct schedules *) 0;
            schedule_active_first = entry;
            schedule_active_last = entry;

      } else if (tsc <= schedule_active_first->time) {
            /* First entry. */
            entry->prev = (struct schedules *) 0;
            entry->next = schedule_active_first;
            schedule_active_first = entry;
            entry->next->prev = entry;

      } else if (schedule_active_last->time <= tsc) {
            /* Last entry. */
            entry->prev = schedule_active_last;
            entry->next = (struct schedules *) 0;
            entry->prev->next = entry;
            schedule_active_last = entry;

      } else {
            struct schedules *prev;
            struct schedules *next;

            for (prev = (struct schedules *) 0, next = schedule_active_first;
                next->time < tsc;
                prev = next, next = next->next) {
            }
            entry->prev = prev;
            entry->next = next;
            entry->prev->next = entry;
            entry->next->prev = entry;
      }
}

void
time_call_after(unsigned long long delay, void (*func)(void *), void *data)
{
      time_call_at(time_guest + delay, func, data);
}

int
time_call_delete(void (*func)(void *), void *data)
{
      struct schedules *entry;

      for (entry = schedule_active_first;
          ;
          entry = entry->next) {
            if (! entry) {
                  /* Entry not found. */
                  return 1;
            }
            if (entry->func == func
             && entry->data == data) {
                  /* Remove entry from active list. */
                  if (entry->prev) {
                        entry->prev->next = entry->next;
                  } else {
                        schedule_active_first = entry->next;
                  }
                  if (entry->next) {
                        entry->next->prev = entry->prev;
                  } else {
                        schedule_active_last = entry->prev;
                  }

                  /* Append to free list. */
                  entry->prev = schedule_free_last;
                  entry->next = (struct schedules *) 0;
                  if (entry->prev) {
                        entry->prev->next = entry;
                  } else {
                        schedule_free_first = entry;
                  }
                  schedule_free_last = entry;

                  return 0;
            }
      }
}

unsigned long long
time_real(void)
{
      struct timeval tv;
      unsigned long long sec;
      unsigned long long usec;
      int ret;

      ret = gettimeofday(&tv, (struct timezone *) 0);
      assert(0 <= ret);

      sec = tv.tv_sec - time_tv_start.tv_sec;
      usec = tv.tv_usec; /* Ignore time_tv_start.tv_usec. */

      return sec * TIME_HZ + usec * TIME_HZ / 1000000;
}

unsigned long long
time_virt(void)
{
      return time_guest;
}

void
time_stop(void)
{
      int ret;

      ret = gettimeofday(&time_tv_stop, (struct timezone *) 0);
      assert(0 <= ret);
}

void
time_cont(void)
{
      struct timeval time_tv_cont;
      int sec;
      int usec;
      int ret;

      ret = gettimeofday(&time_tv_cont, (struct timezone *) 0);
      assert(0 <= ret);

      sec = time_tv_cont.tv_sec - time_tv_stop.tv_sec;
      usec = time_tv_cont.tv_usec - time_tv_stop.tv_usec;
      if (usec < 0) {
            usec += 1000000;
            sec -= 1;
      }
      assert(0 <= usec && usec < 1000000);
      assert(0 <= sec);

      time_tv_start.tv_usec += usec;
      if (1000000 <= time_tv_start.tv_usec) {
            time_tv_start.tv_usec -= 1000000;
            time_tv_start.tv_sec += 1;
      }
      time_tv_start.tv_sec += sec;
}

void
sched_to_process(struct process *p);
asm (
#if defined(DARWIN)
"_sched_to_process: .globl _sched_to_process\n"
#else
"sched_to_process: .globl sched_to_process\n"
#endif
#if defined(__i386__)
"     pushl %ebx\n" /* Save scheduler's regs. */
"     pushl %ecx\n"
"     pushl %edi\n"
"     pushl %esi\n"
"     pushl %ebp\n"
#if defined(DARWIN)
"     movl %esp, _scheduler\n"
#else
"     movl %esp, scheduler\n"
#endif

"     movl 6*4(%esp), %ebx\n" /* Get "p". */

#if defined(DARWIN)
"     movl %ebx, _current\n" /* Load process' regs. */
#else
"     movl %ebx, current\n" /* Load process' regs. */
#endif
"     movl (%ebx), %esp\n"
"     popl %ebp\n"
"     popl %esi\n"
"     popl %edi\n"
"     popl %ecx\n"
"     popl %ebx\n"
"     ret\n"

#elif defined(__x86_64__)
"     pushq %rbx\n" /* Save scheduler's regs. */
"     pushq %rcx\n"
"     pushq %rdx\n"
"     pushq %rdi\n"
"     pushq %rsi\n"
"     pushq %rbp\n"
"     pushq %r8\n"
"     pushq %r9\n"
"     pushq %r10\n"
"     pushq %r11\n"
"     pushq %r12\n"
"     pushq %r13\n"
"     pushq %r14\n"
"     pushq %r15\n"
#if defined(DARWIN)
"     movq %rsp, _scheduler\n"
#else
"     movq %rsp, scheduler\n"
#endif

"     movq %rdi, %rbx\n" /* Get "p". */

#if defined(DARWIN)
"     movq %rbx, _current\n" /* Load process' regs. */
#else
"     movq %rbx, current\n" /* Load process' regs. */
#endif
"     movq (%rbx), %rsp\n"
"     popq %r15\n"
"     popq %r14\n"
"     popq %r13\n"
"     popq %r12\n"
"     popq %r11\n"
"     popq %r10\n"
"     popq %r9\n"
"     popq %r8\n"
"     popq %rbp\n"
"     popq %rsi\n"
"     popq %rdi\n"
"     popq %rdx\n"
"     popq %rcx\n"
"     popq %rbx\n"
"     retq\n"

#else
#error Unknown CPU
#endif
);

asm (
#if defined(DARWIN)
"_sched_to_scheduler: .globl _sched_to_scheduler\n"
#else
"sched_to_scheduler: .globl sched_to_scheduler\n"
#endif
#if defined(__i386__)
"     pushl %ebx\n" /* Save process' regs. */
"     pushl %ecx\n"
"     pushl %edi\n"
"     pushl %esi\n"
"     pushl %ebp\n"
#if defined(DARWIN)
"     movl _current, %ebx\n"
#else
"     movl current, %ebx\n"
#endif
"     movl %esp, (%ebx)\n"

#if defined(DARWIN)
"     movl _scheduler, %esp\n" /* Load scheduler's regs. */
#else
"     movl scheduler, %esp\n" /* Load scheduler's regs. */
#endif
"     popl %ebp\n"
"     popl %esi\n"
"     popl %edi\n"
"     popl %ecx\n"
"     popl %ebx\n"
"     ret\n"

#elif defined(__x86_64__)
"     pushq %rbx\n" /* Save process' regs. */
"     pushq %rcx\n"
"     pushq %rdx\n"
"     pushq %rdi\n"
"     pushq %rsi\n"
"     pushq %rbp\n"
"     pushq %r8\n"
"     pushq %r9\n"
"     pushq %r10\n"
"     pushq %r11\n"
"     pushq %r12\n"
"     pushq %r13\n"
"     pushq %r14\n"
"     pushq %r15\n"
#if defined(DARWIN)
"     movq _current, %rbx\n"
#else
"     movq current, %rbx\n"
#endif
"     movq %rsp, (%rbx)\n"

#if defined(DARWIN)
"     movq _scheduler, %rsp\n" /* Load schedulers regs. */
#else
"     movq scheduler, %rsp\n" /* Load schedulers regs. */
#endif
"     popq %r15\n"
"     popq %r14\n"
"     popq %r13\n"
"     popq %r12\n"
"     popq %r11\n"
"     popq %r10\n"
"     popq %r9\n"
"     popq %r8\n"
"     popq %rbp\n"
"     popq %rsi\n"
"     popq %rdi\n"
"     popq %rdx\n"
"     popq %rcx\n"
"     popq %rbx\n"
"     retq\n"

#else
#error Unknown CPU
#endif
);

void
sched_sleep(void)
{
      assert(current->state == PROCESS_RUNNING);

      current->state = PROCESS_SLEEPING;

      /* Remove process from run queue. */
      if (current->prev) {
            current->prev->next = current->next;
      } else {
            proc_first = current->next;
      }
      if (current->next) {
            current->next->prev = current->prev;
      } else {
            proc_last = current->prev;
      }

      sched_to_scheduler();
}

void
sched_wakeup(struct process *p)
{
      if (p->state != PROCESS_SLEEPING) {
            return;
      }

      p->state = PROCESS_RUNNING;

      /* Add process to run queue. */
      p->prev = (struct process *) 0;
      p->next = proc_first;
      proc_first = p;
      assert(p->next);
      p->next->prev = p;
}

void
sched_process_init(struct process *p, void (*f)(void *), void *s)
{
#if defined(__i386__)
      uint32_t *sp;
      uint8_t *sp8;

      sp8 = (uint8_t *) &p->stack[sizeof(p->stack)];

      /* Stack Alignment */
      while(((unsigned long int)sp8 & 15) != 4) {
            *--sp8 = 0;
      }
      sp = (uint32_t *) sp8;

      *--sp = (uint32_t) s;
      *--sp = 0; /* Return Address */

      *--sp = (uint32_t) f; /* eip */
      *--sp = 0; /* ebx */
      *--sp = 0; /* ecx */
      *--sp = 0; /* edi */
      *--sp = 0; /* esi */
      *--sp = 0; /* ebp */

      p->sp = (void *) sp;

#elif defined(__x86_64__)
      uint64_t *sp;
      uint8_t  *sp8;

      sp8 = (uint8_t *) &p->stack[sizeof(p->stack)];

      /* Stack Alignment */
      while(((unsigned long long int)sp8 & 15) != 0) {
            *--sp8 = 0;
      }
      sp = (uint64_t *) sp8;

      *--sp = 0; /* Return Address */

      *--sp = (uint64_t) f; /* rip */
      *--sp = 0; /* rbx */
      *--sp = 0; /* rcx */
      *--sp = 0; /* rdx */
      *--sp = (uint64_t) s; /* rdi */
      *--sp = 0; /* rsi */
      *--sp = 0; /* rbp */
      *--sp = 0; /* r8 */
      *--sp = 0; /* r9 */
      *--sp = 0; /* r10 */
      *--sp = 0; /* r11 */
      *--sp = 0; /* r12 */
      *--sp = 0; /* r13 */
      *--sp = 0; /* r14 */
      *--sp = 0; /* r15 */

      p->sp = (void *) sp;
#else
#error Unknown CPU
#endif

      p->state = PROCESS_RUNNING;

      p->prev = (struct process *) 0;
      p->next = proc_first;
      proc_first = p;
      if (p->next) {
            p->next->prev = p;
      } else {
            proc_last = p;
      }
}

void
frontend_quit(void)
{
      sigs |= 1;
}

static void
sig_debug(int sig)
{
      loglevel ^= 1;
}

static void __attribute__((__noreturn__))
sig_exception(int sig, siginfo_t *si, void *uc)
{
#if defined(LINUX)
      mcontext_t *regs = &((ucontext_t *) uc)->uc_mcontext;

#if defined(__i386__)
      fprintf(stderr, "Exception %u at %08x (cr2=%08x):\n",
                  (uint32_t) regs->gregs[REG_TRAPNO],
                  (uint32_t) regs->gregs[REG_EIP],
                  (uint32_t) regs->cr2);
      fprintf(stderr, "eax=%08x ebx=%08x ecx=%08x edx=%08x\n",
                  (uint32_t) regs->gregs[REG_EAX],
                  (uint32_t) regs->gregs[REG_EBX],
                  (uint32_t) regs->gregs[REG_ECX],
                  (uint32_t) regs->gregs[REG_EDX]);
      fprintf(stderr, "ebp=%08x esp=%08x edi=%08x esi=%08x\n",
                  (uint32_t) regs->gregs[REG_EBP],
                  (uint32_t) regs->gregs[REG_ESP],
                  (uint32_t) regs->gregs[REG_EDI],
                  (uint32_t) regs->gregs[REG_ESI]);
#elif defined(__x86_64__)
      fprintf(stderr, "Exception %lu at %016lx (cr2=%016lx):\n",
                  (uint64_t) regs->gregs[REG_TRAPNO],
                  (uint64_t) regs->gregs[REG_RIP],
                  (uint64_t) regs->gregs[REG_CR2]);
      fprintf(stderr, "rax=%016lx rbx=%016lx rcx=%016lx rdx=%016lx\n",
                  (uint64_t) regs->gregs[REG_RAX],
                  (uint64_t) regs->gregs[REG_RBX],
                  (uint64_t) regs->gregs[REG_RCX],
                  (uint64_t) regs->gregs[REG_RDX]);
      fprintf(stderr, "rbp=%016lx rsp=%016lx rdi=%016lx rsi=%016lx\n",
                  (uint64_t) regs->gregs[REG_RBP],
                  (uint64_t) regs->gregs[REG_RSP],
                  (uint64_t) regs->gregs[REG_RDI],
                  (uint64_t) regs->gregs[REG_RSI]);
      fprintf(stderr, "r08=%016lx r09=%016lx r10=%016lx r11=%016lx\n",
                  (uint64_t) regs->gregs[REG_R8],
                  (uint64_t) regs->gregs[REG_R9],
                  (uint64_t) regs->gregs[REG_R10],
                  (uint64_t) regs->gregs[REG_R11]);
      fprintf(stderr, "r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n",
                  (uint64_t) regs->gregs[REG_R12],
                  (uint64_t) regs->gregs[REG_R13],
                  (uint64_t) regs->gregs[REG_R14],
                  (uint64_t) regs->gregs[REG_R15]);
#else
#warning "Unsupported CPU - FIXME"
#endif
#elif defined(OPENBSD)
      struct sigcontext *regs = (struct sigcontext *) uc;

#if defined(__i386__)
      fprintf(stderr, "Exception %u at %08x (cr2=%08x):\n",
                  (uint32_t) regs->sc_trapno,
                  (uint32_t) regs->sc_eip,
                  (uint32_t) si->si_addr);
      fprintf(stderr, "eax=%08x ebx=%08x ecx=%08x edx=%08x\n",
                  (uint32_t) regs->sc_eax,
                  (uint32_t) regs->sc_ebx,
                  (uint32_t) regs->sc_ecx,
                  (uint32_t) regs->sc_edx);
      fprintf(stderr, "ebp=%08x esp=%08x edi=%08x esi=%08x\n",
                  (uint32_t) regs->sc_ebp,
                  (uint32_t) regs->sc_esp,
                  (uint32_t) regs->sc_edi,
                  (uint32_t) regs->sc_esi);
#else
#warning "Unsupported CPU - FIXME"
#endif
#elif defined(DARWIN)
      mcontext_t mc = ((ucontext_t *) uc)->uc_mcontext;

#if defined(__i386__)
      fprintf(stderr, "Exception %u at %08x:\n",
                  (uint32_t) mc->__es.__trapno,
                  (uint32_t) mc->__ss.__eip);
      fprintf(stderr, "eax=%08x ebx=%08x ecx=%08x edx=%08x\n",
                  (uint32_t) mc->__ss.__eax,
                  (uint32_t) mc->__ss.__ebx,
                  (uint32_t) mc->__ss.__ecx,
                  (uint32_t) mc->__ss.__edx);
      fprintf(stderr, "ebp=%08x esp=%08x edi=%08x esi=%08x\n",
                  (uint32_t) mc->__ss.__ebp,
                  (uint32_t) mc->__ss.__esp,
                  (uint32_t) mc->__ss.__edi,
                  (uint32_t) mc->__ss.__esi);
#elif defined(__x86_64__)
      fprintf(stderr, "Exception %lu at %016lx:\n",
                  (uint64_t) mc->es.trapno,
                  (uint64_t) mc->ss.rip);
      fprintf(stderr, "rax=%016lx rbx=%016lx rcx=%016lx rdx=%016lx\n",
                  (uint64_t) mc->ss.rax,
                  (uint64_t) mc->ss.rbx,
                  (uint64_t) mc->ss.rcx,
                  (uint64_t) mc->ss.rdx);
      fprintf(stderr, "rbp=%016lx rsp=%016lx rdi=%016lx rsi=%016lx\n",
                  (uint64_t) mc->ss.rbp,
                  (uint64_t) mc->ss.rsp,
                  (uint64_t) mc->ss.rdi,
                  (uint64_t) mc->ss.rsi);
      fprintf(stderr, "r08=%016lx r09=%016lx r10=%016lx r11=%016lx\n",
                  (uint64_t) mc->ss.r8,
                  (uint64_t) mc->ss.r9,
                  (uint64_t) mc->ss.r10,
                  (uint64_t) mc->ss.r11);
      fprintf(stderr, "r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n",
                  (uint64_t) mc->ss.r12,
                  (uint64_t) mc->ss.r13,
                  (uint64_t) mc->ss.r14,
                  (uint64_t) mc->ss.r15);
#else
#warning "Unsupported CPU - FIXME"
#endif
#else
#warning "Unsupported OS - FIXME"
#endif
      assert(0);
}

static void
sigio_handler(int sig)
{
      assert(sig == SIGIO);

      // pci_faum_vhdl_interrupt_immediate(); FIXME
      sigs |= 2;
}

static void
sigterm_handler(int sig)
{
      assert(sig == SIGINT
          || sig == SIGQUIT
          || sig == SIGTERM);

      frontend_quit();
}

static void
sigchld_handler(int sig)
{
      assert(sig == SIGCHLD);

      sigs |= 4;
}

#if PROFILING
static void
sigprof_handler(int sig, siginfo_t *si, void *uc)
{
#if defined(LINUX)
      mcontext_t *regs = &((ucontext_t *) uc)->uc_mcontext;
#elif defined(OPENBSD)
      struct sigcontext *regs = (struct sigcontext *) uc;
#else
#warning "Not ported yet - FIXME."
#endif
      int enosave;
      unsigned long eip;

      assert(sig == SIGPROF);

      /*
       * We are in a signal handler. We must ensure
       * that we don't touch global variables like errno!
       */
      enosave = errno;

#if defined(__i386__)
      eip = (unsigned long) regs->gregs[REG_EIP];

      fprintf(stderr, "PROFILE %08lx\n", eip);
#elif defined(__x86_64__)
      eip = (unsigned long) regs->gregs[REG_RIP];

      fprintf(stderr, "PROFILE %016lx\n", eip);
#else
#warning "Not ported yet - FIXME."
#endif

      errno = enosave;
}
#endif /* PROFILING */

static void __attribute__((__noreturn__))
usage(int retval)
{
      fprintf(stderr, "Usage: %s [options] [setup-file]\n", progname);
      fprintf(stderr, "\t-B <dir>: use <dir> as config directory\n");
      fprintf(stderr, "\t-D <level>: set debug level to <level>\n");
      fprintf(stderr, "\t-d: switch on debug output\n");
      fprintf(stderr, "\t-h: show help (this text)\n");
      fprintf(stderr, "\tsetup-file: Use <setup-file> instead of simulation.setup (in current directory)\n");
      fprintf(stderr, "\t            for finding information about the environment.\n");
      gui_usage();

      exit(retval);
}

int
main(int argc, char **argv)
{
      int c;
      struct sigaction sadebug;
      struct sigaction saexception;
      struct sigaction saio;
      struct sigaction saterm;
      struct sigaction sapipe;
      struct sigaction sachld;
#if PROFILING
      struct sigaction saprof;
      struct itimerval it, itold;
#endif
      struct rlimit limit;
      struct process *proc;
      unsigned int i;
      int ret;

#if PROFILING
      fprintf(stderr, "Switch on profiling by sending SIGABRT to pid %d.\n",
                  getpid());
#endif

      gui_handle_args(&argc, &argv);
      /* audio_args(&argc, &argv); */

      /*
       * Get program name.
       */
      if (strchr(*argv, '/')) {
            progname = strrchr(*argv, '/') + 1;
      } else {
            progname = *argv;
      }

      /*
       * Get options.
       */
      while ((c = getopt(argc, argv, "B:D:dhl")) != -1) {
            switch (c) {
            case 'B':
                  basedir = optarg;
                  break;
            case 'D':
                  loglevel = atoi(optarg);
                  break;
            case 'd':
                  loglevel = 1;
                  break;
            case 'h':
                  usage(0);
                  /*NOTREACHED*/
            default:
                  usage(1);
                  /*NOTREACHED*/
            }
      }
      argc -= optind;
      argv += optind;

      /*
       * Get parameters.
       */
      if (0 < argc) {
            simulation_setup_name = *argv;
            argv++;
            argc--;
      }

      /*
       * Check for parameters.
       */
      if (argc != 0) {
            usage(1);
            /*NOTREACHED*/
      }

      ret = mkdir(basedir, 0755);
      assert(0 <= ret || errno == EEXIST);

      /*
       * Read parameters from simulation.setup
       */
      simsetup_init(simulation_setup_name);

      /*
       * Setup signal handlers.
       */
      sadebug.sa_handler = sig_debug;
      sadebug.sa_flags = 0;
      sigfillset(&sadebug.sa_mask);
      ret = sigaction(SIGABRT, &sadebug, NULL);
      assert(0 <= ret);

      saexception.sa_sigaction = sig_exception;
      saexception.sa_flags = SA_SIGINFO;
      sigfillset(&saexception.sa_mask);
      ret = sigaction(SIGFPE, &saexception, NULL);
      assert(0 <= ret);
      ret = sigaction(SIGUSR1, &saexception, NULL);
      assert(0 <= ret);
      ret = sigaction(SIGUSR2, &saexception, NULL);
      assert(0 <= ret);
      ret = sigaction(SIGTRAP, &saexception, NULL);
      assert(0 <= ret);
      ret = sigaction(SIGSEGV, &saexception, NULL);
      assert(0 <= ret);
      ret = sigaction(SIGILL, &saexception, NULL);
      assert(0 <= ret);
      ret = sigaction(SIGBUS, &saexception, NULL);
      assert(0 <= ret);

      saio.sa_handler = sigio_handler;
      saio.sa_flags = SA_RESTART;
      sigemptyset(&saio.sa_mask);
      ret = sigaction(SIGIO, &saio, NULL);
      assert(0 <= ret);

      saterm.sa_handler = sigterm_handler;
      saterm.sa_flags = SA_RESTART;
      sigemptyset(&saterm.sa_mask);
      ret = sigaction(SIGINT, &saterm, NULL);
      assert(0 <= ret);
      ret = sigaction(SIGQUIT, &saterm, NULL);
      assert(0 <= ret);
      ret = sigaction(SIGTERM, &saterm, NULL);
      assert(0 <= ret);

      sapipe.sa_handler = SIG_IGN;
      sapipe.sa_flags = 0;
      sigemptyset(&sapipe.sa_mask);
      ret = sigaction(SIGPIPE, &sapipe, NULL);
      assert(0 <= ret);

      sachld.sa_handler = sigchld_handler;
      sachld.sa_flags = SA_RESTART;
      sigemptyset(&sachld.sa_mask);
      ret = sigaction(SIGCHLD, &sachld, NULL);
      assert(0 <= ret);

#if PROFILING
      saprof.sa_sigaction = sigprof_handler;
      saprof.sa_flags = SA_RESTART | SA_SIGINFO;
      sigemptyset(&saprof.sa_mask);
      ret = sigaction(SIGPROF, &saprof, NULL);
      assert(0 <= ret);

      it.it_interval.tv_sec = 0;
      it.it_interval.tv_usec = 1000000 / 31;
      it.it_value.tv_sec = 0;
      it.it_value.tv_usec = 1000000 / 31;

      ret = setitimer(ITIMER_PROF, &it, &itold);
      assert(0 <= ret);
#endif

      /*
       * Adjust limits for open files.
       */
      ret = getrlimit(RLIMIT_NOFILE, &limit);
      assert(ret == 0);

      if (limit.rlim_cur < limit.rlim_max) {
#ifdef DARWIN
            limit.rlim_cur = OPEN_MAX < limit.rlim_max ? OPEN_MAX : limit.rlim_max;
#else
            limit.rlim_cur = limit.rlim_max;
#endif
            ret = setrlimit(RLIMIT_NOFILE, &limit);
            assert(ret == 0);
      }

      /*
       * Initialize time management.
       */
      schedule_free_first = (struct schedules *) 0;
      schedule_free_last = (struct schedules *) 0;
      for (i = 0; i < NSCHEDULES; i++) {
            struct schedules *entry;

            entry = &schedule[i];

            /* Append entry to free list. */
            entry->prev = schedule_free_last;
            entry->next = (struct schedules *) 0;
            if (entry->prev) {
                  entry->prev->next = entry;
            } else {
                  schedule_free_first = entry;
            }
            schedule_free_last = entry;
      }

      schedule_active_first = (struct schedules *) 0;
      schedule_active_last = (struct schedules *) 0;

      time_host = 0;
      time_guest = 0;
      time_sync = TIME_INTERVAL;

      /*
       * Initialize process management.
       */
      scheduler = &myself;
      current = (struct process *) 0;

      simnodes_read();

      /*
       * Create components.
       */
      faum_log(FAUM_LOG_INFO, progname, "",
            "Initializing virtual hardware, please wait...\n");
      gui_create();
      audio_create(simsetup.desired_audio_module);
      conn_create();

      sync();

      ret = gettimeofday(&time_tv_start, (struct timezone *) 0);
      assert(0 <= ret);

      /*
       * Send "ready" message to faum-expect.
       */
      gui_init();
      audio_init();
      conn_init();

      /*
       * Create Config
       */
      glue_setup_create();

      /*
       * Execute all processes for init.
       */
      for (proc = proc_first; proc; proc = proc->next) {
            sched_to_process(proc);
      }

      /*
       * Main loop.
       */
      for (;;) {
            if (unlikely(sigs)) {
                  /*
                   * Call I/O Callbacks
                   */
                  if (sigs & 1) {
                        sigs &= ~1;
                        break;
                  }
                  if (sigs & 2) {
                        sigs &= ~2;
                        io_do();
                  }
                  if (sigs & 4) {
                        sigs &= ~4;
                        proc_do();
                  }

            } else if (unlikely(time_sync <= time_guest)) {
                  /*
                   * Sync with other nodes/sync with real-time.
                   */
                  signed long long delta;

                  for (proc = proc_first; proc; proc = proc->next) {
                        uint32_t min;

                        if (proc->inst_limit < proc->inst_cnt) {
                              /* Should not happen, but... */
                              min = proc->inst_limit;
                        } else {
                              min = proc->inst_cnt;
                        }

                        proc->inst_offset += min;
                        proc->inst_limit -= min;
                        proc->inst_cnt -= min;
                  }

                  if (unlikely(simsetup.deterministic)) {
                        delta = 0;

                  } else {
                        time_host = time_real();
                        delta = time_host - time_guest;

                        while (unlikely(delta < 0)) {
                              /* We're too fast. */
                              fd_set rfds;
                              fd_set wfds;
                              fd_set efds;
                              struct timeval tv;

                              delta = -delta;

                              /* Delay for delta time ticks. */
                              FD_ZERO(&rfds);
                              FD_ZERO(&wfds);
                              FD_ZERO(&efds);
                              tv.tv_sec = delta / TIME_HZ;
                              tv.tv_usec = (delta % TIME_HZ) * 1000000 / TIME_HZ;
                              ret = select(0, &rfds, &wfds, &efds, &tv);
                              assert(0 <= ret || errno == EINTR);

                              /* Re-calculate delta. */
                              time_host = time_real();
                              delta = time_host - time_guest;
                        }
                  }

                  time_shift = delta / TIME_INTERVAL;
                  if (unlikely(64 <= time_shift)) {
                        time_shift = 63;
                  }

                  time_sync += TIME_INTERVAL;

            } else if (unlikely(schedule_active_first
                  && schedule_active_first->time <= time_guest)) {
                  /*
                   * Execute event procedures.
                   */
                  struct schedules *entry;
                  void (*func)(void *);
                  void *data;

                  entry = schedule_active_first;

                  /* Remember func/data. */
                  func = entry->func;
                  data = entry->data;

                  /* Remove entry from active list. */
                  schedule_active_first = entry->next;
                  if (entry->next) {
                        entry->next->prev = 0;
                  } else {
                        schedule_active_last = 0;
                  }

                  /* Append entry to free list. */
                  entry->prev = schedule_free_last;
                  entry->next = 0;
                  if (entry->prev) {
                        entry->prev->next = entry;
                  } else {
                        schedule_free_first = entry;
                  }
                  schedule_free_last = entry;

                  /* Execute function. */
                  (*func)(data); /* Might change schedule list! */

            } else {
                  /*
                   * Execute CPU processes (if any).
                   */
                  unsigned long long interval;
                  unsigned long long adapted_interval;
                  unsigned long long steps;
                  struct process *proc_next;

                  interval = TIME_INTERVAL / 128;
                  if (time_sync - time_guest < interval) {
                        interval = time_sync - time_guest;
                  }
                  if (schedule_active_first
                   && schedule_active_first->time - time_guest < interval) {
                        interval = schedule_active_first->time - time_guest;
                  }

                  adapted_interval = interval >> time_shift;

                  for (proc = proc_first; proc; proc = proc->next) {
                        steps = proc->inst_hz * adapted_interval / TIME_HZ + 1;

                        proc->inst_limit += steps;
                  }

                  /*
                   * Warning: Process might remove itself from
                   * run-queue!
                   */
                  for (proc = proc_first; proc; proc = proc_next) {
                        proc_next = proc->next;
                        if (proc->inst_cnt < proc->inst_limit) {
                              sched_to_process(proc);
                        }
                  }

                  time_guest += interval;
            }
      }

      glue_setup_destroy();

      conn_exit();
      audio_exit();
      gui_exit();

      /*
       * Destroy components.
       */
      conn_destroy();
      audio_destroy();
      gui_destroy();

      /*
       * Reset profiling.
       */
#if PROFILING
      it.it_interval.tv_sec = 0;
      it.it_interval.tv_usec = 0;
      it.it_value.tv_sec = 0;
      it.it_value.tv_usec = 0;
      ret = setitimer(ITIMER_PROF, &itold, NULL);
      assert(0 <= ret);
#endif

      return failure;
}

Generated by  Doxygen 1.6.0   Back to index