<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "mutex.h"
#include "sandbox_impl.h"

// This is a C++ implementation of trusted_thread.cc.  Since it trusts
// the contents of the stack, it is not secure.  It is intended to be
// a reference implementation.  This code can be used as an aid to
// understanding what the real trusted thread does, since this code
// should be easier to read than assembly code.  It can also be used
// as a test bed for changes to the trusted thread.

namespace playground {

void die(const char *msg) {
  sys_write(2, msg, strlen(msg));
  sys_exit_group(1);
}

#define TO_STRING_1(x) #x
#define TO_STRING(x) TO_STRING_1(x)

#define assert(expr) { \
  if (!(expr)) die("assertion failed at " __FILE__ ":" TO_STRING(__LINE__) \
                   ": " #expr "\n"); }

// Perform a syscall given an array of syscall arguments.
extern "C" long DoSyscall(long regs[7]);
asm(
    ".pushsection .text, \"ax\", @progbits\n"
    ".global DoSyscall\n"
    "DoSyscall:\n"
#if defined(__x86_64__)
    "push %rdi\n"
    "push %rsi\n"
    "push %rdx\n"
    "push %r10\n"
    "push %r8\n"
    "push %r9\n"
    // Set up syscall arguments
    "mov 0x00(%rdi), %rax\n"
    // Skip 0x08 (%rdi): this comes last
    "mov 0x10(%rdi), %rsi\n"
    "mov 0x18(%rdi), %rdx\n"
    "mov 0x20(%rdi), %r10\n"
    "mov 0x28(%rdi), %r8\n"
    "mov 0x30(%rdi), %r9\n"
    "mov 0x08(%rdi), %rdi\n"
    "syscall\n"
    "pop %r9\n"
    "pop %r8\n"
    "pop %r10\n"
    "pop %rdx\n"
    "pop %rsi\n"
    "pop %rdi\n"
    "ret\n"
#elif defined(__i386__)
    "push %ebx\n"
    "push %ecx\n"
    "push %edx\n"
    "push %esi\n"
    "push %edi\n"
    "push %ebp\n"
    "mov 4+24(%esp), %ecx\n"
    // Set up syscall arguments
    "mov 0x00(%ecx), %eax\n"
    "mov 0x04(%ecx), %ebx\n"
    // Skip 0x08 (%ecx): this comes last
    "mov 0x0c(%ecx), %edx\n"
    "mov 0x10(%ecx), %esi\n"
    "mov 0x14(%ecx), %edi\n"
    "mov 0x18(%ecx), %ebp\n"
    "mov 0x08(%ecx), %ecx\n"
    "int $0x80\n"
    "pop %ebp\n"
    "pop %edi\n"
    "pop %esi\n"
    "pop %edx\n"
    "pop %ecx\n"
    "pop %ebx\n"
    "ret\n"
#else
#error Unsupported target platform
#endif
    ".popsection\n"
    );

void ReturnFromCloneSyscall(SecureMem::Args *secureMem) {
  // TODO(mseaborn): Call sigreturn() to unblock signals.
#if defined(__x86_64__)
  // Get stack argument that was passed to clone().
  void **stack = (void**) secureMem->rsi;
  // Account for the x86-64 red zone adjustment that our syscall
  // interceptor does when returning from the system call.
  stack = (void**) ((char*) stack - 128);
  *--stack = secureMem->ret;
  *--stack = secureMem->r15;
  *--stack = secureMem->r14;
  *--stack = secureMem->r13;
  *--stack = secureMem->r12;
  *--stack = secureMem->r11;
  *--stack = secureMem->r10;
  *--stack = secureMem->r9;
  *--stack = secureMem->r8;
  *--stack = secureMem->rdi;
  *--stack = secureMem->rsi;
  *--stack = secureMem->rdx;
  *--stack = secureMem->rcx;
  *--stack = secureMem->rbx;
  *--stack = secureMem->rbp;
  asm("mov %0, %%rsp\n"
      "pop %%rbp\n"
      "pop %%rbx\n"
      "pop %%rcx\n"
      "pop %%rdx\n"
      "pop %%rsi\n"
      "pop %%rdi\n"
      "pop %%r8\n"
      "pop %%r9\n"
      "pop %%r10\n"
      "pop %%r11\n"
      "pop %%r12\n"
      "pop %%r13\n"
      "pop %%r14\n"
      "pop %%r15\n"
      "mov $0, %%rax\n"
      "ret\n"
      : : "m"(stack));
#elif defined(__i386__)
  // Get stack argument that was passed to clone().
  void **stack = (void**) secureMem->ecx;
  *--stack = secureMem->ret;
  *--stack = secureMem->ebp;
  *--stack = secureMem->edi;
  *--stack = secureMem->esi;
  *--stack = secureMem->edx;
  *--stack = secureMem->ecx;
  *--stack = secureMem->ebx;
  asm("mov %0, %%esp\n"
      "pop %%ebx\n"
      "pop %%ecx\n"
      "pop %%edx\n"
      "pop %%esi\n"
      "pop %%edi\n"
      "pop %%ebp\n"
      "mov $0, %%eax\n"
      "ret\n"
      : : "m"(stack));
#else
#error Unsupported target platform
#endif
}

void InitCustomTLS(void *addr) {
  Sandbox::SysCalls sys;
#if defined(__x86_64__)
  int rc = sys.arch_prctl(ARCH_SET_GS, addr);
  assert(rc == 0);
#elif defined(__i386__)
  struct user_desc u;
  u.entry_number    = (typeof u.entry_number)-1;
  u.base_addr       = (long) addr;
  u.limit           = 0xfffff;
  u.seg_32bit       = 1;
  u.contents        = 0;
  u.read_exec_only  = 0;
  u.limit_in_pages  = 1;
  u.seg_not_present = 0;
  u.useable         = 1;
  int rc = sys.set_thread_area(&u);
  assert(rc == 0);
  asm volatile("movw %w0, %%fs"
               : : "q"(8 * u.entry_number + 3));
#else
#error Unsupported target platform
#endif
}

void UnlockSyscallMutex() {
  Sandbox::SysCalls sys;
  // TODO(mseaborn): Use clone() to be the same as trusted_thread.cc.
  int pid = sys.fork();
  assert(pid >= 0);
  if (pid == 0) {
    int rc = sys.mprotect(&Sandbox::syscall_mutex_, 0x1000,
                          PROT_READ | PROT_WRITE);
    assert(rc == 0);
    Mutex::unlockMutex(&Sandbox::syscall_mutex_);
    sys._exit(0);
  }
  int status;
  int rc = sys.waitpid(pid, &status, 0);
  assert(rc == pid);
  assert(status == 0);
}

// Allocate a stack that is never freed.
char *AllocateStack() {
  Sandbox::SysCalls sys;
  int stack_size = 0x1000;
#if defined(__i386__)
  void *stack = sys.mmap2(NULL, stack_size, PROT_READ | PROT_WRITE,
                          MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
#else
  void *stack = sys.mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
                         MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
#endif
  assert(stack != MAP_FAILED);
  return (char *) stack + stack_size;
}

int HandleNewThread(void *arg) {
  SecureMem::Args *secureMem = (SecureMem::Args *) arg;
  CreateReferenceTrustedThread(secureMem->newSecureMem);
  ReturnFromCloneSyscall(secureMem);
  return 0;
}

struct ThreadArgs {
  SecureMem::Args *secureMem;
  int threadFd;
};

int TrustedThread(void *arg) {
  struct ThreadArgs *args = (struct ThreadArgs *) arg;
  SecureMem::Args *secureMem = args->secureMem;
  int fd = args->threadFd;
  Sandbox::SysCalls sys;

  int sequence_no = 2;
  while (1) {
    long syscall_args[7];
    memset(syscall_args, 0, sizeof(syscall_args));
    int got = sys.read(fd, syscall_args, 4);
    assert(got == 4);

    long syscall_result;
    int sysnum = syscall_args[0];
    if (sysnum == -1 || sysnum == -2) {
      // Syscall where the registers have been checked by the trusted
      // process, e.g. munmap() ranges must be OK.
      // Doesn't need extra memory region.
      assert(secureMem->sequence == sequence_no);
      sequence_no += 2;
      if (secureMem->syscallNum == __NR_exit) {
        int rc = sys.close(fd);
        assert(rc == 0);
        rc = sys.close(secureMem->threadFdPub);
        assert(rc == 0);
      }
      else if (secureMem->syscallNum == __NR_clone) {
        assert(sysnum == -2);
        // Note that HandleNewThread() does UnlockSyscallMutex() for us.
#if defined(__x86_64__)
        long clone_flags = (long) secureMem->rdi;
        int *pid_ptr = (int *) secureMem->rdx;
        int *tid_ptr = (int *) secureMem->r10;
        void *tls_info = secureMem->r8;
#elif defined(__i386__)
        long clone_flags = (long) secureMem->ebx;
        int *pid_ptr = (int *) secureMem->edx;
        void *tls_info = secureMem->esi;
        int *tid_ptr = (int *) secureMem->edi;
#else
#error Unsupported target platform
#endif
        syscall_result = sys.clone(HandleNewThread, (void *) AllocateStack(),
                                   clone_flags, (void *) secureMem,
                                   pid_ptr, tls_info, tid_ptr);
        assert(syscall_result > 0);
        int sent = sys.write(fd, &syscall_result, sizeof(syscall_result));
        assert(sent == sizeof(syscall_result));
        continue;
      }
      memcpy(syscall_args, &secureMem->syscallNum, sizeof(syscall_args));
      // We release the mutex before doing the syscall, because we
      // have now copied the arguments.
      if (sysnum == -2)
        UnlockSyscallMutex();
    }
    else if (sysnum == -3) {
      // RDTSC request.  Send back a dummy answer.
      int timestamp[2] = {0, 0};
      int sent = sys.write(fd, (char *) timestamp, sizeof(timestamp));
      assert(sent == 8);
      continue;
    }
    else {
      int rest_size = sizeof(syscall_args) - sizeof(long);
      got = sys.read(fd, &syscall_args[1], rest_size);
      assert(got == rest_size);
    }
    syscall_result = DoSyscall(syscall_args);
    int sent = sys.write(fd, &syscall_result, sizeof(syscall_result));
    assert(sent == sizeof(syscall_result));
  }
  return 0;
}

void CreateReferenceTrustedThread(SecureMem::Args *secureMem) {
  // We are in the nascent thread.
  Sandbox::SysCalls sys;

  int socks[2];
  int rc = sys.socketpair(AF_UNIX, SOCK_STREAM, 0, socks);
  assert(rc == 0);
  int threadFdPub = socks[0];
  int threadFd = socks[1];

  // Create trusted thread.
  // We omit CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID.
  int flags = CLONE_VM | CLONE_FS | CLONE_FILES |
    CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM;
  // Assumes that the stack grows down.
  char *stack_top = AllocateStack() - sizeof(struct ThreadArgs);
  struct ThreadArgs *thread_args = (struct ThreadArgs *) stack_top;
  thread_args->threadFd = threadFd;
  thread_args->secureMem = secureMem;
  rc = sys.clone(TrustedThread, stack_top, flags, thread_args,
                 NULL, NULL, NULL);
  assert(rc > 0);

  // Make the thread state pages usable.
  rc = sys.mprotect(secureMem, 0x1000, PROT_READ);
  assert(rc == 0);
  rc = sys.mprotect(((char *) secureMem) + 0x1000, 0x1000,
                    PROT_READ | PROT_WRITE);
  assert(rc == 0);

  // Using cookie as the start is a little odd because other code in
  // syscall.c works around this when addressing from %fs.
  void *tls = (void*) &secureMem->cookie;
  InitCustomTLS(tls);

  UnlockSyscallMutex();

  int tid = sys.gettid();
  assert(tid > 0);

  // Send the socket FDs to the trusted process.
  // TODO(mseaborn): Don't duplicate this struct in trusted_process.cc
  struct {
    SecureMem::Args* self;
    int              tid;
    int              fdPub;
  } __attribute__((packed)) data;
  data.self = secureMem;
  data.tid = tid;
  data.fdPub = threadFdPub;
  bool ok = Sandbox::sendFd(Sandbox::cloneFdPub_, threadFdPub, threadFd,
                            (void *) &data, sizeof(data));
  assert(ok);

  // Wait for the trusted process to fill out the thread state for us.
  char byte_message;
  int got = sys.read(threadFdPub, &byte_message, 1);
  assert(got == 1);
  assert(byte_message == 0);

  // Switch to seccomp mode.
  rc = sys.prctl(PR_SET_SECCOMP, 1);
  assert(rc == 0);
}

}
<commit_msg>Bring reference_trusted_thread.cc into line with real implementation<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "mutex.h"
#include "sandbox_impl.h"

// This is a C++ implementation of trusted_thread.cc.  Since it trusts
// the contents of the stack, it is not secure.  It is intended to be
// a reference implementation.  This code can be used as an aid to
// understanding what the real trusted thread does, since this code
// should be easier to read than assembly code.  It can also be used
// as a test bed for changes to the trusted thread.

namespace playground {

void die(const char *msg) {
  sys_write(2, msg, strlen(msg));
  sys_exit_group(1);
}

#define TO_STRING_1(x) #x
#define TO_STRING(x) TO_STRING_1(x)

#define assert(expr) { \
  if (!(expr)) die("assertion failed at " __FILE__ ":" TO_STRING(__LINE__) \
                   ": " #expr "\n"); }

// Perform a syscall given an array of syscall arguments.
extern "C" long DoSyscall(long regs[7]);
asm(
    ".pushsection .text, \"ax\", @progbits\n"
    ".global DoSyscall\n"
    "DoSyscall:\n"
#if defined(__x86_64__)
    "push %rdi\n"
    "push %rsi\n"
    "push %rdx\n"
    "push %r10\n"
    "push %r8\n"
    "push %r9\n"
    // Set up syscall arguments
    "mov 0x00(%rdi), %rax\n"
    // Skip 0x08 (%rdi): this comes last
    "mov 0x10(%rdi), %rsi\n"
    "mov 0x18(%rdi), %rdx\n"
    "mov 0x20(%rdi), %r10\n"
    "mov 0x28(%rdi), %r8\n"
    "mov 0x30(%rdi), %r9\n"
    "mov 0x08(%rdi), %rdi\n"
    "syscall\n"
    "pop %r9\n"
    "pop %r8\n"
    "pop %r10\n"
    "pop %rdx\n"
    "pop %rsi\n"
    "pop %rdi\n"
    "ret\n"
#elif defined(__i386__)
    "push %ebx\n"
    "push %ecx\n"
    "push %edx\n"
    "push %esi\n"
    "push %edi\n"
    "push %ebp\n"
    "mov 4+24(%esp), %ecx\n"
    // Set up syscall arguments
    "mov 0x00(%ecx), %eax\n"
    "mov 0x04(%ecx), %ebx\n"
    // Skip 0x08 (%ecx): this comes last
    "mov 0x0c(%ecx), %edx\n"
    "mov 0x10(%ecx), %esi\n"
    "mov 0x14(%ecx), %edi\n"
    "mov 0x18(%ecx), %ebp\n"
    "mov 0x08(%ecx), %ecx\n"
    "int $0x80\n"
    "pop %ebp\n"
    "pop %edi\n"
    "pop %esi\n"
    "pop %edx\n"
    "pop %ecx\n"
    "pop %ebx\n"
    "ret\n"
#else
#error Unsupported target platform
#endif
    ".popsection\n"
    );

void ReturnFromCloneSyscall(SecureMem::Args *secureMem) {
  // TODO(mseaborn): Call sigreturn() to unblock signals.
#if defined(__x86_64__)
  // Get stack argument that was passed to clone().
  void **stack = (void**) secureMem->rsi;
  // Account for the x86-64 red zone adjustment that our syscall
  // interceptor does when returning from the system call.
  stack = (void**) ((char*) stack - 128);
  *--stack = secureMem->ret;
  *--stack = secureMem->r15;
  *--stack = secureMem->r14;
  *--stack = secureMem->r13;
  *--stack = secureMem->r12;
  *--stack = secureMem->r11;
  *--stack = secureMem->r10;
  *--stack = secureMem->r9;
  *--stack = secureMem->r8;
  *--stack = secureMem->rdi;
  *--stack = secureMem->rsi;
  *--stack = secureMem->rdx;
  *--stack = secureMem->rcx;
  *--stack = secureMem->rbx;
  *--stack = secureMem->rbp;
  asm("mov %0, %%rsp\n"
      "pop %%rbp\n"
      "pop %%rbx\n"
      "pop %%rcx\n"
      "pop %%rdx\n"
      "pop %%rsi\n"
      "pop %%rdi\n"
      "pop %%r8\n"
      "pop %%r9\n"
      "pop %%r10\n"
      "pop %%r11\n"
      "pop %%r12\n"
      "pop %%r13\n"
      "pop %%r14\n"
      "pop %%r15\n"
      "mov $0, %%rax\n"
      "ret\n"
      : : "m"(stack));
#elif defined(__i386__)
  // Get stack argument that was passed to clone().
  void **stack = (void**) secureMem->ecx;
  *--stack = secureMem->ret;
  *--stack = secureMem->ebp;
  *--stack = secureMem->edi;
  *--stack = secureMem->esi;
  *--stack = secureMem->edx;
  *--stack = secureMem->ecx;
  *--stack = secureMem->ebx;
  asm("mov %0, %%esp\n"
      "pop %%ebx\n"
      "pop %%ecx\n"
      "pop %%edx\n"
      "pop %%esi\n"
      "pop %%edi\n"
      "pop %%ebp\n"
      "mov $0, %%eax\n"
      "ret\n"
      : : "m"(stack));
#else
#error Unsupported target platform
#endif
}

void InitCustomTLS(void *addr) {
  Sandbox::SysCalls sys;
#if defined(__x86_64__)
  int rc = sys.arch_prctl(ARCH_SET_GS, addr);
  assert(rc == 0);
#elif defined(__i386__)
  struct user_desc u;
  u.entry_number    = (typeof u.entry_number)-1;
  u.base_addr       = (long) addr;
  u.limit           = 0xfffff;
  u.seg_32bit       = 1;
  u.contents        = 0;
  u.read_exec_only  = 0;
  u.limit_in_pages  = 1;
  u.seg_not_present = 0;
  u.useable         = 1;
  int rc = sys.set_thread_area(&u);
  assert(rc == 0);
  asm volatile("movw %w0, %%fs"
               : : "q"(8 * u.entry_number + 3));
#else
#error Unsupported target platform
#endif
}

void UnlockSyscallMutex() {
  Sandbox::SysCalls sys;
  // TODO(mseaborn): Use clone() to be the same as trusted_thread.cc.
  int pid = sys.fork();
  assert(pid >= 0);
  if (pid == 0) {
    int rc = sys.mprotect(&Sandbox::syscall_mutex_, 0x1000,
                          PROT_READ | PROT_WRITE);
    assert(rc == 0);
    Mutex::unlockMutex(&Sandbox::syscall_mutex_);
    sys._exit(0);
  }
  int status;
  int rc = sys.waitpid(pid, &status, 0);
  assert(rc == pid);
  assert(status == 0);
}

// Allocate a stack that is never freed.
char *AllocateStack() {
  Sandbox::SysCalls sys;
  int stack_size = 0x1000;
#if defined(__i386__)
  void *stack = sys.mmap2(NULL, stack_size, PROT_READ | PROT_WRITE,
                          MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
#else
  void *stack = sys.mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
                         MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
#endif
  assert(stack != MAP_FAILED);
  return (char *) stack + stack_size;
}

int HandleNewThread(void *arg) {
  SecureMem::Args *secureMem = (SecureMem::Args *) arg;
  CreateReferenceTrustedThread(secureMem->newSecureMem);
  ReturnFromCloneSyscall(secureMem);
  return 0;
}

struct ThreadArgs {
  SecureMem::Args *secureMem;
  int threadFd;
};

int TrustedThread(void *arg) {
  struct ThreadArgs *args = (struct ThreadArgs *) arg;
  SecureMem::Args *secureMem = args->secureMem;
  int fd = args->threadFd;
  Sandbox::SysCalls sys;

  int sequence_no = 2;
  while (1) {
    long syscall_args[7];
    memset(syscall_args, 0, sizeof(syscall_args));
    int got = sys.read(fd, syscall_args, 4);
    assert(got == 4);

    long syscall_result;
    int sysnum = syscall_args[0];
    if (sysnum == -1 || sysnum == -2) {
      // Syscall where the registers have been checked by the trusted
      // process, e.g. munmap() ranges must be OK.
      // Doesn't need extra memory region.
      assert(secureMem->sequence == sequence_no);
      sequence_no += 2;
      if (secureMem->syscallNum == __NR_exit) {
        assert(sysnum == -2);
        int rc = sys.close(fd);
        assert(rc == 0);
        rc = sys.close(secureMem->threadFdPub);
        assert(rc == 0);
        // Make the thread's memory area inaccessible as a sanity check.
        rc = sys.mprotect(secureMem, 0x2000, PROT_NONE);
        assert(rc == 0);
        // Although the thread exit syscall does not read from the
        // secure memory area, we use the mutex for it to ensure that
        // the trusted process and trusted thread are synchronised.
        // We do not want the trusted process to think that the
        // thread's memory area has been freed while the trusted
        // thread is still reading from it.
        UnlockSyscallMutex();
        // Fall through to exit the thread.
      }
      else if (secureMem->syscallNum == __NR_clone) {
        assert(sysnum == -2);
        // Note that HandleNewThread() does UnlockSyscallMutex() for us.
#if defined(__x86_64__)
        long clone_flags = (long) secureMem->rdi;
        int *pid_ptr = (int *) secureMem->rdx;
        int *tid_ptr = (int *) secureMem->r10;
        void *tls_info = secureMem->r8;
#elif defined(__i386__)
        long clone_flags = (long) secureMem->ebx;
        int *pid_ptr = (int *) secureMem->edx;
        void *tls_info = secureMem->esi;
        int *tid_ptr = (int *) secureMem->edi;
#else
#error Unsupported target platform
#endif
        syscall_result = sys.clone(HandleNewThread, (void *) AllocateStack(),
                                   clone_flags, (void *) secureMem,
                                   pid_ptr, tls_info, tid_ptr);
        assert(syscall_result > 0);
        int sent = sys.write(fd, &syscall_result, sizeof(syscall_result));
        assert(sent == sizeof(syscall_result));
        continue;
      }
      memcpy(syscall_args, &secureMem->syscallNum, sizeof(syscall_args));
    }
    else if (sysnum == -3) {
      // RDTSC request.  Send back a dummy answer.
      int timestamp[2] = {0, 0};
      int sent = sys.write(fd, (char *) timestamp, sizeof(timestamp));
      assert(sent == 8);
      continue;
    }
    else {
      int rest_size = sizeof(syscall_args) - sizeof(long);
      got = sys.read(fd, &syscall_args[1], rest_size);
      assert(got == rest_size);
    }
    syscall_result = DoSyscall(syscall_args);
    if (sysnum == -2) {
      // This syscall involves reading from the secure memory area for
      // the thread.  We should only unlock this area when the syscall
      // has completed.  Otherwise, the trusted process might
      // overwrite the data while the kernel is still reading it.
      UnlockSyscallMutex();
    }
    int sent = sys.write(fd, &syscall_result, sizeof(syscall_result));
    assert(sent == sizeof(syscall_result));
  }
  return 0;
}

void CreateReferenceTrustedThread(SecureMem::Args *secureMem) {
  // We are in the nascent thread.
  Sandbox::SysCalls sys;

  int socks[2];
  int rc = sys.socketpair(AF_UNIX, SOCK_STREAM, 0, socks);
  assert(rc == 0);
  int threadFdPub = socks[0];
  int threadFd = socks[1];

  // Create trusted thread.
  // We omit CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID.
  int flags = CLONE_VM | CLONE_FS | CLONE_FILES |
    CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM;
  // Assumes that the stack grows down.
  char *stack_top = AllocateStack() - sizeof(struct ThreadArgs);
  struct ThreadArgs *thread_args = (struct ThreadArgs *) stack_top;
  thread_args->threadFd = threadFd;
  thread_args->secureMem = secureMem;
  rc = sys.clone(TrustedThread, stack_top, flags, thread_args,
                 NULL, NULL, NULL);
  assert(rc > 0);

  // Make the thread state pages usable.
  rc = sys.mprotect(secureMem, 0x1000, PROT_READ);
  assert(rc == 0);
  rc = sys.mprotect(((char *) secureMem) + 0x1000, 0x1000,
                    PROT_READ | PROT_WRITE);
  assert(rc == 0);

  // Using cookie as the start is a little odd because other code in
  // syscall.c works around this when addressing from %fs.
  void *tls = (void*) &secureMem->cookie;
  InitCustomTLS(tls);

  UnlockSyscallMutex();

  int tid = sys.gettid();
  assert(tid > 0);

  // Send the socket FDs to the trusted process.
  // TODO(mseaborn): Don't duplicate this struct in trusted_process.cc
  struct {
    SecureMem::Args* self;
    int              tid;
    int              fdPub;
  } __attribute__((packed)) data;
  data.self = secureMem;
  data.tid = tid;
  data.fdPub = threadFdPub;
  bool ok = Sandbox::sendFd(Sandbox::cloneFdPub_, threadFdPub, threadFd,
                            (void *) &data, sizeof(data));
  assert(ok);

  // Wait for the trusted process to fill out the thread state for us.
  char byte_message;
  int got = sys.read(threadFdPub, &byte_message, 1);
  assert(got == 1);
  assert(byte_message == 0);

  // Switch to seccomp mode.
  rc = sys.prctl(PR_SET_SECCOMP, 1);
  assert(rc == 0);
}

}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/phy/seq.C $     */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file seq.C
/// @brief Subroutines for the PHY SEQ registers
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <lib/phy/seq.H>
#include <lib/utils/scom.H>
#include <lib/utils/c_str.H>
#include <lib/utils/bit_count.H>
#include <lib/eff_config/timing.H>

using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_DIMM;

namespace mss
{

namespace seq
{

///
/// @brief PHY SEQ register exponent helper
/// PHY SEQ fields is used as exponent of 2, to calculate the number of MEMINTCLKO clock cycles.
/// For example, if TMOD_CYCLES[0:3] = 5, the internal timers use the value 2^5 = 32 MEMINTCLKO
/// clock cycles. The maximum value per nibble is ‘A’h. This helper takes a calculated value and returns
/// the 'best' exponent.
/// @param[in] i_value a value for which to make an exponent
/// @return uint64_t right-aligned value to stick in the field
///
uint64_t exp_helper( const uint64_t i_value )
{
    // PHY exponents don't make much sense above this value so we short circuit if possible.
    constexpr uint64_t MAX_EXP = 0xA;

    if (i_value >= (1 << MAX_EXP))
    {
        return 0xA;
    }

    // If the user passes in 0, let it past.
    if (i_value == 0)
    {
        return 0;
    }

    // Find the first bit set. The subtraction from 63 switches from a left-count to a right-count (e.g., 0 (left most
    // bit) is really bit 63 if you start on the right.)
    const uint64_t l_first_bit = 63 - first_bit_set(i_value);

    // If the input is greater than 2^first bit, add one to the first_bit so 2^first_bit >= input
    // (round up)
    return l_first_bit + (uint64_t(1 << l_first_bit) < i_value ? 1 : 0);
}

///
/// @brief reset SEQ_TIMING0
/// @param[in] i_target fapi2 target of the port
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
///
template<>
fapi2::ReturnCode reset_timing0( const fapi2::Target<TARGET_TYPE_MCA>& i_target )
{
    typedef seqTraits<TARGET_TYPE_MCA> TT;
    fapi2::buffer<uint64_t> l_data;

    // Table 5-324. SEQ Memory Timing Parameter 0 Register Bit Definition
    // TMOD_CYCLES max(tMRD, tMOD)
    // TRCD_CYCLES tRCD
    // TRP_CYCLES  tRP
    // TRFC_CYCLES tRFC

    uint64_t l_tmod_cycles = 0;
    uint8_t l_trcd = 0;
    uint8_t l_trp = 0;
    uint16_t l_trfc_max = 0;

    l_tmod_cycles = exp_helper( std::max(mss::tmrd(), mss::tmod(i_target)) );
    l_data.insertFromRight<TT::TMOD_CYCLES, TT::TMOD_CYCLES_LEN>(l_tmod_cycles);

    FAPI_TRY( mss::eff_dram_trcd(i_target, l_trcd) );
    l_data.insertFromRight<TT::TRCD_CYCLES, TT::TRCD_CYCLES_LEN>( exp_helper(l_trcd) );

    FAPI_TRY( mss::eff_dram_trp(i_target, l_trp) );
    l_data.insertFromRight<TT::TRP_CYCLES, TT::TRP_CYCLES_LEN>( exp_helper(l_trp) );

    // It's not really clear what to put here. We can have DIMM with different tRFC as they
    // don't have to be the same (3DS v. SPD for example.) So we'll take the maximum trfc we
    // find on the DIMM connected to this port.
    for (const auto& d : mss::find_targets<TARGET_TYPE_DIMM>(i_target))
    {
        uint16_t l_trfc = 0;
        FAPI_TRY( mss::trfc(d, l_trfc) );
        l_trfc_max = std::max(l_trfc_max, l_trfc);
    }

    l_data.insertFromRight<TT::TRFC_CYCLES, TT::TRFC_CYCLES_LEN>( exp_helper(l_trfc_max) );

    FAPI_TRY( mss::putScom(i_target, TT::SEQ_TIMING0_REG, l_data) );

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief reset SEQ_TIMING1
/// @param[in] i_target fapi2 target of the port
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
///
template<>
fapi2::ReturnCode reset_timing1( const fapi2::Target<TARGET_TYPE_MCA>& i_target )
{
    typedef seqTraits<TARGET_TYPE_MCA> TT;
    fapi2::buffer<uint64_t> l_data;

    // Table 5-325. SEQ Memory Timing Parameter 1 Register
    // TZQINIT_CYCLES  max(tZQINIT,tZQOPER)
    // TZQCS_CYCLES  tZQCS
    // TWLDQSEN_CYCLES tWLDQSEN
    // TWRMRD_CYCLES tWLMRD

    uint64_t l_tzqint = std::max( mss::tzqinit(), mss::tzqoper() );
    l_data.insertFromRight<TT::TZQINIT_CYCLES, TT::TZQINIT_CYCLES_LEN>( exp_helper(l_tzqint) );
    l_data.insertFromRight<TT::TZQCS_CYCLES, TT::TZQCS_CYCLES_LEN>( exp_helper(mss::tzqcs()) );
    l_data.insertFromRight<TT::TWLDQSEN_CYCLES, TT::TWLDQSEN_CYCLES_LEN>( exp_helper(mss::twldqsen()) );
    l_data.insertFromRight<TT::TWRMRD_CYCLES, TT::TWRMRD_CYCLES_LEN>( exp_helper(mss::twlmrd()) );

    return mss::putScom(i_target, TT::SEQ_TIMING1_REG, l_data);
}

///
/// @brief reset SEQ_TIMING2
/// @param[in] i_target fapi2 target of the port
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
///
template<>
fapi2::ReturnCode reset_timing2( const fapi2::Target<TARGET_TYPE_MCA>& i_target )
{
    typedef seqTraits<TARGET_TYPE_MCA> TT;

    // Reset value of SEQ_TIMING2 is lucky 7's - we'll fix up the first nibble with ODT info
    fapi2::buffer<uint64_t> l_data(0x7777);

    // Table 5-327. SEQ Memory Timing Parameter 2 Register
    // TODTLON_OFF_CYCLES max(ODTLon, ODTLoff)
    uint8_t l_odtlon = 0;
    uint8_t l_odtloff = 0;
    uint64_t l_odt = 0;
    FAPI_TRY( mss::max_dodt_on(i_target, l_odtlon) );
    FAPI_TRY( mss::max_dodt_off(i_target, l_odtloff) );

    l_odt = std::max( l_odtlon, l_odtloff );
    l_data.insertFromRight<TT::TODTLON_OFF_CYCLES, TT::TODTLON_OFF_CYCLES_LEN>( exp_helper(l_odt) );

    FAPI_TRY( mss::putScom(i_target, TT::SEQ_TIMING2_REG, l_data) );

fapi_try_exit:
    return fapi2::current_err;
}

} // close namespace seq
} // close namespace mss
<commit_msg>Fixed CL and timing bugs, unit test augmentations<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/phy/seq.C $     */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file seq.C
/// @brief Subroutines for the PHY SEQ registers
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <lib/phy/seq.H>
#include <lib/utils/scom.H>
#include <lib/utils/c_str.H>
#include <lib/utils/bit_count.H>
#include <lib/eff_config/timing.H>

using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_DIMM;

namespace mss
{

namespace seq
{

///
/// @brief PHY SEQ register exponent helper
/// PHY SEQ fields is used as exponent of 2, to calculate the number of MEMINTCLKO clock cycles.
/// For example, if TMOD_CYCLES[0:3] = 5, the internal timers use the value 2^5 = 32 MEMINTCLKO
/// clock cycles. The maximum value per nibble is ‘A’h. This helper takes a calculated value and returns
/// the 'best' exponent.
/// @param[in] i_value a value for which to make an exponent
/// @return uint64_t right-aligned value to stick in the field
///
uint64_t exp_helper( const uint64_t i_value )
{
    // PHY exponents don't make much sense above this value so we short circuit if possible.
    constexpr uint64_t MAX_EXP = 0xA;

    if (i_value >= (1 << MAX_EXP))
    {
        return 0xA;
    }

    // If the user passes in 0, let it past.
    if (i_value == 0)
    {
        return 0;
    }

    // Find the first bit set. The subtraction from 63 switches from a left-count to a right-count (e.g., 0 (left most
    // bit) is really bit 63 if you start on the right.)
    const uint64_t l_first_bit = 63 - first_bit_set(i_value);

    // If the input is greater than 2^first bit, add one to the first_bit so 2^first_bit >= input
    // (round up)
    return l_first_bit + (uint64_t(1 << l_first_bit) < i_value ? 1 : 0);
}

///
/// @brief reset SEQ_TIMING0
/// @param[in] i_target fapi2 target of the port
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
///
template<>
fapi2::ReturnCode reset_timing0( const fapi2::Target<TARGET_TYPE_MCA>& i_target )
{
    typedef seqTraits<TARGET_TYPE_MCA> TT;
    fapi2::buffer<uint64_t> l_data;

    // Table 5-324. SEQ Memory Timing Parameter 0 Register Bit Definition
    // TMOD_CYCLES max(tMRD, tMOD)
    // TRCD_CYCLES tRCD
    // TRP_CYCLES  tRP
    // TRFC_CYCLES tRFC

    uint64_t l_tmod_cycles = 0;
    uint8_t l_trcd = 0;
    uint8_t l_trp = 0;
    uint16_t l_trfc_max = 0;

    l_tmod_cycles = exp_helper( std::max(mss::tmrd(), mss::tmod(i_target)) );
    l_data.insertFromRight<TT::TMOD_CYCLES, TT::TMOD_CYCLES_LEN>(l_tmod_cycles);

    FAPI_TRY( mss::eff_dram_trcd(i_target, l_trcd) );
    l_data.insertFromRight<TT::TRCD_CYCLES, TT::TRCD_CYCLES_LEN>( exp_helper(l_trcd) );

    FAPI_TRY( mss::eff_dram_trp(i_target, l_trp) );
    l_data.insertFromRight<TT::TRP_CYCLES, TT::TRP_CYCLES_LEN>( exp_helper(l_trp) );

    // It's not really clear what to put here. We can have DIMM with different tRFC as they
    // don't have to be the same (3DS v. SDP for example.) So we'll take the maximum trfc we
    // find on the DIMM connected to this port.
    for (const auto& d : mss::find_targets<TARGET_TYPE_DIMM>(i_target))
    {
        // tRFC is for non-3DS, tRFC_slr for 3DS is to the same logical rank,
        // and tRFC_dlr is to different logical ranks. Unclear which to use.
        uint16_t l_trfc = 0;
        uint8_t l_trfc_dlr = 0;

        // tRFC (or tRFC_slr) will retrieve a value for 3DS or non-3DS
        // tRFC_dlr is only set for 3DS (should be 0 otherwise)
        // so we opt to take the more aggressive timing,
        // means less chance of data being corrupted
        FAPI_TRY( mss::eff_dram_trfc(d, l_trfc) );
        FAPI_TRY( mss::eff_dram_trfc_dlr(d, l_trfc_dlr) );

        {
            // cast needed for template deduction of std::max()
            // HB doesn't support using std::min() with initializer lists
            const uint16_t l_trfc_3ds_min = std::min(l_trfc, static_cast<uint16_t>(l_trfc_dlr));
            l_trfc_max = std::min( l_trfc_3ds_min, l_trfc_max);
        }
    }

    l_data.insertFromRight<TT::TRFC_CYCLES, TT::TRFC_CYCLES_LEN>( exp_helper(l_trfc_max) );

    FAPI_TRY( mss::putScom(i_target, TT::SEQ_TIMING0_REG, l_data) );

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief reset SEQ_TIMING1
/// @param[in] i_target fapi2 target of the port
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
///
template<>
fapi2::ReturnCode reset_timing1( const fapi2::Target<TARGET_TYPE_MCA>& i_target )
{
    typedef seqTraits<TARGET_TYPE_MCA> TT;
    fapi2::buffer<uint64_t> l_data;

    // Table 5-325. SEQ Memory Timing Parameter 1 Register
    // TZQINIT_CYCLES  max(tZQINIT,tZQOPER)
    // TZQCS_CYCLES  tZQCS
    // TWLDQSEN_CYCLES tWLDQSEN
    // TWRMRD_CYCLES tWLMRD

    uint64_t l_tzqint = std::max( mss::tzqinit(), mss::tzqoper() );
    l_data.insertFromRight<TT::TZQINIT_CYCLES, TT::TZQINIT_CYCLES_LEN>( exp_helper(l_tzqint) );
    l_data.insertFromRight<TT::TZQCS_CYCLES, TT::TZQCS_CYCLES_LEN>( exp_helper(mss::tzqcs()) );
    l_data.insertFromRight<TT::TWLDQSEN_CYCLES, TT::TWLDQSEN_CYCLES_LEN>( exp_helper(mss::twldqsen()) );
    l_data.insertFromRight<TT::TWRMRD_CYCLES, TT::TWRMRD_CYCLES_LEN>( exp_helper(mss::twlmrd()) );

    return mss::putScom(i_target, TT::SEQ_TIMING1_REG, l_data);
}

///
/// @brief reset SEQ_TIMING2
/// @param[in] i_target fapi2 target of the port
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
///
template<>
fapi2::ReturnCode reset_timing2( const fapi2::Target<TARGET_TYPE_MCA>& i_target )
{
    typedef seqTraits<TARGET_TYPE_MCA> TT;

    // Reset value of SEQ_TIMING2 is lucky 7's - we'll fix up the first nibble with ODT info
    fapi2::buffer<uint64_t> l_data(0x7777);

    // Table 5-327. SEQ Memory Timing Parameter 2 Register
    // TODTLON_OFF_CYCLES max(ODTLon, ODTLoff)
    uint8_t l_odtlon = 0;
    uint8_t l_odtloff = 0;
    uint64_t l_odt = 0;
    FAPI_TRY( mss::max_dodt_on(i_target, l_odtlon) );
    FAPI_TRY( mss::max_dodt_off(i_target, l_odtloff) );

    l_odt = std::max( l_odtlon, l_odtloff );
    l_data.insertFromRight<TT::TODTLON_OFF_CYCLES, TT::TODTLON_OFF_CYCLES_LEN>( exp_helper(l_odt) );

    FAPI_TRY( mss::putScom(i_target, TT::SEQ_TIMING2_REG, l_data) );

fapi_try_exit:
    return fapi2::current_err;
}

} // close namespace seq
} // close namespace mss
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/generic/memory/lib/spd/common/rcw_settings.H $     */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file raw_cards.H
/// @brief Raw card data structure
///
// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
// *HWP HWP Backup: Jacob Harvey <jlharvey@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: HB:FSP

#ifndef _MSS_RAW_CARDS_H_
#define _MSS_RAW_CARDS_H_

#include <fapi2.H>
#include <cstdint>
#include <vector>

namespace mss
{

///
/// @brief raw card VBU settings
/// @note contains RCD settings for hard-coded values
/// that are not application specific.
/// Application specific settings are dervied in eff_config
struct rcw_settings
{
    uint64_t iv_rc00;
    uint64_t iv_rc01;

    ///
    /// @brief default ctor
    ///
    rcw_settings() = default;

    ///
    /// @brief Equality operator
    /// @param[in] i_rhs the right-hand side of the == operation
    /// @return true iff both raw_cards are equal
    ///
    inline bool operator==(const rcw_settings& i_rhs) const
    {
        // Betting this is faster than all the conditionals ...
        return (memcmp(this, &i_rhs, sizeof(rcw_settings)) == 0);
    }

    ///
    /// @brief Logical not operator
    /// @param[in] i_rhs the right-hand side of the != operation
    /// @return true iff both raw_cards are not equal
    ///
    inline bool operator!=(const rcw_settings& i_rhs) const
    {
        // Betting this is faster than all the conditionals ...
        return !(*this == i_rhs);
    }

    ///
    /// @brief ctor
    /// @param[in] i_rc00 setting for register control word (RC00)
    /// @param[in] i_rc01 setting for register control word (RC01)
    ///
    constexpr rcw_settings( const uint64_t i_rc00,
                            const uint64_t i_rc01)
        : iv_rc00(i_rc00),
          iv_rc01(i_rc01)
    {}

    ///
    /// @brief default dtor
    ///
    ~rcw_settings() = default;
};

}// mss

#endif //_MSS_RAW_CARDS_H_
<commit_msg>Remove mss::c_str dependency for SPD decoder for future reuse<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/generic/memory/lib/spd/common/rcw_settings.H $     */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file raw_cards.H
/// @brief Raw card data structure
///
// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: HB:FSP

#ifndef _MSS_RAW_CARDS_H_
#define _MSS_RAW_CARDS_H_

#include <fapi2.H>
#include <cstdint>
#include <vector>

namespace mss
{

///
/// @brief raw card VBU settings
/// @note contains RCD settings for hard-coded values
/// that are not application specific.
/// Application specific settings are dervied in eff_config
struct rcw_settings
{
    uint64_t iv_rc00;
    uint64_t iv_rc01;

    ///
    /// @brief default ctor
    ///
    rcw_settings() = default;

    ///
    /// @brief Equality operator
    /// @param[in] i_rhs the right-hand side of the == operation
    /// @return true iff both raw_cards are equal
    ///
    inline bool operator==(const rcw_settings& i_rhs) const
    {
        // Betting this is faster than all the conditionals ...
        return (memcmp(this, &i_rhs, sizeof(rcw_settings)) == 0);
    }

    ///
    /// @brief Logical not operator
    /// @param[in] i_rhs the right-hand side of the != operation
    /// @return true iff both raw_cards are not equal
    ///
    inline bool operator!=(const rcw_settings& i_rhs) const
    {
        // Betting this is faster than all the conditionals ...
        return !(*this == i_rhs);
    }

    ///
    /// @brief ctor
    /// @param[in] i_rc00 setting for register control word (RC00)
    /// @param[in] i_rc01 setting for register control word (RC01)
    ///
    constexpr rcw_settings( const uint64_t i_rc00,
                            const uint64_t i_rc01)
        : iv_rc00(i_rc00),
          iv_rc01(i_rc01)
    {}

    ///
    /// @brief default dtor
    ///
    ~rcw_settings() = default;
};

}// mss

#endif //_MSS_RAW_CARDS_H_
<|endoftext|>


<commit_before>#include <iostream>
#include<stdlib.h>
#include<map>
using namespace std;

void print_num(map<char,int>M)
{
    int num=rand()%100;
    cout<<num<<endl;
    int count=0;
    map<char,int>:: iterator it;
    for(it=M.begin();it!=M.end();it++)
    {
        count+=it->second;
        if(num>0 && num<=count)
            cout<<it->first;

    }

}

int main() {
	map<char,int>M;
	M['A']=10;
	M['B']=20;
	M['C']=30;
	M['D']=40;

	print_num(M);

	return 0;
}

<commit_msg>Adding wtd rand<commit_after>#include <iostream>
#include <stdlib.h>
#include <map>
using namespace std;

void print_num(map<char,int>M)
{
    int num = rand()%100; //45
    // cout<<num<<endl;
    int ub=0;

    map<char,int>:: iterator it;
    int lb = 0;

    for(it=M.begin();it!=M.end();it++)
    {
        ub += it->second;

        if(num >= lb && num < ub)
        {
            cout<<it->first;
            return;
        }

        lb = ub;
    }

}

int main() {
	map<char,int>M;
	M['A']=10;
	M['B']=20;
	M['C']=30;
	M['D']=40;

	//int num=25;

	print_num(M);

	return 0;
}

<|endoftext|>


<commit_before>#ifndef __UHD_QUEUE_HPP__
#define __UHD_QUEUE_HPP__

#include <queue>
#include <mutex>
#include <condition_variable>

namespace uhd {

template <typename T>
class Queue {
  public:
    Queue() {}
    void push(T &&value);
    void push(const T &value);
    T pop();
    void clear();
    bool empty();
    size_t size();

  private:
    std::mutex _lock;
    std::condition_variable _notify;
    std::queue<T> _queue;
};

template <typename T>
void Queue<T>::push(T &&value) {
    std::lock_guard<std::mutex> lg(_lock);
    _queue.push(std::move(value));
    _notify.notify_one();
}

template <typename T>
T Queue<T>::pop() {
    std::unique_lock<std::mutex> lg(_lock);
    while (_queue.empty())
        _notify.wait(lg);
    T value(std::move(_queue.front()));
    _queue.pop();
    return value;
}

template <typename T>
void Queue<T>::clear() {
    std::lock_guard<std::mutex> lg(_lock);
    while (!_queue.empty())
        _queue.pop();
}

template <typename T>
bool Queue<T>::empty() {
    std::lock_guard<std::mutex> lg(_lock);
    return _queue.empty();
}

template <typename T>
size_t Queue<T>::size() {
    std::lock_guard<std::mutex> lg(_lock);
    return _queue.size();
}

}

#endif  /** __UHD_QUEUE_HPP__ **/
<commit_msg>uhd_queue.hpp: add push(const T&)<commit_after>#ifndef __UHD_QUEUE_HPP__
#define __UHD_QUEUE_HPP__

#include <queue>
#include <mutex>
#include <condition_variable>

namespace uhd {

template <typename T>
class Queue {
  public:
    Queue() {}
    void push(const T &value);
    void push(T &&value);
    T pop();
    void clear();
    bool empty();
    size_t size();

  private:
    std::mutex _lock;
    std::condition_variable _notify;
    std::queue<T> _queue;
};

template <typename T>
void Queue<T>::push(const T &value) {
    std::lock_guard<std::mutex> lg(_lock);
    _queue.push(value);
    _notify.notify_one();
}

template <typename T>
void Queue<T>::push(T &&value) {
    std::lock_guard<std::mutex> lg(_lock);
    _queue.push(std::move(value));
    _notify.notify_one();
}

template <typename T>
T Queue<T>::pop() {
    std::unique_lock<std::mutex> lg(_lock);
    while (_queue.empty())
        _notify.wait(lg);
    T value(std::move(_queue.front()));
    _queue.pop();
    return value;
}

template <typename T>
void Queue<T>::clear() {
    std::lock_guard<std::mutex> lg(_lock);
    while (!_queue.empty())
        _queue.pop();
}

template <typename T>
bool Queue<T>::empty() {
    std::lock_guard<std::mutex> lg(_lock);
    return _queue.empty();
}

template <typename T>
size_t Queue<T>::size() {
    std::lock_guard<std::mutex> lg(_lock);
    return _queue.size();
}

}

#endif  /** __UHD_QUEUE_HPP__ **/
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:  vtkDijkstraGraphGeodesicPath.cxx
  Language:  C++
  Date:    $Date$
  Version:   $Revision$

  Made by Rasmus Paulsen
  email:  rrp(at)imm.dtu.dk
  web:    www.imm.dtu.dk/~rrp/VTK

  This class is not mature enough to enter the official VTK release.
=========================================================================*/
#include "vtkDijkstraGraphGeodesicPath.h"

#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkFloatArray.h"
#include "vtkObjectFactory.h"
#include "vtkExecutive.h"
#include "vtkMath.h"
#include "vtkIdList.h"
#include "vtkFloatArray.h"
#include "vtkIntArray.h"
#include "vtkPolyData.h"
#include "vtkPoints.h"
#include "vtkPointData.h"
#include "vtkCellArray.h"

vtkCxxRevisionMacro(vtkDijkstraGraphGeodesicPath, "1.2");
vtkStandardNewMacro(vtkDijkstraGraphGeodesicPath);

//----------------------------------------------------------------------------
vtkDijkstraGraphGeodesicPath::vtkDijkstraGraphGeodesicPath()
{
  this->IdList = vtkIdList::New();
  this->d    = vtkFloatArray::New();
  this->pre  = vtkIntArray::New();
  this->f    = vtkIntArray::New();
  this->s    = vtkIntArray::New();
  this->H    = vtkIntArray::New();
  this->p    = vtkIntArray::New();
  this->Hsize  = 0;
  this->StartVertex = 0;
  this->EndVertex   = 0;
  this->StopWhenEndReached = 0;
  this->UseScalarWeights = 0;
  this->Adj = NULL;
  this->n = 0;
  this->AdjacencyGraphSize = 0;
}

//----------------------------------------------------------------------------
vtkDijkstraGraphGeodesicPath::~vtkDijkstraGraphGeodesicPath()
{
  if (this->IdList)
    this->IdList->Delete();
  if (this->d)
    this->d->Delete();
  if (this->pre)
    this->pre->Delete();
  if (this->f)
    this->f->Delete();
  if (this->s)
    this->s->Delete();
  if (this->H)
    this->H->Delete();
  if (this->p)
    this->p->Delete();

  DeleteAdjacency();
}

//----------------------------------------------------------------------------
int vtkDijkstraGraphGeodesicPath::RequestData(
  vtkInformation *           vtkNotUsed( request ),
  vtkInformationVector **    inputVector,
  vtkInformationVector *     outputVector)
{
  vtkInformation * inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo =   outputVector->GetInformationObject(0);

  vtkPolyData *input = vtkPolyData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  if (!input)
    {
    return 0;
    }

  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));
  if (!input)
    {
    return 0;
    }

  this->Initialize();
  this->ShortestPath(this->StartVertex, this->EndVertex);
  this->TraceShortestPath(input, output, this->StartVertex, this->EndVertex);
  return 1;
}

//----------------------------------------------------------------------------
void vtkDijkstraGraphGeodesicPath::Initialize()
{
  vtkPolyData *input = vtkPolyData::SafeDownCast(
      this->GetExecutive()->GetInputData(0, 0));

  this->BuildAdjacency( input );

  this->IdList->Reset();

  this->n = input->GetNumberOfPoints();

  this->d->SetNumberOfComponents(1);
  this->d->SetNumberOfTuples(this->n);
  this->pre->SetNumberOfComponents(1);
  this->pre->SetNumberOfTuples(this->n);
  this->f->SetNumberOfComponents(1);
  this->f->SetNumberOfTuples(this->n);
  this->s->SetNumberOfComponents(1);
  this->s->SetNumberOfTuples(this->n);
  this->p->SetNumberOfComponents(1);
  this->p->SetNumberOfTuples(this->n);

  // The heap has elements from 1 to n
  this->H->SetNumberOfComponents(1);
  this->H->SetNumberOfTuples(this->n+1);

  this->Hsize = 0;
}

//----------------------------------------------------------------------------
void vtkDijkstraGraphGeodesicPath::DeleteAdjacency()
{
  const int npoints = this->AdjacencyGraphSize;

  if (this->Adj)
    {
    for (int i = 0; i < npoints; i++)
      {
      this->Adj[i]->Delete();
      }
    delete [] this->Adj;
    }
  this->Adj = NULL;
}

//----------------------------------------------------------------------------
// The edge cost function should be implemented as a callback function to
// allow more advanced weighting
double vtkDijkstraGraphGeodesicPath::EdgeCost(
     vtkPolyData *pd, vtkIdType u, vtkIdType v)
{
  double p1[3];
  pd->GetPoint(u,p1);
  double p2[3];
  pd->GetPoint(v,p2);

  double w = sqrt(vtkMath::Distance2BetweenPoints(p1, p2));

  if (this->UseScalarWeights)
    {
    // Note this edge cost is not symmetric!
    vtkFloatArray *scalars = (vtkFloatArray*)pd->GetPointData()->GetScalars();
    //    float s1 = scalars->GetValue(u);
    float s2 = scalars->GetValue(v);

    if (s2)
      {
      w  /= (s2*s2);
      }
    }
  return w;
}

//----------------------------------------------------------------------------
// This is probably a horribly inefficient way to do it.
void vtkDijkstraGraphGeodesicPath::BuildAdjacency(vtkPolyData *pd)
{
  int i;

  int npoints = pd->GetNumberOfPoints();
  int ncells = pd->GetNumberOfCells();

  this->DeleteAdjacency();

  this->Adj = new vtkIdList*[npoints];

  // Remember size, so it can be deleted again
  this->AdjacencyGraphSize = npoints;

  for (i = 0; i < npoints; i++)
    {
    this->Adj[i] = vtkIdList::New();
    }

  for (i = 0; i < ncells; i++)
    {
    // Possible types
    //    VTK_VERTEX, VTK_POLY_VERTEX, VTK_LINE,
    //    VTK_POLY_LINE,VTK_TRIANGLE, VTK_QUAD,
    //    VTK_POLYGON, or VTK_TRIANGLE_STRIP.

    vtkIdType ctype = pd->GetCellType(i);

    // Until now only handle polys and triangles
    // TODO: All types
    if (ctype == VTK_POLYGON || ctype == VTK_TRIANGLE || ctype == VTK_LINE)
      {
      vtkIdType *pts;
      vtkIdType npts;
      pd->GetCellPoints (i, npts, pts);

      vtkIdType u = pts[0];
      vtkIdType v = pts[npts-1];

      Adj[u]->InsertUniqueId(v);
      Adj[v]->InsertUniqueId(u);
      for (int j = 0; j < npts-1; j++)
        {
        vtkIdType u1 = pts[j];
        vtkIdType v1 = pts[j+1];
        Adj[u1]->InsertUniqueId(v1);
        Adj[v1]->InsertUniqueId(u1);
        }
      }
    }
}

//----------------------------------------------------------------------------
void vtkDijkstraGraphGeodesicPath::TraceShortestPath(
               vtkPolyData *inPd, vtkPolyData *outPd,
               vtkIdType startv, vtkIdType endv)
{
  vtkPoints   *points = vtkPoints::New();
  vtkCellArray *lines = vtkCellArray::New();

  // n is far to many. Adjusted later
  lines->InsertNextCell(this->n);

  // trace backward
  int npoints = 0;
  int v = endv;
  double pt[3];
  vtkIdType id;
  while (v != startv)
    {
    IdList->InsertNextId(v);

    inPd->GetPoint(v,pt);
    id = points->InsertNextPoint(pt);
    lines->InsertCellPoint(id);
    npoints++;

    v = this->pre->GetValue(v);
    }

  this->IdList->InsertNextId(v);

  inPd->GetPoint(v,pt);
  id = points->InsertNextPoint(pt);
  lines->InsertCellPoint(id);
  npoints++;

  lines->UpdateCellCount(npoints);
  outPd->SetPoints(points);
  points->Delete();
  outPd->SetLines(lines);
  lines->Delete();
}

//----------------------------------------------------------------------------
void vtkDijkstraGraphGeodesicPath::InitSingleSource(int startv)
{
  for (int v = 0; v < this->n; v++)
    {
    // d will be updated with first visit of vertex
    this->d->SetValue(v, -1);
    this->pre->SetValue(v, -1);
    this->s->SetValue(v, 0);
    this->f->SetValue(v, 0);
    }

  this->d->SetValue(startv, 0);
}

//----------------------------------------------------------------------------
void vtkDijkstraGraphGeodesicPath::Relax(int u, int v, double w)
{
  if (this->d->GetValue(v) > this->d->GetValue(u) + w)
    {
    this->d->SetValue(v, this->d->GetValue(u) + w);
    this->pre->SetValue(v, u);

    this->HeapDecreaseKey(v);
    }
}

//----------------------------------------------------------------------------
void vtkDijkstraGraphGeodesicPath::ShortestPath(int startv, int endv)
{
  vtkPolyData *input = vtkPolyData::SafeDownCast(
      this->GetExecutive()->GetInputData(0, 0));

  int i, u, v;

  this->InitSingleSource(startv);

  this->HeapInsert(startv);
  this->f->SetValue(startv, 1);

  int stop = 0;
  while ((u = this->HeapExtractMin()) >= 0 && !stop)
    {
    // u is now in s since the shortest path to u is determined
    this->s->SetValue(u, 1);
    // remove u from the front set
    this->f->SetValue(u, 0);

    if (u == endv && this->StopWhenEndReached)
      stop = 1;

    // Update all vertices v adjacent to u
    for (i = 0; i < this->Adj[u]->GetNumberOfIds(); i++)
      {
      v = this->Adj[u]->GetId(i);

      // s is the set of vertices with determined shortest path...do not use them again
      if (!this->s->GetValue(v))
        {
        // Only relax edges where the end is not in s and edge is in the front set
        double w = this->EdgeCost(input, u, v);

        if (this->f->GetValue(v))
        {
          Relax(u, v, w);
        }
        // add edge v to front set
        else
        {
          this->f->SetValue(v, 1);
          this->d->SetValue(v, this->d->GetValue(u) + w);

          // Set Predecessor of v to be u
          this->pre->SetValue(v, u);

          this->HeapInsert(v);
          }
        }
      }
    }
}

//----------------------------------------------------------------------------
void vtkDijkstraGraphGeodesicPath::Heapify(int i)
{
  // left node
  int l = i * 2;

  // right node
  int r = i * 2 + 1;

  int smallest = -1;

  // The value of element v is d(v)
  // the heap stores the vertex numbers
  if (   l <= this->Hsize
      && (this->d->GetValue(this->H->GetValue(l)) <
             this->d->GetValue(this->H->GetValue(i))))
    {
    smallest = l;
    }
  else
    {
    smallest = i;
    }

  if ( r <= this->Hsize &&
      (this->d->GetValue(this->H->GetValue(r)) <
      this->d->GetValue(this->H->GetValue(smallest))))
    {
    smallest = r;
    }

  if (smallest != i)
    {
    int t = this->H->GetValue(i);

    this->H->SetValue(i, this->H->GetValue(smallest));

    // where is H(i)
    this->p->SetValue(this->H->GetValue(i), i);

    // H and p is kinda inverse
    this->H->SetValue(smallest, t);
    this->p->SetValue(t, smallest);

    this->Heapify(smallest);
    }
}

//----------------------------------------------------------------------------
// Insert vertex v. Weight is given in d(v)
// H has indices 1..n
void vtkDijkstraGraphGeodesicPath::HeapInsert(int v)
{
  if (this->Hsize >= this->H->GetNumberOfTuples()-1)
    return;

  this->Hsize++;
  int i = this->Hsize;

  while (i > 1 &&
         (this->d->GetValue(this->H->GetValue(i/2))
                   > this->d->GetValue(v)))
    {
    this->H->SetValue(i, this->H->GetValue(i/2));
    this->p->SetValue(this->H->GetValue(i), i);
    i /= 2;
    }
  // H and p is kinda inverse
  this->H->SetValue(i, v);
  this->p->SetValue(v, i);
}

//----------------------------------------------------------------------------
int vtkDijkstraGraphGeodesicPath::HeapExtractMin()
{
  if (this->Hsize == 0)
    return -1;

  int minv = this->H->GetValue(1);
  this->p->SetValue(minv, -1);

  this->H->SetValue(1, this->H->GetValue(this->Hsize));
  this->p->SetValue(this->H->GetValue(1), 1);

  this->Hsize--;
  this->Heapify(1);

  return minv;
}

//----------------------------------------------------------------------------
void vtkDijkstraGraphGeodesicPath::HeapDecreaseKey(int v)
{
  // where in H is vertex v
  int i = this->p->GetValue(v);
  if (i < 1 || i > this->Hsize)
    return;

  while (i > 1 &&
      this->d->GetValue(this->H->GetValue(i/2)) > this->d->GetValue(v))
    {
    this->H->SetValue(i, this->H->GetValue(i/2));
    this->p->SetValue(this->H->GetValue(i), i);
    i /= 2;
    }

  // H and p is kinda inverse
  this->H->SetValue(i, v);
  this->p->SetValue(v, i);
}

//----------------------------------------------------------------------------
void vtkDijkstraGraphGeodesicPath::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  // Add all members later
}

<commit_msg>COMP: try to get rid of the numerical issue on borland.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:  vtkDijkstraGraphGeodesicPath.cxx
  Language:  C++
  Date:    $Date$
  Version:   $Revision$

  Made by Rasmus Paulsen
  email:  rrp(at)imm.dtu.dk
  web:    www.imm.dtu.dk/~rrp/VTK

  This class is not mature enough to enter the official VTK release.
=========================================================================*/
#include "vtkDijkstraGraphGeodesicPath.h"

#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkFloatArray.h"
#include "vtkObjectFactory.h"
#include "vtkExecutive.h"
#include "vtkMath.h"
#include "vtkIdList.h"
#include "vtkFloatArray.h"
#include "vtkIntArray.h"
#include "vtkPolyData.h"
#include "vtkPoints.h"
#include "vtkPointData.h"
#include "vtkCellArray.h"

vtkCxxRevisionMacro(vtkDijkstraGraphGeodesicPath, "1.3");
vtkStandardNewMacro(vtkDijkstraGraphGeodesicPath);

//----------------------------------------------------------------------------
vtkDijkstraGraphGeodesicPath::vtkDijkstraGraphGeodesicPath()
{
  this->IdList = vtkIdList::New();
  this->d    = vtkFloatArray::New();
  this->pre  = vtkIntArray::New();
  this->f    = vtkIntArray::New();
  this->s    = vtkIntArray::New();
  this->H    = vtkIntArray::New();
  this->p    = vtkIntArray::New();
  this->Hsize  = 0;
  this->StartVertex = 0;
  this->EndVertex   = 0;
  this->StopWhenEndReached = 0;
  this->UseScalarWeights = 0;
  this->Adj = NULL;
  this->n = 0;
  this->AdjacencyGraphSize = 0;
}

//----------------------------------------------------------------------------
vtkDijkstraGraphGeodesicPath::~vtkDijkstraGraphGeodesicPath()
{
  if (this->IdList)
    this->IdList->Delete();
  if (this->d)
    this->d->Delete();
  if (this->pre)
    this->pre->Delete();
  if (this->f)
    this->f->Delete();
  if (this->s)
    this->s->Delete();
  if (this->H)
    this->H->Delete();
  if (this->p)
    this->p->Delete();

  DeleteAdjacency();
}

//----------------------------------------------------------------------------
int vtkDijkstraGraphGeodesicPath::RequestData(
  vtkInformation *           vtkNotUsed( request ),
  vtkInformationVector **    inputVector,
  vtkInformationVector *     outputVector)
{
  vtkInformation * inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo =   outputVector->GetInformationObject(0);

  vtkPolyData *input = vtkPolyData::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  if (!input)
    {
    return 0;
    }

  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));
  if (!input)
    {
    return 0;
    }

  this->Initialize();
  this->ShortestPath(this->StartVertex, this->EndVertex);
  this->TraceShortestPath(input, output, this->StartVertex, this->EndVertex);
  return 1;
}

//----------------------------------------------------------------------------
void vtkDijkstraGraphGeodesicPath::Initialize()
{
  vtkPolyData *input = vtkPolyData::SafeDownCast(
      this->GetExecutive()->GetInputData(0, 0));

  this->BuildAdjacency( input );

  this->IdList->Reset();

  this->n = input->GetNumberOfPoints();

  this->d->SetNumberOfComponents(1);
  this->d->SetNumberOfTuples(this->n);
  this->pre->SetNumberOfComponents(1);
  this->pre->SetNumberOfTuples(this->n);
  this->f->SetNumberOfComponents(1);
  this->f->SetNumberOfTuples(this->n);
  this->s->SetNumberOfComponents(1);
  this->s->SetNumberOfTuples(this->n);
  this->p->SetNumberOfComponents(1);
  this->p->SetNumberOfTuples(this->n);

  // The heap has elements from 1 to n
  this->H->SetNumberOfComponents(1);
  this->H->SetNumberOfTuples(this->n+1);

  this->Hsize = 0;
}

//----------------------------------------------------------------------------
void vtkDijkstraGraphGeodesicPath::DeleteAdjacency()
{
  const int npoints = this->AdjacencyGraphSize;

  if (this->Adj)
    {
    for (int i = 0; i < npoints; i++)
      {
      this->Adj[i]->Delete();
      }
    delete [] this->Adj;
    }
  this->Adj = NULL;
}

//----------------------------------------------------------------------------
// The edge cost function should be implemented as a callback function to
// allow more advanced weighting
double vtkDijkstraGraphGeodesicPath::EdgeCost(
     vtkPolyData *pd, vtkIdType u, vtkIdType v)
{
  double p1[3];
  pd->GetPoint(u,p1);
  double p2[3];
  pd->GetPoint(v,p2);

  double w = sqrt(vtkMath::Distance2BetweenPoints(p1, p2));

  if (this->UseScalarWeights)
    {
    // Note this edge cost is not symmetric!
    vtkFloatArray *scalars = (vtkFloatArray*)pd->GetPointData()->GetScalars();
    //    float s1 = scalars->GetValue(u);
    float s2 = scalars->GetValue(v);

    double wt = ((double)(s2))*((double)(s2));
    if (wt != 0.0)
      {
      w  /= wt;
      }
    }
  return w;
}

//----------------------------------------------------------------------------
// This is probably a horribly inefficient way to do it.
void vtkDijkstraGraphGeodesicPath::BuildAdjacency(vtkPolyData *pd)
{
  int i;

  int npoints = pd->GetNumberOfPoints();
  int ncells = pd->GetNumberOfCells();

  this->DeleteAdjacency();

  this->Adj = new vtkIdList*[npoints];

  // Remember size, so it can be deleted again
  this->AdjacencyGraphSize = npoints;

  for (i = 0; i < npoints; i++)
    {
    this->Adj[i] = vtkIdList::New();
    }

  for (i = 0; i < ncells; i++)
    {
    // Possible types
    //    VTK_VERTEX, VTK_POLY_VERTEX, VTK_LINE,
    //    VTK_POLY_LINE,VTK_TRIANGLE, VTK_QUAD,
    //    VTK_POLYGON, or VTK_TRIANGLE_STRIP.

    vtkIdType ctype = pd->GetCellType(i);

    // Until now only handle polys and triangles
    // TODO: All types
    if (ctype == VTK_POLYGON || ctype == VTK_TRIANGLE || ctype == VTK_LINE)
      {
      vtkIdType *pts;
      vtkIdType npts;
      pd->GetCellPoints (i, npts, pts);

      vtkIdType u = pts[0];
      vtkIdType v = pts[npts-1];

      Adj[u]->InsertUniqueId(v);
      Adj[v]->InsertUniqueId(u);
      for (int j = 0; j < npts-1; j++)
        {
        vtkIdType u1 = pts[j];
        vtkIdType v1 = pts[j+1];
        Adj[u1]->InsertUniqueId(v1);
        Adj[v1]->InsertUniqueId(u1);
        }
      }
    }
}

//----------------------------------------------------------------------------
void vtkDijkstraGraphGeodesicPath::TraceShortestPath(
               vtkPolyData *inPd, vtkPolyData *outPd,
               vtkIdType startv, vtkIdType endv)
{
  vtkPoints   *points = vtkPoints::New();
  vtkCellArray *lines = vtkCellArray::New();

  // n is far to many. Adjusted later
  lines->InsertNextCell(this->n);

  // trace backward
  int npoints = 0;
  int v = endv;
  double pt[3];
  vtkIdType id;
  while (v != startv)
    {
    IdList->InsertNextId(v);

    inPd->GetPoint(v,pt);
    id = points->InsertNextPoint(pt);
    lines->InsertCellPoint(id);
    npoints++;

    v = this->pre->GetValue(v);
    }

  this->IdList->InsertNextId(v);

  inPd->GetPoint(v,pt);
  id = points->InsertNextPoint(pt);
  lines->InsertCellPoint(id);
  npoints++;

  lines->UpdateCellCount(npoints);
  outPd->SetPoints(points);
  points->Delete();
  outPd->SetLines(lines);
  lines->Delete();
}

//----------------------------------------------------------------------------
void vtkDijkstraGraphGeodesicPath::InitSingleSource(int startv)
{
  for (int v = 0; v < this->n; v++)
    {
    // d will be updated with first visit of vertex
    this->d->SetValue(v, -1);
    this->pre->SetValue(v, -1);
    this->s->SetValue(v, 0);
    this->f->SetValue(v, 0);
    }

  this->d->SetValue(startv, 0);
}

//----------------------------------------------------------------------------
void vtkDijkstraGraphGeodesicPath::Relax(int u, int v, double w)
{
  if (this->d->GetValue(v) > this->d->GetValue(u) + w)
    {
    this->d->SetValue(v, this->d->GetValue(u) + w);
    this->pre->SetValue(v, u);

    this->HeapDecreaseKey(v);
    }
}

//----------------------------------------------------------------------------
void vtkDijkstraGraphGeodesicPath::ShortestPath(int startv, int endv)
{
  vtkPolyData *input = vtkPolyData::SafeDownCast(
      this->GetExecutive()->GetInputData(0, 0));

  int i, u, v;

  this->InitSingleSource(startv);

  this->HeapInsert(startv);
  this->f->SetValue(startv, 1);

  int stop = 0;
  while ((u = this->HeapExtractMin()) >= 0 && !stop)
    {
    // u is now in s since the shortest path to u is determined
    this->s->SetValue(u, 1);
    // remove u from the front set
    this->f->SetValue(u, 0);

    if (u == endv && this->StopWhenEndReached)
      stop = 1;

    // Update all vertices v adjacent to u
    for (i = 0; i < this->Adj[u]->GetNumberOfIds(); i++)
      {
      v = this->Adj[u]->GetId(i);

      // s is the set of vertices with determined shortest path...do not use them again
      if (!this->s->GetValue(v))
        {
        // Only relax edges where the end is not in s and edge is in the front set
        double w = this->EdgeCost(input, u, v);

        if (this->f->GetValue(v))
        {
          Relax(u, v, w);
        }
        // add edge v to front set
        else
        {
          this->f->SetValue(v, 1);
          this->d->SetValue(v, this->d->GetValue(u) + w);

          // Set Predecessor of v to be u
          this->pre->SetValue(v, u);

          this->HeapInsert(v);
          }
        }
      }
    }
}

//----------------------------------------------------------------------------
void vtkDijkstraGraphGeodesicPath::Heapify(int i)
{
  // left node
  int l = i * 2;

  // right node
  int r = i * 2 + 1;

  int smallest = -1;

  // The value of element v is d(v)
  // the heap stores the vertex numbers
  if (   l <= this->Hsize
      && (this->d->GetValue(this->H->GetValue(l)) <
             this->d->GetValue(this->H->GetValue(i))))
    {
    smallest = l;
    }
  else
    {
    smallest = i;
    }

  if ( r <= this->Hsize &&
      (this->d->GetValue(this->H->GetValue(r)) <
      this->d->GetValue(this->H->GetValue(smallest))))
    {
    smallest = r;
    }

  if (smallest != i)
    {
    int t = this->H->GetValue(i);

    this->H->SetValue(i, this->H->GetValue(smallest));

    // where is H(i)
    this->p->SetValue(this->H->GetValue(i), i);

    // H and p is kinda inverse
    this->H->SetValue(smallest, t);
    this->p->SetValue(t, smallest);

    this->Heapify(smallest);
    }
}

//----------------------------------------------------------------------------
// Insert vertex v. Weight is given in d(v)
// H has indices 1..n
void vtkDijkstraGraphGeodesicPath::HeapInsert(int v)
{
  if (this->Hsize >= this->H->GetNumberOfTuples()-1)
    return;

  this->Hsize++;
  int i = this->Hsize;

  while (i > 1 &&
         (this->d->GetValue(this->H->GetValue(i/2))
                   > this->d->GetValue(v)))
    {
    this->H->SetValue(i, this->H->GetValue(i/2));
    this->p->SetValue(this->H->GetValue(i), i);
    i /= 2;
    }
  // H and p is kinda inverse
  this->H->SetValue(i, v);
  this->p->SetValue(v, i);
}

//----------------------------------------------------------------------------
int vtkDijkstraGraphGeodesicPath::HeapExtractMin()
{
  if (this->Hsize == 0)
    return -1;

  int minv = this->H->GetValue(1);
  this->p->SetValue(minv, -1);

  this->H->SetValue(1, this->H->GetValue(this->Hsize));
  this->p->SetValue(this->H->GetValue(1), 1);

  this->Hsize--;
  this->Heapify(1);

  return minv;
}

//----------------------------------------------------------------------------
void vtkDijkstraGraphGeodesicPath::HeapDecreaseKey(int v)
{
  // where in H is vertex v
  int i = this->p->GetValue(v);
  if (i < 1 || i > this->Hsize)
    return;

  while (i > 1 &&
      this->d->GetValue(this->H->GetValue(i/2)) > this->d->GetValue(v))
    {
    this->H->SetValue(i, this->H->GetValue(i/2));
    this->p->SetValue(this->H->GetValue(i), i);
    i /= 2;
    }

  // H and p is kinda inverse
  this->H->SetValue(i, v);
  this->p->SetValue(v, i);
}

//----------------------------------------------------------------------------
void vtkDijkstraGraphGeodesicPath::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  // Add all members later
}

<|endoftext|>


<commit_before>#include "user.h"
#include "process.h"
#include <shlwapi.h>
#include <io.h>
#include <stdio.h>
#include <fcntl.h>
#include <iostream>

int wmain() {
	try {
		UserManager user_manager;
		JobbedProcessManager process;
		WCHAR szDirectory[MAX_PATH];

		GetModuleFileName(nullptr, szDirectory, MAX_PATH);
		*(PathFindFileName(szDirectory) - 1) = '\0';
		process.time(2).memory(65536 * 1024).processes(1).command(L"hello.exe").directory(szDirectory)
			.withLogin(user_manager.username(), user_manager.password());
		process.spawn();
		process.stdIn().close();
		process.stdErr().close();
		int ch, fd = _open_osfhandle((intptr_t) (HANDLE) process.stdOut(), _O_RDONLY);
		FILE *file = _fdopen(fd, "r");
		while ((ch = fgetc(file)) != EOF)
			putchar(ch);
	} catch (WindowsException &e) {
		std::cout << e.what() << '\n';
	}
}<commit_msg>Prevent double close.<commit_after>#include "user.h"
#include "process.h"
#include <shlwapi.h>
#include <io.h>
#include <stdio.h>
#include <fcntl.h>
#include <iostream>

int wmain() {
	try {
		UserManager user_manager;
		JobbedProcessManager process;
		WCHAR szDirectory[MAX_PATH];

		GetModuleFileName(nullptr, szDirectory, MAX_PATH);
		*(PathFindFileName(szDirectory) - 1) = '\0';
		process.time(2).memory(65536 * 1024).processes(1).command(L"hello.exe").directory(szDirectory)
			.withLogin(user_manager.username(), user_manager.password());
		process.spawn();
		process.stdIn().close();
		process.stdErr().close();
		int ch, fd = _open_osfhandle((intptr_t) process.stdOut().detach(), _O_RDONLY);
		FILE *file = _fdopen(fd, "r");
		while ((ch = fgetc(file)) != EOF)
			putchar(ch);
	} catch (WindowsException &e) {
		std::cout << e.what() << '\n';
	}
}<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2013 J-P Nurmi <jpnurmi@gmail.com>
 *
 * This test is free, and not covered by LGPL license. There is no
 * restriction applied to their modification, redistribution, using and so on.
 * You can study them, modify them, use them in your own program - either
 * completely or partially. By using it you may give me some credits in your
 * program, but you don't have to.
 */

#include "messageformatter.h"
#include "usermodel.h"
#include "session.h"
#include <QtTest/QtTest>
#include <QtCore/QStringList>

static const QString MSG_32_5("Vestibulum eu libero eget metus.");
static const QString MSG_64_9("Phasellus enim dui, sodales sed tincidunt quis, ultricies metus.");
static const QString MSG_128_19("Ut porttitor volutpat tristique. Aenean semper ligula eget nulla condimentum tempor in quis felis. Sed sem diam, tincidunt amet.");
static const QString MSG_256_37("Vestibulum quis lorem velit, a varius augue. Suspendisse risus augue, ultricies at convallis in, elementum in velit. Fusce fermentum congue augue sit amet dapibus. Fusce ultrices urna ut tortor laoreet a aliquet elit lobortis. Suspendisse volutpat posuere.");
static const QString MSG_512_75("Nam leo risus, accumsan a sagittis eget, posuere eu velit. Morbi mattis auctor risus, vel consequat massa pulvinar nec. Proin aliquam convallis elit nec egestas. Pellentesque accumsan placerat augue, id volutpat nibh dictum vel. Aenean venenatis varius feugiat. Nullam molestie, ipsum id dignissim vulputate, eros urna vestibulum massa, in vehicula lacus nisi vitae risus. Ut nunc nunc, venenatis a mattis auctor, dictum et sem. Nulla posuere libero ut tortor elementum egestas. Aliquam egestas suscipit posuere.");

static const QStringList USERS_100 = QStringList()
                                     << "jpnurmi" << "Curabitur" << "nORMAL" << "leo" << "luctus"
                                     << "luctus" << "paraply" << "sapien" << "nope" << "vitae"
                                     << "where" << "alien" << "urna" << "turpis" << "rea_son"
                                     << "alone" << "velit" << "jipsu" << "rutrum" << "DiSCO"
                                     << "abort" << "venue" << "__duis__" << "eros" << "adam"
                                     << "hendrix" << "liber0" << "Jim" << "Leonardo" << "JiMi"
                                     << "justin" << "semper" << "fidelis" << "Excelsior" << "parachute"
                                     << "nam" << "nom" << "Lorem" << "risus" << "stereo"
                                     << "tv" << "what-ever" << "kill" << "savior" << "[haha]"
                                     << "null" << "nill" << "will" << "still" << "ill"
                                     << "fill" << "hill" << "bill" << "Lucas" << "metus"
                                     << "bitch" << "d0nut" << "perverT" << "br0tha" << "WHYZ"
                                     << "Amen" << "hero" << "another" << "other" << "augue"
                                     << "Vestibulum" << "quit" << "quis" << "Luis" << "luiz"
                                     << "Luigi" << "anus" << "formal" << "f00bar" << "sed"
                                     << "sodales" << "phasellus" << "port" << "porttitor" << "absolute"
                                     << "varius" << "Marius" << "access" << "ZzZzZz" << "dust"
                                     << "up" << "d0wn" << "l3ft" << "r1ght" << "n0ne"
                                     << "MeSsAgE" << "FoRmAtTeR" << "c00l" << "_[KiDDO]_" << "yes"
                                     << "no" << "never" << "tincidunt" << "ultricies" << "posuere";

class TestMessageFormatter : public MessageFormatter
{
    friend class tst_MessageFormatter;
};

class TestUserModel : public UserModel
{
    friend class tst_MessageFormatter;
public:
    TestUserModel(Session* session) : UserModel(session) { }
};

class tst_MessageFormatter : public QObject
{
    Q_OBJECT

private slots:
    void testFormatHtml_data();
    void testFormatHtml();

private:
    TestMessageFormatter formatter;
};

Q_DECLARE_METATYPE(QStringList)
void tst_MessageFormatter::testFormatHtml_data()
{
    qRegisterMetaType<QStringList>();

    QStringList USERS_UC;
    foreach (const QString& user, USERS_100)
        USERS_UC += user.toUpper();

    QTest::addColumn<QString>("message");
    QTest::addColumn<QStringList>("users");

    QTest::newRow("empty") << QString() << QStringList();

    QTest::newRow("32 chars / 5 words / 0 users") << MSG_32_5 << QStringList();
    QTest::newRow("32 chars / 5 words / 25 users") << MSG_32_5 << QStringList(USERS_100.mid(0, 25));
    QTest::newRow("32 chars / 5 words / 50 users") << MSG_32_5 << QStringList(USERS_100.mid(0, 50));
    QTest::newRow("32 chars / 5 words / 75 users") << MSG_32_5 << QStringList(USERS_100.mid(0, 75));
    QTest::newRow("32 chars / 5 words / 100 users") << MSG_32_5 << USERS_100;
    QTest::newRow("32 chars / 5 words / 200 users") << MSG_32_5 << USERS_100 + USERS_UC;

    QTest::newRow("64 chars / 9 words / 0 users")  << MSG_64_9 << QStringList();
    QTest::newRow("64 chars / 9 words / 25 users") << MSG_64_9 << QStringList(USERS_100.mid(0, 25));
    QTest::newRow("64 chars / 9 words / 50 users") << MSG_64_9 << QStringList(USERS_100.mid(0, 50));
    QTest::newRow("64 chars / 9 words / 75 users") << MSG_64_9 << QStringList(USERS_100.mid(0, 75));
    QTest::newRow("64 chars / 9 words / 100 users") << MSG_64_9 << USERS_100;
    QTest::newRow("64 chars / 9 words / 200 users") << MSG_64_9 << USERS_100 + USERS_UC;

    QTest::newRow("128 chars / 19 words / 0 users")  << MSG_128_19 << QStringList();
    QTest::newRow("128 chars / 19 words / 25 users") << MSG_128_19 << QStringList(USERS_100.mid(0, 25));
    QTest::newRow("128 chars / 19 words / 50 users") << MSG_128_19 << QStringList(USERS_100.mid(0, 50));
    QTest::newRow("128 chars / 19 words / 75 users") << MSG_128_19 << QStringList(USERS_100.mid(0, 75));
    QTest::newRow("128 chars / 19 words / 100 users") << MSG_128_19 << USERS_100;
    QTest::newRow("128 chars / 19 words / 200 users") << MSG_128_19 << USERS_100 + USERS_UC;

    QTest::newRow("256 chars / 37 words / 0 users")  << MSG_256_37 << QStringList();
    QTest::newRow("256 chars / 37 words / 25 users") << MSG_256_37 << QStringList(USERS_100.mid(0, 25));
    QTest::newRow("256 chars / 37 words / 50 users") << MSG_256_37 << QStringList(USERS_100.mid(0, 50));
    QTest::newRow("256 chars / 37 words / 75 users") << MSG_256_37 << QStringList(USERS_100.mid(0, 75));
    QTest::newRow("256 chars / 37 words / 100 users") << MSG_256_37 << USERS_100;
    QTest::newRow("256 chars / 37 words / 200 users") << MSG_256_37 << USERS_100 + USERS_UC;

    QTest::newRow("512 chars / 75 words / 0 users")  << MSG_512_75 << QStringList();
    QTest::newRow("512 chars / 75 words / 25 users") << MSG_512_75 << QStringList(USERS_100.mid(0, 25));
    QTest::newRow("512 chars / 75 words / 50 users") << MSG_512_75 << QStringList(USERS_100.mid(0, 50));
    QTest::newRow("512 chars / 75 words / 75 users") << MSG_512_75 << QStringList(USERS_100.mid(0, 75));
    QTest::newRow("512 chars / 75 words / 100 users") << MSG_512_75 << USERS_100;
    QTest::newRow("512 chars / 75 words / 200 users") << MSG_512_75 << USERS_100 + USERS_UC;
}

void tst_MessageFormatter::testFormatHtml()
{
    QFETCH(QString, message);
    QFETCH(QStringList, users);

    Session session;
    TestUserModel model(&session);
    model.addUsers(users);
    QCOMPARE(model.rowCount(), users.count());

    IrcMessage dummy;
    formatter.formatMessage(&dummy, &model);

    QBENCHMARK {
        formatter.formatHtml(message);
    }
}

QTEST_MAIN(tst_MessageFormatter)

#include "tst_messageformatter.moc"
<commit_msg>Fix tst_messageformatter build failure<commit_after>/*
 * Copyright (C) 2008-2013 J-P Nurmi <jpnurmi@gmail.com>
 *
 * This test is free, and not covered by LGPL license. There is no
 * restriction applied to their modification, redistribution, using and so on.
 * You can study them, modify them, use them in your own program - either
 * completely or partially. By using it you may give me some credits in your
 * program, but you don't have to.
 */

#include "messageformatter.h"
#include "usermodel.h"
#include "session.h"
#include <QtTest/QtTest>
#include <QtCore/QStringList>

static const QString MSG_32_5("Vestibulum eu libero eget metus.");
static const QString MSG_64_9("Phasellus enim dui, sodales sed tincidunt quis, ultricies metus.");
static const QString MSG_128_19("Ut porttitor volutpat tristique. Aenean semper ligula eget nulla condimentum tempor in quis felis. Sed sem diam, tincidunt amet.");
static const QString MSG_256_37("Vestibulum quis lorem velit, a varius augue. Suspendisse risus augue, ultricies at convallis in, elementum in velit. Fusce fermentum congue augue sit amet dapibus. Fusce ultrices urna ut tortor laoreet a aliquet elit lobortis. Suspendisse volutpat posuere.");
static const QString MSG_512_75("Nam leo risus, accumsan a sagittis eget, posuere eu velit. Morbi mattis auctor risus, vel consequat massa pulvinar nec. Proin aliquam convallis elit nec egestas. Pellentesque accumsan placerat augue, id volutpat nibh dictum vel. Aenean venenatis varius feugiat. Nullam molestie, ipsum id dignissim vulputate, eros urna vestibulum massa, in vehicula lacus nisi vitae risus. Ut nunc nunc, venenatis a mattis auctor, dictum et sem. Nulla posuere libero ut tortor elementum egestas. Aliquam egestas suscipit posuere.");

static const QStringList USERS_100 = QStringList()
                                     << "jpnurmi" << "Curabitur" << "nORMAL" << "leo" << "luctus"
                                     << "luctus" << "paraply" << "sapien" << "nope" << "vitae"
                                     << "where" << "alien" << "urna" << "turpis" << "rea_son"
                                     << "alone" << "velit" << "jipsu" << "rutrum" << "DiSCO"
                                     << "abort" << "venue" << "__duis__" << "eros" << "adam"
                                     << "hendrix" << "liber0" << "Jim" << "Leonardo" << "JiMi"
                                     << "justin" << "semper" << "fidelis" << "Excelsior" << "parachute"
                                     << "nam" << "nom" << "Lorem" << "risus" << "stereo"
                                     << "tv" << "what-ever" << "kill" << "savior" << "[haha]"
                                     << "null" << "nill" << "will" << "still" << "ill"
                                     << "fill" << "hill" << "bill" << "Lucas" << "metus"
                                     << "bitch" << "d0nut" << "perverT" << "br0tha" << "WHYZ"
                                     << "Amen" << "hero" << "another" << "other" << "augue"
                                     << "Vestibulum" << "quit" << "quis" << "Luis" << "luiz"
                                     << "Luigi" << "anus" << "formal" << "f00bar" << "sed"
                                     << "sodales" << "phasellus" << "port" << "porttitor" << "absolute"
                                     << "varius" << "Marius" << "access" << "ZzZzZz" << "dust"
                                     << "up" << "d0wn" << "l3ft" << "r1ght" << "n0ne"
                                     << "MeSsAgE" << "FoRmAtTeR" << "c00l" << "_[KiDDO]_" << "yes"
                                     << "no" << "never" << "tincidunt" << "ultricies" << "posuere";

class TestMessageFormatter : public MessageFormatter
{
    friend class tst_MessageFormatter;
};

class TestUserModel : public UserModel
{
    friend class tst_MessageFormatter;
public:
    TestUserModel(Session* session) : UserModel(session) { }
};

class tst_MessageFormatter : public QObject
{
    Q_OBJECT

private slots:
    void testFormatHtml_data();
    void testFormatHtml();

private:
    TestMessageFormatter formatter;
};

Q_DECLARE_METATYPE(QStringList)
void tst_MessageFormatter::testFormatHtml_data()
{
    qRegisterMetaType<QStringList>();

    QStringList USERS_UC;
    foreach (const QString& user, USERS_100)
        USERS_UC += user.toUpper();

    QTest::addColumn<QString>("message");
    QTest::addColumn<QStringList>("users");

    QTest::newRow("empty") << QString() << QStringList();

    QTest::newRow("32 chars / 5 words / 0 users") << MSG_32_5 << QStringList();
    QTest::newRow("32 chars / 5 words / 25 users") << MSG_32_5 << QStringList(USERS_100.mid(0, 25));
    QTest::newRow("32 chars / 5 words / 50 users") << MSG_32_5 << QStringList(USERS_100.mid(0, 50));
    QTest::newRow("32 chars / 5 words / 75 users") << MSG_32_5 << QStringList(USERS_100.mid(0, 75));
    QTest::newRow("32 chars / 5 words / 100 users") << MSG_32_5 << USERS_100;
    QTest::newRow("32 chars / 5 words / 200 users") << MSG_32_5 << USERS_100 + USERS_UC;

    QTest::newRow("64 chars / 9 words / 0 users")  << MSG_64_9 << QStringList();
    QTest::newRow("64 chars / 9 words / 25 users") << MSG_64_9 << QStringList(USERS_100.mid(0, 25));
    QTest::newRow("64 chars / 9 words / 50 users") << MSG_64_9 << QStringList(USERS_100.mid(0, 50));
    QTest::newRow("64 chars / 9 words / 75 users") << MSG_64_9 << QStringList(USERS_100.mid(0, 75));
    QTest::newRow("64 chars / 9 words / 100 users") << MSG_64_9 << USERS_100;
    QTest::newRow("64 chars / 9 words / 200 users") << MSG_64_9 << USERS_100 + USERS_UC;

    QTest::newRow("128 chars / 19 words / 0 users")  << MSG_128_19 << QStringList();
    QTest::newRow("128 chars / 19 words / 25 users") << MSG_128_19 << QStringList(USERS_100.mid(0, 25));
    QTest::newRow("128 chars / 19 words / 50 users") << MSG_128_19 << QStringList(USERS_100.mid(0, 50));
    QTest::newRow("128 chars / 19 words / 75 users") << MSG_128_19 << QStringList(USERS_100.mid(0, 75));
    QTest::newRow("128 chars / 19 words / 100 users") << MSG_128_19 << USERS_100;
    QTest::newRow("128 chars / 19 words / 200 users") << MSG_128_19 << USERS_100 + USERS_UC;

    QTest::newRow("256 chars / 37 words / 0 users")  << MSG_256_37 << QStringList();
    QTest::newRow("256 chars / 37 words / 25 users") << MSG_256_37 << QStringList(USERS_100.mid(0, 25));
    QTest::newRow("256 chars / 37 words / 50 users") << MSG_256_37 << QStringList(USERS_100.mid(0, 50));
    QTest::newRow("256 chars / 37 words / 75 users") << MSG_256_37 << QStringList(USERS_100.mid(0, 75));
    QTest::newRow("256 chars / 37 words / 100 users") << MSG_256_37 << USERS_100;
    QTest::newRow("256 chars / 37 words / 200 users") << MSG_256_37 << USERS_100 + USERS_UC;

    QTest::newRow("512 chars / 75 words / 0 users")  << MSG_512_75 << QStringList();
    QTest::newRow("512 chars / 75 words / 25 users") << MSG_512_75 << QStringList(USERS_100.mid(0, 25));
    QTest::newRow("512 chars / 75 words / 50 users") << MSG_512_75 << QStringList(USERS_100.mid(0, 50));
    QTest::newRow("512 chars / 75 words / 75 users") << MSG_512_75 << QStringList(USERS_100.mid(0, 75));
    QTest::newRow("512 chars / 75 words / 100 users") << MSG_512_75 << USERS_100;
    QTest::newRow("512 chars / 75 words / 200 users") << MSG_512_75 << USERS_100 + USERS_UC;
}

void tst_MessageFormatter::testFormatHtml()
{
    QFETCH(QString, message);
    QFETCH(QStringList, users);

    Session session;
    TestUserModel model(&session);
    model.addUsers(users);
    QCOMPARE(model.rowCount(), users.count());

    IrcMessage* dummy = new IrcMessage(&session);
    formatter.formatMessage(dummy, &model);

    QBENCHMARK {
        formatter.formatHtml(message);
    }
}

QTEST_MAIN(tst_MessageFormatter)

#include "tst_messageformatter.moc"
<|endoftext|>