<commit_before>//===--- Errors.cpp - Error reporting utilities ---------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Utilities for reporting errors to stderr, system console, and crash logs.
//
//===----------------------------------------------------------------------===//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <pthread.h>
#include <stdarg.h>
#include "swift/Runtime/Debug.h"
#include "swift/Runtime/Mutex.h"
#include "swift/Basic/Demangle.h"
#include <cxxabi.h>
#if !defined(__CYGWIN__) && !defined(__ANDROID__)
// execinfo.h is not available on Android. Checks in this file ensure that
// fatalError behaves as expected, but without stack traces.
#include <execinfo.h>
#endif

#ifdef __APPLE__
#include <asl.h>
#endif

namespace FatalErrorFlags {
enum: uint32_t {
  ReportBacktrace = 1 << 0
};
} // end namespace FatalErrorFlags

#if !defined(__CYGWIN__) && !defined(__ANDROID__)
LLVM_ATTRIBUTE_ALWAYS_INLINE
static bool
isIdentifier(char c)
{
  return isalnum(c) || c == '_' || c == '$';
}

static bool
demangledLinePrefix(std::string line, std::string prefix,
                    std::string &out,
                    bool (*demangle)(std::string, std::string &))
{
  int symbolStart = -1;
  int symbolEnd = -1;

  for (size_t i = 0; i < line.size(); i++) {
    char c = line[i];

    bool hasBegun = symbolStart != -1;
    bool isIdentifierChar = isIdentifier(c);
    bool isEndOfSymbol = hasBegun && !isIdentifierChar;
    bool isEndOfLine = i == line.size() - 1;

    if (isEndOfLine || isEndOfSymbol) {
      symbolEnd = i;
      break;
    }

    bool canFindPrefix = (line.size() - 2) - i > prefix.size();
    if (!hasBegun && canFindPrefix && !isIdentifierChar &&
        line.substr(i + 1, prefix.size()) == prefix) {
      symbolStart = i + 1;
      continue;
    }
  }

  if (symbolStart == -1 || symbolEnd == -1) {
    out = line;
    return false;
  } else {
    auto symbol = line.substr(symbolStart, symbolEnd - symbolStart);

    std::string demangled;
    bool success = demangle(symbol, demangled);

    if (success) {
      line.replace(symbolStart, symbolEnd - symbolStart, demangled);
    }

    out = line;

    return success;
  }
}

static std::string
demangledLine(std::string line) {
  std::string res;
  bool success = false;
  auto cppPrefix = "_Z"; // not sure how to check for DARWIN's __Z here.
  success = demangledLinePrefix(line, cppPrefix, res,
                                [](std::string symbol, std::string &out) {
    int status;
    auto demangled = abi::__cxa_demangle(symbol.c_str(), 0, 0, &status);
    if (demangled == NULL || status != 0) {
      out = symbol;
      return false;
    } else {
      out = demangled;
      free(demangled);
      return true;
    }
  });
  if (success) return res;
  success = demangledLinePrefix(line, "_T", res,
                                [](std::string symbol, std::string &out) {
    out = swift::Demangle::demangleSymbolAsString(symbol);
    return true;
  });
  if (success) return res;
  return line;
}

const int STACK_DEPTH = 128;

static char **
reportBacktrace(int *count)
{
  void **addrs = (void **)malloc(sizeof(void *) * STACK_DEPTH);
  if (addrs == NULL) {
    if (count) *count = 0;
    return NULL;
  }
  int symbolCount = backtrace(addrs, STACK_DEPTH);
  if (count) *count = symbolCount;

  char **symbols = backtrace_symbols(addrs, symbolCount);
  free(addrs);
  if (symbols == NULL) {
    if (count) *count = 0;
    return NULL;
  }

  return symbols;
}
#endif

#ifdef SWIFT_HAVE_CRASHREPORTERCLIENT
#include <malloc/malloc.h>

// Instead of linking to CrashReporterClient.a (because it complicates the
// build system), define the only symbol from that static archive ourselves.
//
// The layout of this struct is CrashReporter ABI, so there are no ABI concerns
// here.
extern "C" {
CRASH_REPORTER_CLIENT_HIDDEN
struct crashreporter_annotations_t gCRAnnotations
    __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) = {
        CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0, 0};
}

// Report a message to any forthcoming crash log.
static void
reportOnCrash(uint32_t flags, const char *message)
{
  // We must use an "unsafe" mutex in this pathway since the normal "safe"
  // mutex calls fatalError when an error is detected and fatalError ends up
  // calling us. In other words we could get infinite recursion if the
  // mutex errors.
  static swift::StaticUnsafeMutex crashlogLock();

  crashlogLock.lock();

  char *oldMessage = (char *)CRGetCrashLogMessage();
  char *newMessage;
  if (oldMessage) {
    asprintf(&newMessage, "%s%s", oldMessage, message);
    if (malloc_size(oldMessage)) free(oldMessage);
  } else {
    newMessage = strdup(message);
  }

  CRSetCrashLogMessage(newMessage);

  crashlogLock.unlock();
}

#else

static void
reportOnCrash(uint32_t flags, const char *message)
{
  // empty
}

#endif

// Report a message to system console and stderr.
static void
reportNow(uint32_t flags, const char *message)
{
  write(STDERR_FILENO, message, strlen(message));
#ifdef __APPLE__
  asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s", message);
#endif
#if !defined(__CYGWIN__) && !defined(__ANDROID__)
  if (flags & FatalErrorFlags::ReportBacktrace) {
    fputs("Current stack trace:\n", stderr);
    int count = 0;
    char **trace = reportBacktrace(&count);
    for (int i = 0; i < count; i++) {
      fprintf(stderr, "%s\n", demangledLine(trace[i]).c_str());
    }
    free(trace);
  }
#endif
}

/// Report a fatal error to system console, stderr, and crash logs.
/// Does not crash by itself.
void swift::swift_reportError(uint32_t flags,
                              const char *message) {
  reportNow(flags, message);
  reportOnCrash(flags, message);
}

// Report a fatal error to system console, stderr, and crash logs, then abort.
LLVM_ATTRIBUTE_NORETURN
void
swift::fatalError(uint32_t flags, const char *format, ...)
{
  va_list args;
  va_start(args, format);

  char *log;
  vasprintf(&log, format, args);

  swift_reportError(flags, log);
  abort();
}

// Crash when a deleted method is called by accident.
SWIFT_RUNTIME_EXPORT
LLVM_ATTRIBUTE_NORETURN
extern "C" void
swift_deletedMethodError() {
  swift::fatalError(/* flags = */ 0,
                    "fatal error: call of deleted method\n");
}
<commit_msg>Resolve ambiguity in mutex declaration<commit_after>//===--- Errors.cpp - Error reporting utilities ---------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Utilities for reporting errors to stderr, system console, and crash logs.
//
//===----------------------------------------------------------------------===//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <pthread.h>
#include <stdarg.h>
#include "swift/Runtime/Debug.h"
#include "swift/Runtime/Mutex.h"
#include "swift/Basic/Demangle.h"
#include <cxxabi.h>
#if !defined(__CYGWIN__) && !defined(__ANDROID__)
// execinfo.h is not available on Android. Checks in this file ensure that
// fatalError behaves as expected, but without stack traces.
#include <execinfo.h>
#endif

#ifdef __APPLE__
#include <asl.h>
#endif

namespace FatalErrorFlags {
enum: uint32_t {
  ReportBacktrace = 1 << 0
};
} // end namespace FatalErrorFlags

#if !defined(__CYGWIN__) && !defined(__ANDROID__)
LLVM_ATTRIBUTE_ALWAYS_INLINE
static bool
isIdentifier(char c)
{
  return isalnum(c) || c == '_' || c == '$';
}

static bool
demangledLinePrefix(std::string line, std::string prefix,
                    std::string &out,
                    bool (*demangle)(std::string, std::string &))
{
  int symbolStart = -1;
  int symbolEnd = -1;

  for (size_t i = 0; i < line.size(); i++) {
    char c = line[i];

    bool hasBegun = symbolStart != -1;
    bool isIdentifierChar = isIdentifier(c);
    bool isEndOfSymbol = hasBegun && !isIdentifierChar;
    bool isEndOfLine = i == line.size() - 1;

    if (isEndOfLine || isEndOfSymbol) {
      symbolEnd = i;
      break;
    }

    bool canFindPrefix = (line.size() - 2) - i > prefix.size();
    if (!hasBegun && canFindPrefix && !isIdentifierChar &&
        line.substr(i + 1, prefix.size()) == prefix) {
      symbolStart = i + 1;
      continue;
    }
  }

  if (symbolStart == -1 || symbolEnd == -1) {
    out = line;
    return false;
  } else {
    auto symbol = line.substr(symbolStart, symbolEnd - symbolStart);

    std::string demangled;
    bool success = demangle(symbol, demangled);

    if (success) {
      line.replace(symbolStart, symbolEnd - symbolStart, demangled);
    }

    out = line;

    return success;
  }
}

static std::string
demangledLine(std::string line) {
  std::string res;
  bool success = false;
  auto cppPrefix = "_Z"; // not sure how to check for DARWIN's __Z here.
  success = demangledLinePrefix(line, cppPrefix, res,
                                [](std::string symbol, std::string &out) {
    int status;
    auto demangled = abi::__cxa_demangle(symbol.c_str(), 0, 0, &status);
    if (demangled == NULL || status != 0) {
      out = symbol;
      return false;
    } else {
      out = demangled;
      free(demangled);
      return true;
    }
  });
  if (success) return res;
  success = demangledLinePrefix(line, "_T", res,
                                [](std::string symbol, std::string &out) {
    out = swift::Demangle::demangleSymbolAsString(symbol);
    return true;
  });
  if (success) return res;
  return line;
}

const int STACK_DEPTH = 128;

static char **
reportBacktrace(int *count)
{
  void **addrs = (void **)malloc(sizeof(void *) * STACK_DEPTH);
  if (addrs == NULL) {
    if (count) *count = 0;
    return NULL;
  }
  int symbolCount = backtrace(addrs, STACK_DEPTH);
  if (count) *count = symbolCount;

  char **symbols = backtrace_symbols(addrs, symbolCount);
  free(addrs);
  if (symbols == NULL) {
    if (count) *count = 0;
    return NULL;
  }

  return symbols;
}
#endif

#ifdef SWIFT_HAVE_CRASHREPORTERCLIENT
#include <malloc/malloc.h>

// Instead of linking to CrashReporterClient.a (because it complicates the
// build system), define the only symbol from that static archive ourselves.
//
// The layout of this struct is CrashReporter ABI, so there are no ABI concerns
// here.
extern "C" {
CRASH_REPORTER_CLIENT_HIDDEN
struct crashreporter_annotations_t gCRAnnotations
    __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) = {
        CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0, 0};
}

// Report a message to any forthcoming crash log.
static void
reportOnCrash(uint32_t flags, const char *message)
{
  // We must use an "unsafe" mutex in this pathway since the normal "safe"
  // mutex calls fatalError when an error is detected and fatalError ends up
  // calling us. In other words we could get infinite recursion if the
  // mutex errors.
  static swift::StaticUnsafeMutex crashlogLock;

  crashlogLock.lock();

  char *oldMessage = (char *)CRGetCrashLogMessage();
  char *newMessage;
  if (oldMessage) {
    asprintf(&newMessage, "%s%s", oldMessage, message);
    if (malloc_size(oldMessage)) free(oldMessage);
  } else {
    newMessage = strdup(message);
  }

  CRSetCrashLogMessage(newMessage);

  crashlogLock.unlock();
}

#else

static void
reportOnCrash(uint32_t flags, const char *message)
{
  // empty
}

#endif

// Report a message to system console and stderr.
static void
reportNow(uint32_t flags, const char *message)
{
  write(STDERR_FILENO, message, strlen(message));
#ifdef __APPLE__
  asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s", message);
#endif
#if !defined(__CYGWIN__) && !defined(__ANDROID__)
  if (flags & FatalErrorFlags::ReportBacktrace) {
    fputs("Current stack trace:\n", stderr);
    int count = 0;
    char **trace = reportBacktrace(&count);
    for (int i = 0; i < count; i++) {
      fprintf(stderr, "%s\n", demangledLine(trace[i]).c_str());
    }
    free(trace);
  }
#endif
}

/// Report a fatal error to system console, stderr, and crash logs.
/// Does not crash by itself.
void swift::swift_reportError(uint32_t flags,
                              const char *message) {
  reportNow(flags, message);
  reportOnCrash(flags, message);
}

// Report a fatal error to system console, stderr, and crash logs, then abort.
LLVM_ATTRIBUTE_NORETURN
void
swift::fatalError(uint32_t flags, const char *format, ...)
{
  va_list args;
  va_start(args, format);

  char *log;
  vasprintf(&log, format, args);

  swift_reportError(flags, log);
  abort();
}

// Crash when a deleted method is called by accident.
SWIFT_RUNTIME_EXPORT
LLVM_ATTRIBUTE_NORETURN
extern "C" void
swift_deletedMethodError() {
  swift::fatalError(/* flags = */ 0,
                    "fatal error: call of deleted method\n");
}
<|endoftext|>


<commit_before>//===-- ipcd.cpp ----------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Implements IPCD interface, communicates with ipcd via control socket
//
//===----------------------------------------------------------------------===//

#include "ipcd.h"

#include "debug.h"
#include "real.h"
#include "rename_fd.h"
#include "magic_socket_nums.h"
#include "lock.h"

#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>

static int ipcd_socket = 0;
static int mypid = 0;

// Must match that used by server,
// currently defined in ipcd/clients.go
const char *SOCK_PATH = "/tmp/ipcd.sock";
const char *IPCD_BIN_PATH = "/bin/ipcd";

const useconds_t SLEEP_AFTER_IPCD_START_INTERVAL = 10 * 1000; // 10ms?

SimpleLock &getConnectLock() {
  static SimpleLock ConnectLock;
  return ConnectLock;
}

bool we_are_ipcd;

void check_if_we_are_ipcd() {
  // man 3 program_invocation_name
  extern char *program_invocation_short_name;
  assert(program_invocation_short_name);

  ipclog("program_invocation_short_name: %s\n", program_invocation_short_name);

  we_are_ipcd = strcmp("ipcd", program_invocation_short_name) == 0;
}

void start_ipcd() {
  int d = daemon(0, 0);
  if (d == -1) {
    perror("Failed to daemonize");
    exit(1);
  }

  execl(IPCD_BIN_PATH, IPCD_BIN_PATH, (char *)NULL);
  perror("Failed to exec ipcd");
  exit(1);
}

void fork_ipcd() {
  switch (__real_fork()) {
  case -1:
    break;
  case 0:
    // Child
    start_ipcd();
    assert(0 && "Exec failed?");
    break;
  default:
    // Wait for ipcd to start :P
    ipclog("Starting ipcd...\n");
  }
}

void connect_to_ipcd() {
  int s, len;
  struct sockaddr_un remote;

  if ((s = __real_socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) {
    perror("socket");
    exit(1);
  }
  bool rename_success = rename_fd(s, MAGIC_SOCKET_FD, /* cloexec */ true);
  assert(rename_success);
  s = MAGIC_SOCKET_FD;

  remote.sun_family = AF_UNIX;
  strcpy(remote.sun_path, SOCK_PATH);
  len = strlen(remote.sun_path) + sizeof(remote.sun_family);
  if (__real_connect(s, (struct sockaddr *)&remote, len) == -1) {
    // XXX: Super kludge!
    // If we can't connect to daemon, assume it hasn't been
    // started yet and attempt to run it ourselves.
    // This code is terrible, and is likely to break
    // badly in many situations, but works for now.
    if (errno == ENOENT || errno == ECONNREFUSED) {
      fork_ipcd();

      int attempts = 0;
      const int MAX_ATTEMPTS = 10;
      while (attempts < MAX_ATTEMPTS) {
        usleep(SLEEP_AFTER_IPCD_START_INTERVAL);
        if (__real_connect(s, (struct sockaddr *)&remote, len) != -1)
          break;
        ++attempts;
      }
      if (attempts == MAX_ATTEMPTS) {
        perror("Unable to connect to ipcd after attempting to start it");
        exit(1);
      }
    } else {
      // Race with socket creation and permissions, maybe?
      ipclog("Connect failed, attempting a few more times...\n");
      int attempts = 0;
      const int MAX_ATTEMPTS = 10;
      while (attempts < MAX_ATTEMPTS) {
        usleep(SLEEP_AFTER_IPCD_START_INTERVAL);
        if (__real_connect(s, (struct sockaddr *)&remote, len) != -1)
          break;
        ++attempts;
      }
      if (attempts == MAX_ATTEMPTS) {
        perror("Connect to ipcd socket");
        ipclog("Error connecting to ipcd?\n");
        exit(1);
      }
    }
  }

  ipclog("Connected to IPCD, fd=%d\n", s);
  mypid = getpid();
  ipcd_socket = s;
}

void __ipcd_init() {
  assert(ipcd_socket == 0);
  check_if_we_are_ipcd();
  if (ipcd_enabled())
    connect_to_ipcd();
}

void __attribute__((destructor)) ipcd_dtor() {
  ipclog("ipcd_dtor()!\n");
  if (ipcd_socket == 0) {
    ipclog("Exiting without establishing connection to ipcd...\n");
    return;
  }
  assert(ipcd_socket != 0);
  assert(mypid != 0);

  // TODO: REMOVEALL is goodness, but we don't presently
  // correctly associate PID's with endpoints they own in ipcd.
  // Partially due to the mechanism for REREGISTER being
  // performed 'eagerly' before the child PID is known,
  // and partially due to a need to update ipcd's datastructures.

  // This needs to be done eventually anyway, to provide
  // access control restrictions on who can unregister,
  // optimize, etc. a given endpoint.

  // For now, explicitly unregister all endpoints we know we own.
  // XXX: This is done in ipcopt.cpp since this code
  // doesn't have access to our state table, just ipcd.

  // Return instead of REMOVEALL to avoid
  // duplicate UNREGISTER.
  return;

  char buf[100];
  int len = sprintf(buf, "REMOVEALL %d\n", mypid);
  assert(len > 5);
  int err = __real_send(ipcd_socket, buf, len, MSG_NOSIGNAL);
  if (err < 0) {
    ipclog("Error sending ipcd REMOVEALL command in dtor: %s\n",
           strerror(errno));
    return;
  }
  err = __real_recv(ipcd_socket, buf, 50, MSG_NOSIGNAL);
  assert(err > 5);

  const char *match = "200 REMOVED ";
  size_t matchlen = strlen(match);
  if (size_t(err) < matchlen) {
    ipclog("Error receiving response from ipcd in dtor: %s\n", strerror(errno));
    return;
  }
  bool success = (strncmp(buf, "200 REMOVED ", matchlen) == 0);
  if (!success) {
    ipclog("Failure, response=%s\n", buf);
  }
  if (success)
    ipclog("Successfully unregistered all fd's\n");
  else
    ipclog("Failed to remove all fd's\n");
}

void connect_if_needed() {
  if (mypid == getpid())
    return;

  ipclog("Reconnecting to ipcd in child...\n");
  __real_close(ipcd_socket);
  connect_to_ipcd();
}

endpoint ipcd_register_socket(int fd) {
  ScopedLock L(getConnectLock());
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "REGISTER %d %d\n", getpid(), fd);
  assert(len > 5);

  assert(ipcd_socket);
  // ipclog("REGISTER %d -->\n", fd);
  int err = __real_send(ipcd_socket, buf, len, MSG_NOSIGNAL);
  if (err < 0) {
    perror("write");
    exit(1);
  }

  // ipclog("REGISTER %d <--\n", fd);
  err = __real_recv(ipcd_socket, buf, 50, MSG_NOSIGNAL);
  assert(err > 5);

  buf[err] = 0;
  int id;
  int n = sscanf(buf, "200 ID %d\n", &id);
  assert(n == 1);

  // ipclog("Registered and got endpoint id=%d\n", id);

  return id;
}

bool ipcd_localize(endpoint local, endpoint remote) {
  ScopedLock L(getConnectLock());
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "LOCALIZE %d %d\n", local, remote);
  assert(len > 5);
  int err = __real_send(ipcd_socket, buf, len, MSG_NOSIGNAL);
  if (err < 0) {
    perror("write");
    exit(1);
  }
  err = __real_recv(ipcd_socket, buf, 50, MSG_NOSIGNAL);
  assert(err > 5);

  return strncmp(buf, "200 OK\n", err) == 0;
}

// GETLOCALFD
int ipcd_getlocalfd(endpoint local) {
  ScopedLock L(getConnectLock());
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "GETLOCALFD %d\n", local);
  assert(len > 5);
  int err = __real_send(ipcd_socket, buf, len, MSG_NOSIGNAL);
  if (err < 0) {
    perror("write");
    exit(1);
  }

  int fd;
  {
    // Lots of magic
    const size_t CONTROLLEN = CMSG_LEN(sizeof(int));
    struct iovec iov[1];
    struct msghdr msg;
    struct cmsghdr *cmsg;
    char cmsg_buf[CONTROLLEN];
    cmsg = (struct cmsghdr *)cmsg_buf;

    memset(&msg, 0, sizeof(msg));

    iov[0].iov_base = buf;
    iov[0].iov_len = sizeof(buf);
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;
    msg.msg_control = cmsg;
    msg.msg_controllen = CONTROLLEN;

    int ret = __real_recvmsg(ipcd_socket, &msg, MSG_NOSIGNAL);
    if (ret <= 0) {
      perror("recvmsg");
      exit(1);
    }

    // TODO: Understand and fix mismatch between
    // CONTROLLEN and msg.msg_controllen after recvmsg()!
    memcpy(&fd, CMSG_DATA(cmsg), sizeof(int));
    ipclog("received local fd %d for endpoint %d\n", fd, local);
  }

  err = __real_recv(ipcd_socket, buf, 50, MSG_NOSIGNAL);
  assert(err > 5);

  bool success = strncmp(buf, "200 OK\n", err) == 0;
  assert(success);

  return fd;
}

// UNREGISTER
bool ipcd_unregister_socket(endpoint ep) {
  ScopedLock L(getConnectLock());
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "UNREGISTER %d\n", ep);
  assert(len > 5);
  int err = __real_send(ipcd_socket, buf, len, MSG_NOSIGNAL);
  if (err < 0) {
    perror("write");
    exit(1);
  }
  err = __real_recv(ipcd_socket, buf, 50, MSG_NOSIGNAL);
  assert(err > 5);

  return strncmp(buf, "200 OK\n", err) == 0;
}

// REREGISTER
bool ipcd_reregister_socket(endpoint ep, int fd) {
  ScopedLock L(getConnectLock());
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "REREGISTER %d %d %d\n", ep, getpid(), fd);
  assert(len > 5);
  int err = __real_send(ipcd_socket, buf, len, MSG_NOSIGNAL);
  if (err < 0) {
    perror("write");
    exit(1);
  }
  err = __real_recv(ipcd_socket, buf, 50, MSG_NOSIGNAL);
  assert(err > 5);

  return strncmp(buf, "200 OK\n", err) == 0;
}

endpoint ipcd_endpoint_kludge(endpoint local) {
  ScopedLock L(getConnectLock());
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "ENDPOINT_KLUDGE %d\n", local);
  assert(len > 5);
  int err = __real_send(ipcd_socket, buf, len, MSG_NOSIGNAL);
  if (err < 0) {
    perror("write");
    exit(1);
  }
  err = __real_recv(ipcd_socket, buf, 50, MSG_NOSIGNAL);
  assert(err > 5);

  buf[err] = 0;
  int id;
  ipclog("endpoint_kludge(%d) = %s\n", local, buf);
  int n = sscanf(buf, "200 PAIR %d\n", &id);
  if (n == 1) {
    return id;
  }

  return EP_INVALID;
}

endpoint ipcd_crc_kludge(endpoint local, uint32_t s_crc, uint32_t r_crc,
                         bool last) {
  ScopedLock L(getConnectLock());
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "THRESH_CRC_KLUDGE %d %d %d %d\n", local, s_crc, r_crc,
                    last ? 1 : 0);
  assert(len > 5);
  int err = __real_send(ipcd_socket, buf, len, MSG_NOSIGNAL);
  if (err < 0) {
    perror("write");
    exit(1);
  }
  err = __real_recv(ipcd_socket, buf, 50, MSG_NOSIGNAL);
  assert(err > 5);

  buf[err] = 0;
  int id;
  ipclog("crc_kludge(%d, %d, %d) = %s\n", local, s_crc, r_crc, buf);
  int n = sscanf(buf, "200 PAIR %d\n", &id);
  if (n == 1) {
    return id;
  }

  return EP_INVALID;
}

bool ipcd_is_protected(int fd) {
  return fd == ipcd_socket;
}

bool ipcd_enabled() {
  static bool disabled = getenv("IPCD_DISABLE") || we_are_ipcd;
  return !disabled;
}
<commit_msg>libipc: Be sure lock is released if assert fails or we exit.<commit_after>//===-- ipcd.cpp ----------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Implements IPCD interface, communicates with ipcd via control socket
//
//===----------------------------------------------------------------------===//

#include "ipcd.h"

#include "debug.h"
#include "real.h"
#include "rename_fd.h"
#include "magic_socket_nums.h"
#include "lock.h"

#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>

static int ipcd_socket = 0;
static int mypid = 0;

// Must match that used by server,
// currently defined in ipcd/clients.go
const char *SOCK_PATH = "/tmp/ipcd.sock";
const char *IPCD_BIN_PATH = "/bin/ipcd";

const useconds_t SLEEP_AFTER_IPCD_START_INTERVAL = 10 * 1000; // 10ms?

SimpleLock &getConnectLock() {
  static SimpleLock ConnectLock;
  return ConnectLock;
}

#define ASSERT_WITH_LOCK(expr)                                                 \
  ((expr) ? __ASSERT_VOID_CAST(0)                                              \
          : unlock_and_assert_fail(__STRING(expr), __FILE__, __LINE__,         \
                                   __ASSERT_FUNCTION))

void unlock_and_assert_fail(const char *assertion, const char *file,
                              unsigned int line, const char *function) {
  getConnectLock().Unlock();
  __assert_fail(assertion, file, line, function);
}

bool we_are_ipcd;

void check_if_we_are_ipcd() {
  // man 3 program_invocation_name
  extern char *program_invocation_short_name;
  assert(program_invocation_short_name);

  ipclog("program_invocation_short_name: %s\n", program_invocation_short_name);

  we_are_ipcd = strcmp("ipcd", program_invocation_short_name) == 0;
}

void start_ipcd() {
  int d = daemon(0, 0);
  if (d == -1) {
    perror("Failed to daemonize");
    exit(1);
  }

  execl(IPCD_BIN_PATH, IPCD_BIN_PATH, (char *)NULL);
  perror("Failed to exec ipcd");
  exit(1);
}

void fork_ipcd() {
  switch (__real_fork()) {
  case -1:
    break;
  case 0:
    // Child
    start_ipcd();
    assert(0 && "Exec failed?");
    break;
  default:
    // Wait for ipcd to start :P
    ipclog("Starting ipcd...\n");
  }
}

void connect_to_ipcd() {
  int s, len;
  struct sockaddr_un remote;

  if ((s = __real_socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) {
    perror("socket");
    exit(1);
  }
  bool rename_success = rename_fd(s, MAGIC_SOCKET_FD, /* cloexec */ true);
  assert(rename_success);
  s = MAGIC_SOCKET_FD;

  remote.sun_family = AF_UNIX;
  strcpy(remote.sun_path, SOCK_PATH);
  len = strlen(remote.sun_path) + sizeof(remote.sun_family);
  if (__real_connect(s, (struct sockaddr *)&remote, len) == -1) {
    // XXX: Super kludge!
    // If we can't connect to daemon, assume it hasn't been
    // started yet and attempt to run it ourselves.
    // This code is terrible, and is likely to break
    // badly in many situations, but works for now.
    if (errno == ENOENT || errno == ECONNREFUSED) {
      fork_ipcd();

      int attempts = 0;
      const int MAX_ATTEMPTS = 10;
      while (attempts < MAX_ATTEMPTS) {
        usleep(SLEEP_AFTER_IPCD_START_INTERVAL);
        if (__real_connect(s, (struct sockaddr *)&remote, len) != -1)
          break;
        ++attempts;
      }
      if (attempts == MAX_ATTEMPTS) {
        perror("Unable to connect to ipcd after attempting to start it");
        exit(1);
      }
    } else {
      // Race with socket creation and permissions, maybe?
      ipclog("Connect failed, attempting a few more times...\n");
      int attempts = 0;
      const int MAX_ATTEMPTS = 10;
      while (attempts < MAX_ATTEMPTS) {
        usleep(SLEEP_AFTER_IPCD_START_INTERVAL);
        if (__real_connect(s, (struct sockaddr *)&remote, len) != -1)
          break;
        ++attempts;
      }
      if (attempts == MAX_ATTEMPTS) {
        perror("Connect to ipcd socket");
        ipclog("Error connecting to ipcd?\n");
        exit(1);
      }
    }
  }

  ipclog("Connected to IPCD, fd=%d\n", s);
  mypid = getpid();
  ipcd_socket = s;
}

void __ipcd_init() {
  assert(ipcd_socket == 0);
  check_if_we_are_ipcd();
  if (ipcd_enabled())
    connect_to_ipcd();
}

void __attribute__((destructor)) ipcd_dtor() {
  ipclog("ipcd_dtor()!\n");
  if (ipcd_socket == 0) {
    ipclog("Exiting without establishing connection to ipcd...\n");
    return;
  }
  assert(ipcd_socket != 0);
  assert(mypid != 0);

  // TODO: REMOVEALL is goodness, but we don't presently
  // correctly associate PID's with endpoints they own in ipcd.
  // Partially due to the mechanism for REREGISTER being
  // performed 'eagerly' before the child PID is known,
  // and partially due to a need to update ipcd's datastructures.

  // This needs to be done eventually anyway, to provide
  // access control restrictions on who can unregister,
  // optimize, etc. a given endpoint.

  // For now, explicitly unregister all endpoints we know we own.
  // XXX: This is done in ipcopt.cpp since this code
  // doesn't have access to our state table, just ipcd.

  // Return instead of REMOVEALL to avoid
  // duplicate UNREGISTER.
  return;

  char buf[100];
  int len = sprintf(buf, "REMOVEALL %d\n", mypid);
  assert(len > 5);
  int err = __real_send(ipcd_socket, buf, len, MSG_NOSIGNAL);
  if (err < 0) {
    ipclog("Error sending ipcd REMOVEALL command in dtor: %s\n",
           strerror(errno));
    return;
  }
  err = __real_recv(ipcd_socket, buf, 50, MSG_NOSIGNAL);
  assert(err > 5);

  const char *match = "200 REMOVED ";
  size_t matchlen = strlen(match);
  if (size_t(err) < matchlen) {
    ipclog("Error receiving response from ipcd in dtor: %s\n", strerror(errno));
    return;
  }
  bool success = (strncmp(buf, "200 REMOVED ", matchlen) == 0);
  if (!success) {
    ipclog("Failure, response=%s\n", buf);
  }
  if (success)
    ipclog("Successfully unregistered all fd's\n");
  else
    ipclog("Failed to remove all fd's\n");
}

void connect_if_needed() {
  if (mypid == getpid())
    return;

  ipclog("Reconnecting to ipcd in child...\n");
  __real_close(ipcd_socket);
  connect_to_ipcd();
}

endpoint ipcd_register_socket(int fd) {
  ScopedLock L(getConnectLock());
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "REGISTER %d %d\n", getpid(), fd);
  ASSERT_WITH_LOCK(len > 5);

  ASSERT_WITH_LOCK(ipcd_socket);
  // ipclog("REGISTER %d -->\n", fd);
  int err = __real_send(ipcd_socket, buf, len, MSG_NOSIGNAL);
  if (err < 0) {
    perror("write");
    ASSERT_WITH_LOCK(0);
  }

  // ipclog("REGISTER %d <--\n", fd);
  err = __real_recv(ipcd_socket, buf, 50, MSG_NOSIGNAL);
  ASSERT_WITH_LOCK(err > 5);

  buf[err] = 0;
  int id;
  int n = sscanf(buf, "200 ID %d\n", &id);
  ASSERT_WITH_LOCK(n == 1);

  // ipclog("Registered and got endpoint id=%d\n", id);

  return id;
}

bool ipcd_localize(endpoint local, endpoint remote) {
  ScopedLock L(getConnectLock());
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "LOCALIZE %d %d\n", local, remote);
  ASSERT_WITH_LOCK(len > 5);
  int err = __real_send(ipcd_socket, buf, len, MSG_NOSIGNAL);
  if (err < 0) {
    perror("write");
    ASSERT_WITH_LOCK(0);
  }
  err = __real_recv(ipcd_socket, buf, 50, MSG_NOSIGNAL);
  ASSERT_WITH_LOCK(err > 5);

  return strncmp(buf, "200 OK\n", err) == 0;
}

// GETLOCALFD
int ipcd_getlocalfd(endpoint local) {
  ScopedLock L(getConnectLock());
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "GETLOCALFD %d\n", local);
  ASSERT_WITH_LOCK(len > 5);
  int err = __real_send(ipcd_socket, buf, len, MSG_NOSIGNAL);
  if (err < 0) {
    perror("write");
    ASSERT_WITH_LOCK(0);
  }

  int fd;
  {
    // Lots of magic
    const size_t CONTROLLEN = CMSG_LEN(sizeof(int));
    struct iovec iov[1];
    struct msghdr msg;
    struct cmsghdr *cmsg;
    char cmsg_buf[CONTROLLEN];
    cmsg = (struct cmsghdr *)cmsg_buf;

    memset(&msg, 0, sizeof(msg));

    iov[0].iov_base = buf;
    iov[0].iov_len = sizeof(buf);
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;
    msg.msg_control = cmsg;
    msg.msg_controllen = CONTROLLEN;

    int ret = __real_recvmsg(ipcd_socket, &msg, MSG_NOSIGNAL);
    if (ret <= 0) {
      perror("recvmsg");
      ASSERT_WITH_LOCK(0);
    }

    // TODO: Understand and fix mismatch between
    // CONTROLLEN and msg.msg_controllen after recvmsg()!
    memcpy(&fd, CMSG_DATA(cmsg), sizeof(int));
    ipclog("received local fd %d for endpoint %d\n", fd, local);
  }

  err = __real_recv(ipcd_socket, buf, 50, MSG_NOSIGNAL);
  ASSERT_WITH_LOCK(err > 5);

  bool success = strncmp(buf, "200 OK\n", err) == 0;
  ASSERT_WITH_LOCK(success);

  return fd;
}

// UNREGISTER
bool ipcd_unregister_socket(endpoint ep) {
  ScopedLock L(getConnectLock());
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "UNREGISTER %d\n", ep);
  ASSERT_WITH_LOCK(len > 5);
  int err = __real_send(ipcd_socket, buf, len, MSG_NOSIGNAL);
  if (err < 0) {
    perror("write");
    ASSERT_WITH_LOCK(0);
  }
  err = __real_recv(ipcd_socket, buf, 50, MSG_NOSIGNAL);
  ASSERT_WITH_LOCK(err > 5);

  return strncmp(buf, "200 OK\n", err) == 0;
}

// REREGISTER
bool ipcd_reregister_socket(endpoint ep, int fd) {
  ScopedLock L(getConnectLock());
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "REREGISTER %d %d %d\n", ep, getpid(), fd);
  ASSERT_WITH_LOCK(len > 5);
  int err = __real_send(ipcd_socket, buf, len, MSG_NOSIGNAL);
  if (err < 0) {
    perror("write");
    ASSERT_WITH_LOCK(0);
  }
  err = __real_recv(ipcd_socket, buf, 50, MSG_NOSIGNAL);
  ASSERT_WITH_LOCK(err > 5);

  return strncmp(buf, "200 OK\n", err) == 0;
}

endpoint ipcd_endpoint_kludge(endpoint local) {
  ScopedLock L(getConnectLock());
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "ENDPOINT_KLUDGE %d\n", local);
  ASSERT_WITH_LOCK(len > 5);
  int err = __real_send(ipcd_socket, buf, len, MSG_NOSIGNAL);
  if (err < 0) {
    perror("write");
    ASSERT_WITH_LOCK(0);
  }
  err = __real_recv(ipcd_socket, buf, 50, MSG_NOSIGNAL);
  ASSERT_WITH_LOCK(err > 5);

  buf[err] = 0;
  int id;
  ipclog("endpoint_kludge(%d) = %s\n", local, buf);
  int n = sscanf(buf, "200 PAIR %d\n", &id);
  if (n == 1) {
    return id;
  }

  return EP_INVALID;
}

endpoint ipcd_crc_kludge(endpoint local, uint32_t s_crc, uint32_t r_crc,
                         bool last) {
  ScopedLock L(getConnectLock());
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "THRESH_CRC_KLUDGE %d %d %d %d\n", local, s_crc, r_crc,
                    last ? 1 : 0);
  ASSERT_WITH_LOCK(len > 5);
  int err = __real_send(ipcd_socket, buf, len, MSG_NOSIGNAL);
  if (err < 0) {
    perror("write");
    ASSERT_WITH_LOCK(0);
  }
  err = __real_recv(ipcd_socket, buf, 50, MSG_NOSIGNAL);
  ASSERT_WITH_LOCK(err > 5);

  buf[err] = 0;
  int id;
  ipclog("crc_kludge(%d, %d, %d) = %s\n", local, s_crc, r_crc, buf);
  int n = sscanf(buf, "200 PAIR %d\n", &id);
  if (n == 1) {
    return id;
  }

  return EP_INVALID;
}

bool ipcd_is_protected(int fd) {
  return fd == ipcd_socket;
}

bool ipcd_enabled() {
  static bool disabled = getenv("IPCD_DISABLE") || we_are_ipcd;
  return !disabled;
}
<|endoftext|>


<commit_before>//===-- ipcd.cpp ----------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Implements IPCD interface, communicates with ipcd via control socket
//
//===----------------------------------------------------------------------===//

#include "ipcd.h"

#include "debug.h"
// XXX: Shouldn't need to include this for _real_*
#include "socket_inline.h"

#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stropts.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>

static int ipcd_socket = 0;
static int mypid = 0;

// Must match that used by server,
// currently defined in ipcd/clients.go
const char *SOCK_PATH = "/tmp/ipcd.sock";
const char *IPCD_BIN_PATH = "/bin/ipcd";

const char *PRELOAD_PATH = "/etc/ld.so.preload";
const char *PRELOAD_TMP = "/tmp/preload.cfg";

void connect_to_ipcd() {
  int s, t, len;
  struct sockaddr_un remote;

  if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
    perror("socket");
    exit(1);
  }

  remote.sun_family = AF_UNIX;
  strcpy(remote.sun_path, SOCK_PATH);
  len = strlen(remote.sun_path) + sizeof(remote.sun_family);
  if (connect(s, (struct sockaddr *)&remote, len) == -1) {
    if (errno == ENOENT || errno == ECONNREFUSED) {
      rename(PRELOAD_PATH, PRELOAD_TMP);
      switch (fork()) {
      case -1:
        break;
      case 0:
        // Child
        execl(IPCD_BIN_PATH, IPCD_BIN_PATH, 0);
        perror("Failed to exec ipcd");
        assert(0 && "Exec failed?");
        break;
      default:
        // Wait for ipcd to start :P
        ipclog("Starting ipcd...\n");
        sleep(1);
      }
      rename(PRELOAD_TMP, PRELOAD_PATH);
      if (connect(s, (struct sockaddr *)&remote, len) == -1) {
        perror("connect-after-fork");
        exit(1);
      }
    } else {
      perror("connect");
      ipclog("Error connecting to ipcd?\n");
      exit(1);
    }
  }

  ipclog("Connected to IPCD, fd=%d\n", s);
  mypid = getpid();
  ipcd_socket = s;
}

void __attribute__((constructor)) ipcd_init() {
  assert(ipcd_socket == 0);
  connect_to_ipcd();
}

void __attribute__((destructor)) ipcd_dtor() {
  if (ipcd_socket == 0) {
    ipclog("Exiting without establishing connection to ipcd...\n");
    return;
  }
  assert(ipcd_socket != 0);
  assert(mypid != 0);

  char buf[100];
  int len = sprintf(buf, "REMOVEALL %d\n", mypid);
  assert(len > 5);
  int err = __real_write(ipcd_socket, buf, len);
  if (err < 0) {
    perror("write");
    exit(1);
  }
  err = __real_read(ipcd_socket, buf, 50);
  assert(err > 5);

  const char *match = "200 REMOVED ";
  size_t matchlen = strlen(match);
  if (err < matchlen) {
    perror("read");
    exit(1);
  }
  bool success = (strncmp(buf, "200 REMOVED ", matchlen) == 0);
  if (!success) {
    ipclog("Failure, response=%s\n", buf);
  }
  assert(success && "Unable to unregister all fd's");
}

static volatile int connect_lock = 0;
void ipcd_lock() {
  while (__sync_lock_test_and_set(&connect_lock, 1)) {
    // wait
  };
}

void ipcd_unlock() { __sync_lock_release(&connect_lock); }

struct IPCLock {
  IPCLock() { ipcd_lock(); }
  ~IPCLock() { ipcd_unlock(); }
};

void connect_if_needed() {
  if (mypid == getpid())
    return;

  ipclog("Reconnecting to ipcd in child...\n");
  close(ipcd_socket);
  connect_to_ipcd();
}

endpoint ipcd_register_socket(int fd) {
  IPCLock();
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "REGISTER %d %d\n", getpid(), fd);
  assert(len > 5);

  assert(ipcd_socket);
  // ipclog("REGISTER %d -->\n", fd);
  int err = __real_write(ipcd_socket, buf, len);
  if (err < 0) {
    perror("write");
    exit(1);
  }

  // ipclog("REGISTER %d <--\n", fd);
  err = __real_read(ipcd_socket, buf, 50);
  assert(err > 5);

  buf[err] = 0;
  int id;
  int n = sscanf(buf, "200 ID %d\n", &id);
  assert(n == 1);

  // ipclog("Registered and got endpoint id=%d\n", id);

  return id;
}

bool ipcd_localize(endpoint local, endpoint remote) {
  IPCLock();
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "LOCALIZE %d %d\n", local, remote);
  assert(len > 5);
  int err = __real_write(ipcd_socket, buf, len);
  if (err < 0) {
    perror("write");
    exit(1);
  }
  err = __real_read(ipcd_socket, buf, 50);
  assert(err > 5);

  return strncmp(buf, "200 OK\n", err) == 0;
}

// GETLOCALFD
int ipcd_getlocalfd(endpoint local) {
  IPCLock();
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "GETLOCALFD %d\n", local);
  assert(len > 5);
  int err = __real_write(ipcd_socket, buf, len);
  if (err < 0) {
    perror("write");
    exit(1);
  }

  int fd;
  {
    // Lots of magic
    const size_t CONTROLLEN = CMSG_LEN(sizeof(int));
    struct iovec iov[1];
    struct msghdr msg;
    struct cmsghdr *cmsg;
    char cmsg_buf[CONTROLLEN];
    cmsg = (struct cmsghdr *)cmsg_buf;

    memset(&msg, 0, sizeof(msg));

    iov[0].iov_base = buf;
    iov[0].iov_len = sizeof(buf);
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;
    msg.msg_control = cmsg;
    msg.msg_controllen = CONTROLLEN;

    int ret = recvmsg(ipcd_socket, &msg, 0);
    if (ret <= 0) {
      perror("recvmsg");
      exit(1);
    }

    // TODO: Understand and fix mismatch between
    // CONTROLLEN and msg.msg_controllen after recvmsg()!
    fd = *(int *)CMSG_DATA(cmsg);
    ipclog("received local fd %d for endpoint %d\n", fd, local);
  }

  err = __real_read(ipcd_socket, buf, 50);
  assert(err > 5);

  bool success = strncmp(buf, "200 OK\n", err) == 0;
  assert(success);

  return fd;
}

// UNREGISTER
bool ipcd_unregister_socket(endpoint ep) {
  IPCLock();
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "UNREGISTER %d\n", ep);
  assert(len > 5);
  int err = __real_write(ipcd_socket, buf, len);
  if (err < 0) {
    perror("write");
    exit(1);
  }
  err = __real_read(ipcd_socket, buf, 50);
  assert(err > 5);

  return strncmp(buf, "200 OK\n", err) == 0;
}

<commit_msg>Add note ensuring readers are aware of how bad autostarting ipcd is :/<commit_after>//===-- ipcd.cpp ----------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Implements IPCD interface, communicates with ipcd via control socket
//
//===----------------------------------------------------------------------===//

#include "ipcd.h"

#include "debug.h"
// XXX: Shouldn't need to include this for _real_*
#include "socket_inline.h"

#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stropts.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>

static int ipcd_socket = 0;
static int mypid = 0;

// Must match that used by server,
// currently defined in ipcd/clients.go
const char *SOCK_PATH = "/tmp/ipcd.sock";
const char *IPCD_BIN_PATH = "/bin/ipcd";

const char *PRELOAD_PATH = "/etc/ld.so.preload";
const char *PRELOAD_TMP = "/tmp/preload.cfg";

void connect_to_ipcd() {
  int s, t, len;
  struct sockaddr_un remote;

  if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
    perror("socket");
    exit(1);
  }

  remote.sun_family = AF_UNIX;
  strcpy(remote.sun_path, SOCK_PATH);
  len = strlen(remote.sun_path) + sizeof(remote.sun_family);
  if (connect(s, (struct sockaddr *)&remote, len) == -1) {
    // XXX: Super kludge!
    // If we can't connect to daemon, assume it hasn't been
    // started yet and attempt to run it ourselves.
    // This code is terrible, and is likely to break
    // badly in many situations, but works for now.
    if (errno == ENOENT || errno == ECONNREFUSED) {
      rename(PRELOAD_PATH, PRELOAD_TMP);
      switch (fork()) {
      case -1:
        break;
      case 0:
        // Child
        execl(IPCD_BIN_PATH, IPCD_BIN_PATH, 0);
        perror("Failed to exec ipcd");
        assert(0 && "Exec failed?");
        break;
      default:
        // Wait for ipcd to start :P
        ipclog("Starting ipcd...\n");
        sleep(1);
      }
      rename(PRELOAD_TMP, PRELOAD_PATH);
      if (connect(s, (struct sockaddr *)&remote, len) == -1) {
        perror("connect-after-fork");
        exit(1);
      }
    } else {
      perror("connect");
      ipclog("Error connecting to ipcd?\n");
      exit(1);
    }
  }

  ipclog("Connected to IPCD, fd=%d\n", s);
  mypid = getpid();
  ipcd_socket = s;
}

void __attribute__((constructor)) ipcd_init() {
  assert(ipcd_socket == 0);
  connect_to_ipcd();
}

void __attribute__((destructor)) ipcd_dtor() {
  if (ipcd_socket == 0) {
    ipclog("Exiting without establishing connection to ipcd...\n");
    return;
  }
  assert(ipcd_socket != 0);
  assert(mypid != 0);

  char buf[100];
  int len = sprintf(buf, "REMOVEALL %d\n", mypid);
  assert(len > 5);
  int err = __real_write(ipcd_socket, buf, len);
  if (err < 0) {
    perror("write");
    exit(1);
  }
  err = __real_read(ipcd_socket, buf, 50);
  assert(err > 5);

  const char *match = "200 REMOVED ";
  size_t matchlen = strlen(match);
  if (err < matchlen) {
    perror("read");
    exit(1);
  }
  bool success = (strncmp(buf, "200 REMOVED ", matchlen) == 0);
  if (!success) {
    ipclog("Failure, response=%s\n", buf);
  }
  assert(success && "Unable to unregister all fd's");
}

static volatile int connect_lock = 0;
void ipcd_lock() {
  while (__sync_lock_test_and_set(&connect_lock, 1)) {
    // wait
  };
}

void ipcd_unlock() { __sync_lock_release(&connect_lock); }

struct IPCLock {
  IPCLock() { ipcd_lock(); }
  ~IPCLock() { ipcd_unlock(); }
};

void connect_if_needed() {
  if (mypid == getpid())
    return;

  ipclog("Reconnecting to ipcd in child...\n");
  close(ipcd_socket);
  connect_to_ipcd();
}

endpoint ipcd_register_socket(int fd) {
  IPCLock();
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "REGISTER %d %d\n", getpid(), fd);
  assert(len > 5);

  assert(ipcd_socket);
  // ipclog("REGISTER %d -->\n", fd);
  int err = __real_write(ipcd_socket, buf, len);
  if (err < 0) {
    perror("write");
    exit(1);
  }

  // ipclog("REGISTER %d <--\n", fd);
  err = __real_read(ipcd_socket, buf, 50);
  assert(err > 5);

  buf[err] = 0;
  int id;
  int n = sscanf(buf, "200 ID %d\n", &id);
  assert(n == 1);

  // ipclog("Registered and got endpoint id=%d\n", id);

  return id;
}

bool ipcd_localize(endpoint local, endpoint remote) {
  IPCLock();
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "LOCALIZE %d %d\n", local, remote);
  assert(len > 5);
  int err = __real_write(ipcd_socket, buf, len);
  if (err < 0) {
    perror("write");
    exit(1);
  }
  err = __real_read(ipcd_socket, buf, 50);
  assert(err > 5);

  return strncmp(buf, "200 OK\n", err) == 0;
}

// GETLOCALFD
int ipcd_getlocalfd(endpoint local) {
  IPCLock();
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "GETLOCALFD %d\n", local);
  assert(len > 5);
  int err = __real_write(ipcd_socket, buf, len);
  if (err < 0) {
    perror("write");
    exit(1);
  }

  int fd;
  {
    // Lots of magic
    const size_t CONTROLLEN = CMSG_LEN(sizeof(int));
    struct iovec iov[1];
    struct msghdr msg;
    struct cmsghdr *cmsg;
    char cmsg_buf[CONTROLLEN];
    cmsg = (struct cmsghdr *)cmsg_buf;

    memset(&msg, 0, sizeof(msg));

    iov[0].iov_base = buf;
    iov[0].iov_len = sizeof(buf);
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;
    msg.msg_control = cmsg;
    msg.msg_controllen = CONTROLLEN;

    int ret = recvmsg(ipcd_socket, &msg, 0);
    if (ret <= 0) {
      perror("recvmsg");
      exit(1);
    }

    // TODO: Understand and fix mismatch between
    // CONTROLLEN and msg.msg_controllen after recvmsg()!
    fd = *(int *)CMSG_DATA(cmsg);
    ipclog("received local fd %d for endpoint %d\n", fd, local);
  }

  err = __real_read(ipcd_socket, buf, 50);
  assert(err > 5);

  bool success = strncmp(buf, "200 OK\n", err) == 0;
  assert(success);

  return fd;
}

// UNREGISTER
bool ipcd_unregister_socket(endpoint ep) {
  IPCLock();
  connect_if_needed();

  char buf[100];
  int len = sprintf(buf, "UNREGISTER %d\n", ep);
  assert(len > 5);
  int err = __real_write(ipcd_socket, buf, len);
  if (err < 0) {
    perror("write");
    exit(1);
  }
  err = __real_read(ipcd_socket, buf, 50);
  assert(err > 5);

  return strncmp(buf, "200 OK\n", err) == 0;
}

<|endoftext|>


<commit_before>#include <stdio.h>
#include <magrathea.h>
#include <terrain.h>
#include <game.h>
#include <dynotree.h>
#include <heightmap.h>
#include <images.h>
#include <smallFern.h>
#include <heightmap.h>
#include <cmath>
#include <texture.h>
#include <stdlib.h>

GLuint texture = 0;

/// Constructs a new region at the given position
/// @param x The x coordinate of the origin
/// @param y The y coordinate of the origin
/// @param parent The game that this region is in.
Terrain::Terrain(glm::vec3 pos,Game* parent) : Object(pos,parent)
{
  initialiseTriangles();
  freeze();
  shaderID = game->shaderManager->newShader("terrain",VERTEX_SHADER|GEOMETRY_SHADER|FRAGMENT_SHADER|TESSELATION_SHADER);
  makeTexture();
  texture = textureFromTGA("assets/grass.tga",true);
}

/// Constructs the triangles
void Terrain::initialiseTriangles()
{
  clearTriangleData((NUMBER_OF_PATCHES+1)*(NUMBER_OF_PATCHES+1)*6,2);
  for (int i= 0;i<NUMBER_OF_PATCHES+1;i++)
    for (int j = 0;j<NUMBER_OF_PATCHES+1;j++)
    {
      addPoint((i*NUMBER_OF_PATCHES+j)*6,
                   glm::vec3(i*PATCH_SIZE,
			                       0,
			                       j*PATCH_SIZE),
                             glm::vec3(1,0,0),
                             1,1,1);
      addPoint((i*NUMBER_OF_PATCHES+j)*6+1,
                   glm::vec3(i*PATCH_SIZE,
			                       0,
                             j*PATCH_SIZE+PATCH_SIZE),
                             glm::vec3(1,0,0),
                             1,1,1);
      addPoint((i*NUMBER_OF_PATCHES+j)*6+2,
                   glm::vec3(i*PATCH_SIZE+PATCH_SIZE,
			                       0,
			                       j*PATCH_SIZE+PATCH_SIZE),
                             glm::vec3(1,0,0),
                             1,1,1);
      addPoint((i*NUMBER_OF_PATCHES+j)*6+3,
                   glm::vec3(i*PATCH_SIZE+PATCH_SIZE,
			                       0,
			                       j*PATCH_SIZE+PATCH_SIZE),
                             glm::vec3(1,0,0),
                             1,1,1);
      addPoint((i*NUMBER_OF_PATCHES+j)*6+4,
                   glm::vec3(i*PATCH_SIZE+PATCH_SIZE,
			                       0,
                             j*PATCH_SIZE),
                             glm::vec3(1,0,0),
                             1,1,1);
      addPoint((i*NUMBER_OF_PATCHES+j)*6+5,
                   glm::vec3(i*PATCH_SIZE,
			                       0,
                             j*PATCH_SIZE),
                             glm::vec3(1,0,0),
                             1,1,1);
    }
  pushTriangleData();
}

void Terrain::Render()
{
  heightmapTexture->load();
  texture->load();
  game->shaderManager->loadShader(shaderID);
  // Load our transformation matrix etc
  game->shaderManager->getCurrentShader()->setObjectData(objectBO);
  // Select this object's texture
  glBindVertexArray(VAO);
  glPatchParameteri(GL_PATCH_VERTICES,3);
  glDrawArrays(GL_PATCHES,0,6*NUMBER_OF_PATCHES*NUMBER_OF_PATCHES);
}

void Terrain::makeTexture()
{
  int width = 2049;
  int height = 2049;
  float* heights = getHeightmapData(width,height);
  heightmapTexture = new Texture(HEIGHTMAP_TEXTURE,width,height);
  heightmapTexture->loadBumpData(heights);
  heightmapTexture->load();
  heightmapTexture->toTGA("heightmap.tga");
}
<commit_msg>Removed broken dependecies<commit_after>#include <stdio.h>
#include <magrathea.h>
#include <terrain.h>
#include <game.h>
#include <heightmap.h>
#include <images.h>
#include <heightmap.h>
#include <cmath>
#include <texture.h>
#include <stdlib.h>

GLuint texture = 0;

/// Constructs a new region at the given position
/// @param x The x coordinate of the origin
/// @param y The y coordinate of the origin
/// @param parent The game that this region is in.
Terrain::Terrain(glm::vec3 pos,Game* parent) : Object(pos,parent)
{
  initialiseTriangles();
  freeze();
  shaderID = game->shaderManager->newShader("terrain",VERTEX_SHADER|GEOMETRY_SHADER|FRAGMENT_SHADER|TESSELATION_SHADER);
  makeTexture();
  texture = textureFromTGA("assets/grass.tga",true);
}

/// Constructs the triangles
void Terrain::initialiseTriangles()
{
  clearTriangleData((NUMBER_OF_PATCHES+1)*(NUMBER_OF_PATCHES+1)*6,2);
  for (int i= 0;i<NUMBER_OF_PATCHES+1;i++)
    for (int j = 0;j<NUMBER_OF_PATCHES+1;j++)
    {
      addPoint((i*NUMBER_OF_PATCHES+j)*6,
                   glm::vec3(i*PATCH_SIZE,
			                       0,
			                       j*PATCH_SIZE),
                             glm::vec3(1,0,0),
                             1,1,1);
      addPoint((i*NUMBER_OF_PATCHES+j)*6+1,
                   glm::vec3(i*PATCH_SIZE,
			                       0,
                             j*PATCH_SIZE+PATCH_SIZE),
                             glm::vec3(1,0,0),
                             1,1,1);
      addPoint((i*NUMBER_OF_PATCHES+j)*6+2,
                   glm::vec3(i*PATCH_SIZE+PATCH_SIZE,
			                       0,
			                       j*PATCH_SIZE+PATCH_SIZE),
                             glm::vec3(1,0,0),
                             1,1,1);
      addPoint((i*NUMBER_OF_PATCHES+j)*6+3,
                   glm::vec3(i*PATCH_SIZE+PATCH_SIZE,
			                       0,
			                       j*PATCH_SIZE+PATCH_SIZE),
                             glm::vec3(1,0,0),
                             1,1,1);
      addPoint((i*NUMBER_OF_PATCHES+j)*6+4,
                   glm::vec3(i*PATCH_SIZE+PATCH_SIZE,
			                       0,
                             j*PATCH_SIZE),
                             glm::vec3(1,0,0),
                             1,1,1);
      addPoint((i*NUMBER_OF_PATCHES+j)*6+5,
                   glm::vec3(i*PATCH_SIZE,
			                       0,
                             j*PATCH_SIZE),
                             glm::vec3(1,0,0),
                             1,1,1);
    }
  pushTriangleData();
}

void Terrain::Render()
{
  heightmapTexture->load();
  texture->load();
  game->shaderManager->loadShader(shaderID);
  // Load our transformation matrix etc
  game->shaderManager->getCurrentShader()->setObjectData(objectBO);
  // Select this object's texture
  glBindVertexArray(VAO);
  glPatchParameteri(GL_PATCH_VERTICES,3);
  glDrawArrays(GL_PATCHES,0,6*NUMBER_OF_PATCHES*NUMBER_OF_PATCHES);
}

void Terrain::makeTexture()
{
  int width = 2049;
  int height = 2049;
  float* heights = getHeightmapData(width,height);
  heightmapTexture = new Texture(HEIGHTMAP_TEXTURE,width,height);
  heightmapTexture->loadBumpData(heights);
  heightmapTexture->load();
  heightmapTexture->toTGA("heightmap.tga");
}
<|endoftext|>


<commit_before>/**
 * @file Cognition.cpp
 *
 * @author Heinrich Mellmann
 * Implementation of the class Cognition
 */

#include "Cognition.h"

#include <PlatformInterface/Platform.h>

// tools
#include "Tools/Debug/Trace.h"

/////////////////////////////////////
// Modules
/////////////////////////////////////

// infrastructure
#include "Modules/Infrastructure/IO/Sensor.h"
#include "Modules/Infrastructure/IO/Actuator.h"
#include "Modules/Infrastructure/ButtonEventMonitor/ButtonEventMonitor.h"
#include "Cognition/Modules/Infrastructure/WifiModeSetter/WifiModeSetter.h"
#include "Modules/Infrastructure/BatteryAlert/BatteryAlert.h"
#include "Modules/Infrastructure/GameController/GameController.h"
#include "Modules/Infrastructure/Debug/FrameRateCheck.h"
#include "Modules/Infrastructure/Debug/DebugExecutor.h"
#include "Modules/Infrastructure/Debug/Debug.h"
#include "Modules/Infrastructure/LEDSetter/LEDSetter.h"
#include "Modules/Infrastructure/UltraSoundControl/UltraSoundControl.h"

#include "Modules/Infrastructure/TeamCommunicator/TeamCommReceiver.h"
#include "Modules/Infrastructure/TeamCommunicator/TeamCommSender.h"
#include "Modules/Infrastructure/TeamCommunicator/SimpleNetworkTimeProtocol.h"

#include "Modules/Infrastructure/Debug/CameraDebug.h"
#include "Modules/Infrastructure/Camera/CameraInfoSetter.h"
#include "Modules/Infrastructure/Camera/AdaptiveAutoExposure.h"
#include "Modules/Infrastructure/GameLogger/GameLogger.h"

// perception
#include "Modules/SelfAwareness/CameraMatrixFinder/CameraMatrixFinder.h"
#include "Modules/SelfAwareness/KinematicChainProvider/KinematicChainProvider.h"
#include "Modules/SelfAwareness/ArtificialHorizonCalculator/ArtificialHorizonCalculator.h"
#include "Modules/SelfAwareness/BodyContourProvider/BodyContourProvider.h"
#include "Modules/SelfAwareness/CameraMatrixCorrectorV2/CameraMatrixCorrectorV2.h"
#include "Modules/SelfAwareness/CameraMatrixCorrectorV3/CameraMatrixCorrectorV3.h"

#include "Modules/VisualCortex/HistogramProvider.h"
#include "Modules/VisualCortex/FieldColorClassifier.h"
#include "Modules/VisualCortex/ScanGrid/ScanGridProvider.h"
#include "Modules/VisualCortex/ScanGrid/ScanGridEdgelDetector.h"
#include "Modules/VisualCortex/ScanLineEdgelDetector/ScanLineEdgelDetector.h"
#include "Modules/VisualCortex/FieldDetector/FieldDetector.h"
#include "Modules/VisualCortex/FieldDetector/IntegralFieldDetector.h"
#include "Modules/VisualCortex/LineDetector/LineGraphProvider.h"
#include "Modules/VisualCortex/GoalDetector/GoalFeatureDetector.h"
#include "Modules/VisualCortex/GoalDetector/GoalFeatureDetectorV2.h"
#include "Modules/VisualCortex/GoalDetector/GoalDetector.h"
#include "Modules/VisualCortex/GoalDetector/GoalDetectorV2.h"
#include "Modules/VisualCortex/GoalDetector/GoalCrossBarDetector.h"
#include "Modules/VisualCortex/BallDetector/RedBallDetector.h"
#include "Modules/VisualCortex/BallDetector/CNNBallDetector.h"
#include "Modules/VisualCortex/BallDetector/MultiPassBallDetector.h"
#include "Modules/VisualCortex/IntegralImageProvider.h"

#include "Modules/VisualCortex/ObstacleDetector/NoGreenObstacleDetector.h"

#include "Modules/SelfAwareness/FakeCameraMatrixFinder/FakeCameraMatrixFinder.h"
#include "Modules/VisualCortex/FakeBallDetector/FakeBallDetector.h"

#include "Modules/Perception/VirtualVisionProcessor/VirtualVisionProcessor.h"
#include "Modules/Perception/PerceptionsVisualizer/PerceptionsVisualizer.h"
#include "Modules/Perception/WhistleDetector/WhistleDetectorV1.h"
#include "Modules/Perception/WhistleDetector/WhistleDetectorV2.h"

#include "Modules/VisualCortex/LineDetector/RansacLineDetector.h"
#include "Modules/VisualCortex/LineDetector/RansacLineDetectorOnGraphs.h"
#include "Modules/VisualCortex/LineDetector/LineAugmenter.h"

#include "Modules/Modeling/CompassProvider/CompassProvider.h"

// modeling
#include "Modules/Modeling/BodyStateProvider/BodyStateProvider.h"
#include "Modules/Modeling/FieldCompass/FieldCompass.h"
#include "Modules/Modeling/ObstacleLocator/UltraSoundObstacleLocator.h"
#include "Modules/Modeling/ObstacleLocator/UltrasonicObstacleLocator2020.h"
#include "Modules/Infrastructure/TeamCommunicator/TeamCommReceiveEmulator.h"
#include "Modules/Modeling/TeamMessageStatistics/TeamMessageStatisticsModule.h"
#include "Modules/Modeling/TeamMessageStatistics/TeamMessagePlayersStateModule.h"
#include "Modules/Modeling/SoccerStrategyProvider/SoccerStrategyProvider.h"
#include "Modules/Modeling/PotentialFieldProvider/PotentialFieldProvider.h"
#include "Modules/Modeling/SelfLocator/GPS_SelfLocator/GPS_SelfLocator.h"
#include "Modules/Modeling/SelfLocator/MonteCarloSelfLocator/MonteCarloSelfLocator.h"
#include "Modules/Modeling/SelfLocator/OdometrySelfLocator/OdometrySelfLocator.h"
#include "Modules/Modeling/GoalModel/DummyActiveGoalLocator/DummyActiveGoalLocator.h"
#include "Modules/Modeling/GoalModel/WholeGoalLocator/WholeGoalLocator.h"

// role decisions
#include "Modules/Modeling/RoleDecision/RolesProvider.h"
#include "Modules/Modeling/RoleDecision/Dynamic/RoleDecisionDynamic.h"

#include "Modules/Modeling/RoleDecision/Position/RoleDecisionPositionStatic.h"
#include "Modules/Modeling/RoleDecision/Position/RoleDecisionPositionForce.h"
#include "Modules/Modeling/RoleDecision/Position/RoleDecisionPositionPotentialField.h"
#include "Modules/Modeling/RoleDecision/Position/RoleDecisionPositionFormation.h"
#include "Modules/Modeling/RoleDecision/Position/RoleDecisionPositionDynamicGoalie.h"
#include "Modules/Modeling/RoleDecision/Assignment/RoleDecisionAssignmentStatic.h"
#include "Modules/Modeling/RoleDecision/Assignment/RoleDecisionAssignmentDistance.h"
// the old striker decision (dynamic)
#include "Modules/Modeling/RoleDecision/Dynamic/SimpleRoleDecision.h"
#include "Modules/Modeling/RoleDecision/Dynamic/StableRoleDecision.h"
#include "Modules/Modeling/RoleDecision/Dynamic/CleanRoleDecision.h"

#include "Modules/Modeling/BallLocator/TeamBallLocator/TeamBallLocatorMedian.h"
#include "Modules/Modeling/BallLocator/TeamBallLocator/TeamBallLocatorCanopyCluster.h"
#include "Modules/Modeling/BallLocator/MultiKalmanBallLocator/MultiKalmanBallLocator.h"
#include "Modules/Modeling/StaticDebugModelProvider/StaticDebugModelProvider.h"

#include "Modules/Modeling/ObstacleLocator/MultiUnifiedObstacleLocator.h"
#include "Modules/Modeling/Simulation/SimulationTest.h"

#include "Modules/Modeling/Simulation/Simulation.h"
#include "Modules/Modeling/Simulation/KickDirectionSimulator.h"
#include "Modules/Modeling/SelfLocator/SituationPriorProvider/SituationPriorProvider.h"

// behavior
#include "Modules/Behavior/BasicTestBehavior/BasicTestBehavior.h"
#include "Modules/Behavior/XABSLBehaviorControl/XABSLBehaviorControl.h"
#include "Modules/Behavior/PathPlanner/PathPlanner.h"
#include "Modules/Behavior/PathPlanner/PathPlanner2018.h"

using namespace std;

Cognition::Cognition()
  : ModuleManagerWithDebug("")
{
}

Cognition::~Cognition()
{
}

#define REGISTER_MODULE(module) \
  std::cout << "[Cognition] Register " << #module << std::endl;\
  registerModule<module>(std::string(#module))

void Cognition::init(naoth::ProcessInterface& platformInterface, const naoth::PlatformBase& platform)
{
  std::cout << "[Cognition] Cognition register start" << std::endl;

  // register input module
  ModuleCreator<Sensor>* sensor = registerModule<Sensor>(std::string("Sensor"), true);
  sensor->getModuleT()->init(platformInterface, platform);

  /*
  * to register a module use
  *   REGISTER_MODULE(ModuleClassName);
  *
  * Remark: to enable the module don't forget
  *         to set the value in modules.cfg
  */

  // -- BEGIN REGISTER MODULES --

  // infrastructure
  REGISTER_MODULE(ButtonEventMonitor);
  REGISTER_MODULE(WifiModeSetter);
  REGISTER_MODULE(TeamCommReceiver);
  REGISTER_MODULE(SimpleNetworkTimeProtocol);
  REGISTER_MODULE(GameController);
  REGISTER_MODULE(BatteryAlert);
  REGISTER_MODULE(LEDSetter);
  REGISTER_MODULE(UltraSoundControl);

  REGISTER_MODULE(CameraDebug);
  REGISTER_MODULE(CameraInfoSetter);
  REGISTER_MODULE(AdaptiveAutoExposure);
  REGISTER_MODULE(WhistleDetectorV1);
  REGISTER_MODULE(WhistleDetectorV2);

  // perception
  REGISTER_MODULE(CameraMatrixFinder);
  REGISTER_MODULE(KinematicChainProvider);
  REGISTER_MODULE(ArtificialHorizonCalculator);
  REGISTER_MODULE(BodyContourProvider);
  REGISTER_MODULE(CameraMatrixCorrectorV2);

  REGISTER_MODULE(HistogramProvider);
  REGISTER_MODULE(IntegralImageProvider);
  REGISTER_MODULE(FieldColorClassifier);
  REGISTER_MODULE(IntegralFieldDetector);
  REGISTER_MODULE(ScanGridProvider);
  REGISTER_MODULE(ScanGridEdgelDetector);
  REGISTER_MODULE(ScanLineEdgelDetector);
  REGISTER_MODULE(FieldDetector);
  REGISTER_MODULE(LineGraphProvider);
  REGISTER_MODULE(GoalFeatureDetector);
  REGISTER_MODULE(GoalFeatureDetectorV2);
  REGISTER_MODULE(GoalDetector);
  REGISTER_MODULE(GoalDetectorV2);
  REGISTER_MODULE(GoalCrossBarDetector);

  REGISTER_MODULE(NoGreenObstacleDetector);

  REGISTER_MODULE(RedBallDetector);
  REGISTER_MODULE(CNNBallDetector);
  REGISTER_MODULE(MultiPassBallDetector);
  REGISTER_MODULE(FakeCameraMatrixFinder);
  REGISTER_MODULE(FakeBallDetector);

  REGISTER_MODULE(VirtualVisionProcessor);
  REGISTER_MODULE(PerceptionsVisualizer);

  REGISTER_MODULE(RansacLineDetector);
  REGISTER_MODULE(RansacLineDetectorOnGraphs);
  REGISTER_MODULE(LineAugmenter);

  REGISTER_MODULE(CompassProvider);

  // modeling
  REGISTER_MODULE(SituationPriorProvider);
  REGISTER_MODULE(BodyStateProvider);
  REGISTER_MODULE(FieldCompass);
  REGISTER_MODULE(UltraSoundObstacleLocator);
  REGISTER_MODULE(UltrasonicObstacleLocator2020);
  REGISTER_MODULE(TeamCommReceiveEmulator);
  REGISTER_MODULE(TeamMessageStatisticsModule);
  REGISTER_MODULE(TeamMessagePlayersStateModule);
  REGISTER_MODULE(SoccerStrategyProvider);
  REGISTER_MODULE(PotentialFieldProvider);
  REGISTER_MODULE(GPS_SelfLocator);
  REGISTER_MODULE(MonteCarloSelfLocator);
  REGISTER_MODULE(OdometrySelfLocator);
  REGISTER_MODULE(WholeGoalLocator);
  REGISTER_MODULE(DummyActiveGoalLocator);
  REGISTER_MODULE(MultiKalmanBallLocator);

  REGISTER_MODULE(TeamBallLocatorMedian);
  REGISTER_MODULE(TeamBallLocatorCanopyCluster);

  REGISTER_MODULE(MultiUnifiedObstacleLocator);
  /*
   * BEGIN ROLE DECISIONS
   */
  REGISTER_MODULE(RolesProvider);
  // first set the position of the roles
  REGISTER_MODULE(RoleDecisionPositionStatic);
  REGISTER_MODULE(RoleDecisionPositionForce);
  REGISTER_MODULE(RoleDecisionPositionPotentialField);
  REGISTER_MODULE(RoleDecisionPositionFormation);
  REGISTER_MODULE(RoleDecisionPositionDynamicGoalie);
  // then decide which player should have which role
  REGISTER_MODULE(RoleDecisionAssignmentStatic);
  REGISTER_MODULE(RoleDecisionAssignmentDistance);
  // finally, determine the dynamic role (striker, supporter, ...)
  REGISTER_MODULE(RoleDecisionDynamic);

  // old striker decisions
  REGISTER_MODULE(SimpleRoleDecision);
  REGISTER_MODULE(StableRoleDecision);
  REGISTER_MODULE(CleanRoleDecision);
  /*
   * END ROLE DECISIONS
   */

  REGISTER_MODULE(KickDirectionSimulator);
  REGISTER_MODULE(Simulation);
  REGISTER_MODULE(StaticDebugModelProvider);

  // behavior
  REGISTER_MODULE(BasicTestBehavior);
  REGISTER_MODULE(XABSLBehaviorControl);
  REGISTER_MODULE(PathPlanner);
  REGISTER_MODULE(PathPlanner2018);

  REGISTER_MODULE(CameraMatrixCorrectorV3);

  REGISTER_MODULE(TeamCommSender);

  // debug
  REGISTER_MODULE(GameLogger);
  REGISTER_MODULE(Debug);
  REGISTER_MODULE(FrameRateCheck);
  REGISTER_MODULE(DebugExecutor);

  // -- END REGISTER MODULES --

  // register output module
  ModuleCreator<Actuator>* actuator = registerModule<Actuator>(std::string("Actuator"), true);
  actuator->getModuleT()->init(platformInterface, platform);

  // use the configuration in order to set whether a module is activated or not
  const naoth::Configuration& config = Platform::getInstance().theConfiguration;

  list<string>::const_iterator name = getExecutionList().begin();
  for(;name != getExecutionList().end(); ++name)
  {
    bool active = false;
    if(config.hasKey("modules", *name)) {
      active = config.getBool("modules", *name);
    }
    if(active) {
      std::cout << "[Cognition] activating module " << *name << std::endl;
    }
    setModuleEnabled(*name, active);
  }//end for

  // auto-generate the execution list
  //calculateExecutionList();

  std::cout << "[Cognition] register end" << std::endl;

  stopwatch.start();
}//end init

void Cognition::call()
{
  // BEGIN cognition frame rate measuring
  stopwatch.stop();
  stopwatch.start();
  PLOT("Cognition.Cycle", stopwatch.lastValue);
  // END cognition frame rate measuring

  STOPWATCH_START("Cognition.Execute");

  // execute all modules
  list<AbstractModuleCreator*>::const_iterator iter;
  for (iter = getModuleExecutionList().begin(); iter != getModuleExecutionList().end(); ++iter)
  {
    AbstractModuleCreator* module = *iter;
    if (module != NULL && module->isEnabled())
    {
      std::string name(module->getModule()->getName());
      GT_TRACE("executing " << name);
      module->execute();
    }
  }

  STOPWATCH_STOP("Cognition.Execute");

  // HACK: reset all the debug stuff before executing the modules
  STOPWATCH_START("Cognition.Debug.Init");
  getDebugDrawings().reset();
  getDebugImageDrawings().reset();
  getDebugImageDrawingsTop().reset();
  getDebugDrawings3D().reset();
  STOPWATCH_STOP("Cognition.Debug.Init");
}//end call
<commit_msg>fix a compile error<commit_after>/**
 * @file Cognition.cpp
 *
 * @author Heinrich Mellmann
 * Implementation of the class Cognition
 */

#include "Cognition.h"

#include <PlatformInterface/Platform.h>

// tools
#include "Tools/Debug/Trace.h"

/////////////////////////////////////
// Modules
/////////////////////////////////////

// infrastructure
#include "Modules/Infrastructure/IO/Sensor.h"
#include "Modules/Infrastructure/IO/Actuator.h"
#include "Modules/Infrastructure/ButtonEventMonitor/ButtonEventMonitor.h"
#include "Cognition/Modules/Infrastructure/WifiModeSetter/WifiModeSetter.h"
#include "Modules/Infrastructure/BatteryAlert/BatteryAlert.h"
#include "Modules/Infrastructure/GameController/GameController.h"
#include "Modules/Infrastructure/Debug/FrameRateCheck.h"
#include "Modules/Infrastructure/Debug/DebugExecutor.h"
#include "Modules/Infrastructure/Debug/Debug.h"
#include "Modules/Infrastructure/LEDSetter/LEDSetter.h"
#include "Modules/Infrastructure/UltraSoundControl/UltraSoundControl.h"

#include "Modules/Infrastructure/TeamCommunicator/TeamCommReceiver.h"
#include "Modules/Infrastructure/TeamCommunicator/TeamCommSender.h"
#include "Modules/Infrastructure/TeamCommunicator/SimpleNetworkTimeProtocol.h"

#include "Modules/Infrastructure/Debug/CameraDebug.h"
#include "Modules/Infrastructure/Camera/CameraInfoSetter.h"
#include "Modules/Infrastructure/Camera/AdaptiveAutoExposure.h"
#include "Modules/Infrastructure/GameLogger/GameLogger.h"

// perception
#include "Modules/SelfAwareness/CameraMatrixFinder/CameraMatrixFinder.h"
#include "Modules/SelfAwareness/KinematicChainProvider/KinematicChainProvider.h"
#include "Modules/SelfAwareness/ArtificialHorizonCalculator/ArtificialHorizonCalculator.h"
#include "Modules/SelfAwareness/BodyContourProvider/BodyContourProvider.h"
#include "Modules/SelfAwareness/CameraMatrixCorrectorV2/CameraMatrixCorrectorV2.h"
#include "Modules/SelfAwareness/CameraMatrixCorrectorV3/CameraMatrixCorrectorV3.h"

#include "Modules/VisualCortex/HistogramProvider.h"
#include "Modules/VisualCortex/FieldColorClassifier.h"
#include "Modules/VisualCortex/ScanGrid/ScanGridProvider.h"
#include "Modules/VisualCortex/ScanGrid/ScanGridEdgelDetector.h"
#include "Modules/VisualCortex/ScanLineEdgelDetector/ScanLineEdgelDetector.h"
#include "Modules/VisualCortex/FieldDetector/FieldDetector.h"
#include "Modules/VisualCortex/FieldDetector/IntegralFieldDetector.h"
#include "Modules/VisualCortex/LineDetector/LineGraphProvider.h"
#include "Modules/VisualCortex/GoalDetector/GoalFeatureDetector.h"
#include "Modules/VisualCortex/GoalDetector/GoalFeatureDetectorV2.h"
#include "Modules/VisualCortex/GoalDetector/GoalDetector.h"
#include "Modules/VisualCortex/GoalDetector/GoalDetectorV2.h"
#include "Modules/VisualCortex/GoalDetector/GoalCrossBarDetector.h"
#include "Modules/VisualCortex/BallDetector/RedBallDetector.h"
#include "Modules/VisualCortex/BallDetector/CNNBallDetector.h"
#include "Modules/VisualCortex/BallDetector/MultiPassBallDetector.h"
#include "Modules/VisualCortex/IntegralImageProvider.h"

#include "Modules/VisualCortex/ObstacleDetector/NoGreenObstacleDetector.h"

#include "Modules/SelfAwareness/FakeCameraMatrixFinder/FakeCameraMatrixFinder.h"
#include "Modules/VisualCortex/FakeBallDetector/FakeBallDetector.h"

#include "Modules/Perception/VirtualVisionProcessor/VirtualVisionProcessor.h"
#include "Modules/Perception/PerceptionsVisualizer/PerceptionsVisualizer.h"
#include "Modules/Perception/WhistleDetector/WhistleDetectorV1.h"
#include "Modules/Perception/WhistleDetector/WhistleDetectorV2.h"

#include "Modules/VisualCortex/LineDetector/RansacLineDetector.h"
#include "Modules/VisualCortex/LineDetector/RansacLineDetectorOnGraphs.h"
#include "Modules/VisualCortex/LineDetector/LineAugmenter.h"

#include "Modules/Modeling/CompassProvider/CompassProvider.h"

// modeling
#include "Modules/Modeling/BodyStateProvider/BodyStateProvider.h"
#include "Modules/Modeling/FieldCompass/FieldCompass.h"
#include "Modules/Modeling/ObstacleLocator/UltraSoundObstacleLocator.h"
#include "Modules/Modeling/ObstacleLocator/UltrasonicObstacleLocator2020.h"
#include "Modules/Infrastructure/TeamCommunicator/TeamCommReceiveEmulator.h"
#include "Modules/Modeling/TeamMessageStatistics/TeamMessageStatisticsModule.h"
#include "Modules/Modeling/TeamMessageStatistics/TeamMessagePlayersStateModule.h"
#include "Modules/Modeling/SoccerStrategyProvider/SoccerStrategyProvider.h"
#include "Modules/Modeling/PotentialFieldProvider/PotentialFieldProvider.h"
#include "Modules/Modeling/SelfLocator/GPS_SelfLocator/GPS_SelfLocator.h"
#include "Modules/Modeling/SelfLocator/MonteCarloSelfLocator/MonteCarloSelfLocator.h"
#include "Modules/Modeling/SelfLocator/OdometrySelfLocator/OdometrySelfLocator.h"
#include "Modules/Modeling/GoalModel/DummyActiveGoalLocator/DummyActiveGoalLocator.h"
#include "Modules/Modeling/GoalModel/WholeGoalLocator/WholeGoalLocator.h"

// role decisions
#include "Modules/Modeling/RoleDecision/RolesProvider.h"
#include "Modules/Modeling/RoleDecision/Dynamic/RoleDecisionDynamic.h"

#include "Modules/Modeling/RoleDecision/Position/RoleDecisionPositionStatic.h"
#include "Modules/Modeling/RoleDecision/Position/RoleDecisionPositionForce.h"
#include "Modules/Modeling/RoleDecision/Position/RoleDecisionPositionPotentialField.h"
#include "Modules/Modeling/RoleDecision/Position/RoleDecisionPositionFormation.h"
#include "Modules/Modeling/RoleDecision/Position/RoleDecisionPositionDynamicGoalie.h"
#include "Modules/Modeling/RoleDecision/Assignment/RoleDecisionAssignmentStatic.h"
#include "Modules/Modeling/RoleDecision/Assignment/RoleDecisionAssignmentDistance.h"
// the old striker decision (dynamic)
#include "Modules/Modeling/RoleDecision/Dynamic/SimpleRoleDecision.h"
#include "Modules/Modeling/RoleDecision/Dynamic/StableRoleDecision.h"
#include "Modules/Modeling/RoleDecision/Dynamic/CleanRoleDecision.h"

#include "Modules/Modeling/BallLocator/TeamBallLocator/TeamBallLocatorMedian.h"
#include "Modules/Modeling/BallLocator/TeamBallLocator/TeamBallLocatorCanopyCluster.h"
#include "Modules/Modeling/BallLocator/MultiKalmanBallLocator/MultiKalmanBallLocator.h"
#include "Modules/Modeling/StaticDebugModelProvider/StaticDebugModelProvider.h"

#include "Modules/Modeling/ObstacleLocator/MultiUnifiedObstacleLocator.h"

#include "Modules/Modeling/Simulation/Simulation.h"
#include "Modules/Modeling/Simulation/KickDirectionSimulator.h"
#include "Modules/Modeling/SelfLocator/SituationPriorProvider/SituationPriorProvider.h"

// behavior
#include "Modules/Behavior/BasicTestBehavior/BasicTestBehavior.h"
#include "Modules/Behavior/XABSLBehaviorControl/XABSLBehaviorControl.h"
#include "Modules/Behavior/PathPlanner/PathPlanner.h"
#include "Modules/Behavior/PathPlanner/PathPlanner2018.h"

using namespace std;

Cognition::Cognition()
  : ModuleManagerWithDebug("")
{
}

Cognition::~Cognition()
{
}

#define REGISTER_MODULE(module) \
  std::cout << "[Cognition] Register " << #module << std::endl;\
  registerModule<module>(std::string(#module))

void Cognition::init(naoth::ProcessInterface& platformInterface, const naoth::PlatformBase& platform)
{
  std::cout << "[Cognition] Cognition register start" << std::endl;

  // register input module
  ModuleCreator<Sensor>* sensor = registerModule<Sensor>(std::string("Sensor"), true);
  sensor->getModuleT()->init(platformInterface, platform);

  /*
  * to register a module use
  *   REGISTER_MODULE(ModuleClassName);
  *
  * Remark: to enable the module don't forget
  *         to set the value in modules.cfg
  */

  // -- BEGIN REGISTER MODULES --

  // infrastructure
  REGISTER_MODULE(ButtonEventMonitor);
  REGISTER_MODULE(WifiModeSetter);
  REGISTER_MODULE(TeamCommReceiver);
  REGISTER_MODULE(SimpleNetworkTimeProtocol);
  REGISTER_MODULE(GameController);
  REGISTER_MODULE(BatteryAlert);
  REGISTER_MODULE(LEDSetter);
  REGISTER_MODULE(UltraSoundControl);

  REGISTER_MODULE(CameraDebug);
  REGISTER_MODULE(CameraInfoSetter);
  REGISTER_MODULE(AdaptiveAutoExposure);
  REGISTER_MODULE(WhistleDetectorV1);
  REGISTER_MODULE(WhistleDetectorV2);

  // perception
  REGISTER_MODULE(CameraMatrixFinder);
  REGISTER_MODULE(KinematicChainProvider);
  REGISTER_MODULE(ArtificialHorizonCalculator);
  REGISTER_MODULE(BodyContourProvider);
  REGISTER_MODULE(CameraMatrixCorrectorV2);

  REGISTER_MODULE(HistogramProvider);
  REGISTER_MODULE(IntegralImageProvider);
  REGISTER_MODULE(FieldColorClassifier);
  REGISTER_MODULE(IntegralFieldDetector);
  REGISTER_MODULE(ScanGridProvider);
  REGISTER_MODULE(ScanGridEdgelDetector);
  REGISTER_MODULE(ScanLineEdgelDetector);
  REGISTER_MODULE(FieldDetector);
  REGISTER_MODULE(LineGraphProvider);
  REGISTER_MODULE(GoalFeatureDetector);
  REGISTER_MODULE(GoalFeatureDetectorV2);
  REGISTER_MODULE(GoalDetector);
  REGISTER_MODULE(GoalDetectorV2);
  REGISTER_MODULE(GoalCrossBarDetector);

  REGISTER_MODULE(NoGreenObstacleDetector);

  REGISTER_MODULE(RedBallDetector);
  REGISTER_MODULE(CNNBallDetector);
  REGISTER_MODULE(MultiPassBallDetector);
  REGISTER_MODULE(FakeCameraMatrixFinder);
  REGISTER_MODULE(FakeBallDetector);

  REGISTER_MODULE(VirtualVisionProcessor);
  REGISTER_MODULE(PerceptionsVisualizer);

  REGISTER_MODULE(RansacLineDetector);
  REGISTER_MODULE(RansacLineDetectorOnGraphs);
  REGISTER_MODULE(LineAugmenter);

  REGISTER_MODULE(CompassProvider);

  // modeling
  REGISTER_MODULE(SituationPriorProvider);
  REGISTER_MODULE(BodyStateProvider);
  REGISTER_MODULE(FieldCompass);
  REGISTER_MODULE(UltraSoundObstacleLocator);
  REGISTER_MODULE(UltrasonicObstacleLocator2020);
  REGISTER_MODULE(TeamCommReceiveEmulator);
  REGISTER_MODULE(TeamMessageStatisticsModule);
  REGISTER_MODULE(TeamMessagePlayersStateModule);
  REGISTER_MODULE(SoccerStrategyProvider);
  REGISTER_MODULE(PotentialFieldProvider);
  REGISTER_MODULE(GPS_SelfLocator);
  REGISTER_MODULE(MonteCarloSelfLocator);
  REGISTER_MODULE(OdometrySelfLocator);
  REGISTER_MODULE(WholeGoalLocator);
  REGISTER_MODULE(DummyActiveGoalLocator);
  REGISTER_MODULE(MultiKalmanBallLocator);

  REGISTER_MODULE(TeamBallLocatorMedian);
  REGISTER_MODULE(TeamBallLocatorCanopyCluster);

  REGISTER_MODULE(MultiUnifiedObstacleLocator);
  /*
   * BEGIN ROLE DECISIONS
   */
  REGISTER_MODULE(RolesProvider);
  // first set the position of the roles
  REGISTER_MODULE(RoleDecisionPositionStatic);
  REGISTER_MODULE(RoleDecisionPositionForce);
  REGISTER_MODULE(RoleDecisionPositionPotentialField);
  REGISTER_MODULE(RoleDecisionPositionFormation);
  REGISTER_MODULE(RoleDecisionPositionDynamicGoalie);
  // then decide which player should have which role
  REGISTER_MODULE(RoleDecisionAssignmentStatic);
  REGISTER_MODULE(RoleDecisionAssignmentDistance);
  // finally, determine the dynamic role (striker, supporter, ...)
  REGISTER_MODULE(RoleDecisionDynamic);

  // old striker decisions
  REGISTER_MODULE(SimpleRoleDecision);
  REGISTER_MODULE(StableRoleDecision);
  REGISTER_MODULE(CleanRoleDecision);
  /*
   * END ROLE DECISIONS
   */

  REGISTER_MODULE(KickDirectionSimulator);
  REGISTER_MODULE(Simulation);
  REGISTER_MODULE(StaticDebugModelProvider);

  // behavior
  REGISTER_MODULE(BasicTestBehavior);
  REGISTER_MODULE(XABSLBehaviorControl);
  REGISTER_MODULE(PathPlanner);
  REGISTER_MODULE(PathPlanner2018);

  REGISTER_MODULE(CameraMatrixCorrectorV3);

  REGISTER_MODULE(TeamCommSender);

  // debug
  REGISTER_MODULE(GameLogger);
  REGISTER_MODULE(Debug);
  REGISTER_MODULE(FrameRateCheck);
  REGISTER_MODULE(DebugExecutor);

  // -- END REGISTER MODULES --

  // register output module
  ModuleCreator<Actuator>* actuator = registerModule<Actuator>(std::string("Actuator"), true);
  actuator->getModuleT()->init(platformInterface, platform);

  // use the configuration in order to set whether a module is activated or not
  const naoth::Configuration& config = Platform::getInstance().theConfiguration;

  list<string>::const_iterator name = getExecutionList().begin();
  for(;name != getExecutionList().end(); ++name)
  {
    bool active = false;
    if(config.hasKey("modules", *name)) {
      active = config.getBool("modules", *name);
    }
    if(active) {
      std::cout << "[Cognition] activating module " << *name << std::endl;
    }
    setModuleEnabled(*name, active);
  }//end for

  // auto-generate the execution list
  //calculateExecutionList();

  std::cout << "[Cognition] register end" << std::endl;

  stopwatch.start();
}//end init

void Cognition::call()
{
  // BEGIN cognition frame rate measuring
  stopwatch.stop();
  stopwatch.start();
  PLOT("Cognition.Cycle", stopwatch.lastValue);
  // END cognition frame rate measuring

  STOPWATCH_START("Cognition.Execute");

  // execute all modules
  list<AbstractModuleCreator*>::const_iterator iter;
  for (iter = getModuleExecutionList().begin(); iter != getModuleExecutionList().end(); ++iter)
  {
    AbstractModuleCreator* module = *iter;
    if (module != NULL && module->isEnabled())
    {
      std::string name(module->getModule()->getName());
      GT_TRACE("executing " << name);
      module->execute();
    }
  }

  STOPWATCH_STOP("Cognition.Execute");

  // HACK: reset all the debug stuff before executing the modules
  STOPWATCH_START("Cognition.Debug.Init");
  getDebugDrawings().reset();
  getDebugImageDrawings().reset();
  getDebugImageDrawingsTop().reset();
  getDebugDrawings3D().reset();
  STOPWATCH_STOP("Cognition.Debug.Init");
}//end call
<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/log/log.h>
LOG_SETUP("dense_dot_product_function_test");

#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/eval/eval/tensor_function.h>
#include <vespa/eval/eval/operation.h>
#include <vespa/eval/eval/simple_tensor.h>
#include <vespa/eval/eval/simple_tensor_engine.h>
#include <vespa/eval/tensor/default_tensor_engine.h>
#include <vespa/eval/tensor/dense/dense_xw_product_function.h>
#include <vespa/eval/tensor/dense/dense_tensor.h>
#include <vespa/eval/tensor/dense/dense_tensor_view.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/eval/test/eval_fixture.h>

#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/stash.h>

using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;
using namespace vespalib::tensor;
using namespace vespalib::eval::tensor_function;

const TensorEngine &prod_engine = DefaultTensorEngine::ref();

struct MyVecSeq : Sequence {
    double operator[](size_t i) const override { return (3.0 + i) * 7.0; }
};

struct MyMatSeq : Sequence {
    double operator[](size_t i) const override { return (5.0 + i) * 43.0; }
};

EvalFixture::ParamRepo make_params() {
    return EvalFixture::ParamRepo()
        .add("y1", spec({y(1)}, MyVecSeq()))
        .add("y3", spec({y(3)}, MyVecSeq()))
        .add("y3f", spec(float_cells({y(3)}), MyVecSeq()))
        .add("y5", spec({y(5)}, MyVecSeq()))
        .add("y16", spec({y(16)}, MyVecSeq()))
        .add("x1y1", spec({x(1),y(1)}, MyMatSeq()))
        .add("y1z1", spec({y(1),z(1)}, MyMatSeq()))
        .add("x2y3", spec({x(2),y(3)}, MyMatSeq()))
        .add("x2y3f", spec(float_cells({x(2),y(3)}), MyMatSeq()))
        .add("y3z2f", spec(float_cells({y(3),z(2)}), MyMatSeq()))
        .add("x2z3", spec({x(2),z(3)}, MyMatSeq()))
        .add("y3z2", spec({y(3),z(2)}, MyMatSeq()))
        .add("x8y5", spec({x(8),y(5)}, MyMatSeq()))
        .add("y5z8", spec({y(5),z(8)}, MyMatSeq()))
        .add("x5y16", spec({x(5),y(16)}, MyMatSeq()))
        .add("y16z5", spec({y(16),z(5)}, MyMatSeq()));
}
EvalFixture::ParamRepo param_repo = make_params();

void verify_optimized(const vespalib::string &expr, size_t vec_size, size_t res_size, bool happy) {
    EvalFixture fixture(prod_engine, expr, param_repo, true);
    EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
    auto info = fixture.find_all<DenseXWProductFunction>();
    ASSERT_EQUAL(info.size(), 1u);
    EXPECT_TRUE(info[0]->result_is_mutable());
    EXPECT_EQUAL(info[0]->vectorSize(), vec_size);
    EXPECT_EQUAL(info[0]->resultSize(), res_size);
    EXPECT_EQUAL(info[0]->matrixHasCommonDimensionInnermost(), happy);
}

void verify_not_optimized(const vespalib::string &expr) {
    EvalFixture fixture(prod_engine, expr, param_repo, true);
    EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
    auto info = fixture.find_all<DenseXWProductFunction>();
    EXPECT_TRUE(info.empty());
}

TEST("require that xw product gives same results as reference join/reduce") {
    // 1 -> 1 happy/unhappy
    TEST_DO(verify_optimized("reduce(y1*x1y1,sum,y)", 1, 1, true));
    TEST_DO(verify_optimized("reduce(y1*y1z1,sum,y)", 1, 1, false));
    // 3 -> 2 happy/unhappy
    TEST_DO(verify_optimized("reduce(y3*x2y3,sum,y)", 3, 2, true));
    TEST_DO(verify_optimized("reduce(y3*y3z2,sum,y)", 3, 2, false));
    // 5 -> 8 happy/unhappy
    TEST_DO(verify_optimized("reduce(y5*x8y5,sum,y)", 5, 8, true));
    TEST_DO(verify_optimized("reduce(y5*y5z8,sum,y)", 5, 8, false));
    // 16 -> 5 happy/unhappy
    TEST_DO(verify_optimized("reduce(y16*x5y16,sum,y)", 16, 5, true));
    TEST_DO(verify_optimized("reduce(y16*y16z5,sum,y)", 16, 5, false));
}

TEST("require that various variants of xw product can be optimized") {
    TEST_DO(verify_optimized("reduce(y3*x2y3,sum,y)", 3, 2, true));
    TEST_DO(verify_optimized("reduce(x2y3*y3,sum,y)", 3, 2, true));
    TEST_DO(verify_optimized("reduce(join(y3,x2y3,f(x,y)(x*y)),sum,y)", 3, 2, true));
    TEST_DO(verify_optimized("reduce(join(x2y3,y3,f(x,y)(x*y)),sum,y)", 3, 2, true));
}

TEST("require that expressions similar to xw product are not optimized") {
    TEST_DO(verify_not_optimized("reduce(y3*x2y3,sum,x)"));
    TEST_DO(verify_not_optimized("reduce(y3*x2y3,prod,y)"));
    TEST_DO(verify_not_optimized("reduce(y3*x2y3,sum)"));
    TEST_DO(verify_not_optimized("reduce(join(y3,x2y3,f(x,y)(x+y)),sum,y)"));
    // TEST_DO(verify_not_optimized("reduce(join(y3,x2y3,f(x,y)(y*x)),sum,y)"));
    TEST_DO(verify_not_optimized("reduce(join(y3,x2y3,f(x,y)(x*x)),sum,y)"));
    TEST_DO(verify_not_optimized("reduce(join(y3,x2y3,f(x,y)(y*y)),sum,y)"));
    TEST_DO(verify_not_optimized("reduce(join(y3,x2y3,f(x,y)(y*x*1)),sum,y)"));
}

TEST("require that xw products with incompatible dimensions are not optimized") {
    TEST_DO(verify_not_optimized("reduce(y3*x2z3,sum,y)"));
    TEST_DO(verify_not_optimized("reduce(y3*x2z3,sum,z)"));
}

TEST("require that xw product can be debug dumped") {
    EvalFixture fixture(prod_engine, "reduce(y5*x8y5,sum,y)", param_repo, true);
    auto info = fixture.find_all<DenseXWProductFunction>();
    ASSERT_EQUAL(info.size(), 1u);
    EXPECT_TRUE(info[0]->result_is_mutable());
    fprintf(stderr, "%s\n", info[0]->as_string().c_str());
}

TEST("require that optimization works for float cells") {
    TEST_DO(verify_optimized("reduce(y3f*x2y3,sum,y)", 3, 2, true));
    TEST_DO(verify_optimized("reduce(y3*x2y3f,sum,y)", 3, 2, true));
    TEST_DO(verify_optimized("reduce(y3f*x2y3f,sum,y)", 3, 2, true));
}

TEST("require that optimization works for float cells with inconvenient dimension nesting") {
    TEST_DO(verify_optimized("reduce(y3f*y3z2,sum,y)", 3, 2, false));
    TEST_DO(verify_optimized("reduce(y3*y3z2f,sum,y)", 3, 2, false));
    TEST_DO(verify_optimized("reduce(y3f*y3z2f,sum,y)", 3, 2, false));
}

TEST_MAIN() { TEST_RUN_ALL(); }
<commit_msg>better coverage of cell type and parameter ordering<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/eval/eval/tensor_function.h>
#include <vespa/eval/eval/operation.h>
#include <vespa/eval/eval/simple_tensor.h>
#include <vespa/eval/eval/simple_tensor_engine.h>
#include <vespa/eval/tensor/default_tensor_engine.h>
#include <vespa/eval/tensor/dense/dense_xw_product_function.h>
#include <vespa/eval/tensor/dense/dense_tensor.h>
#include <vespa/eval/tensor/dense/dense_tensor_view.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/eval/test/eval_fixture.h>

#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/stash.h>

using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;
using namespace vespalib::tensor;
using namespace vespalib::eval::tensor_function;

const TensorEngine &prod_engine = DefaultTensorEngine::ref();

struct First {
    bool value;
    explicit First(bool value_in) : value(value_in) {}
    operator bool() const { return value; }
};

struct MyVecSeq : Sequence {
    double operator[](size_t i) const override { return (3.0 + i) * 7.0; }
};

struct MyMatSeq : Sequence {
    double operator[](size_t i) const override { return (5.0 + i) * 43.0; }
};

void add_vector(EvalFixture::ParamRepo &repo, const char *d1, size_t s1) {
    auto name = make_string("%s%zu", d1, s1);
    auto layout = Layout({{d1, s1}});
    repo.add(name, spec(layout, MyVecSeq()));
    repo.add(name + "f", spec(float_cells(layout), MyVecSeq()));
}

void add_matrix(EvalFixture::ParamRepo &repo, const char *d1, size_t s1, const char *d2, size_t s2) {
    auto name = make_string("%s%zu%s%zu", d1, s1, d2, s2);
    auto layout = Layout({{d1, s1}, {d2, s2}});
    repo.add(name, spec(layout, MyMatSeq()));
    repo.add(name + "f", spec(float_cells(layout), MyMatSeq()));
}

EvalFixture::ParamRepo make_params() {
    EvalFixture::ParamRepo repo;
    add_vector(repo, "y",  1);
    add_vector(repo, "y",  3);
    add_vector(repo, "y",  5);
    add_vector(repo, "y", 16);
    add_matrix(repo, "x",  1, "y",  1);
    add_matrix(repo, "y",  1, "z",  1);
    add_matrix(repo, "x",  2, "y",  3);
    add_matrix(repo, "y",  3, "z",  2);
    add_matrix(repo, "x",  2, "z",  3);
    add_matrix(repo, "x",  8, "y",  5);
    add_matrix(repo, "y",  5, "z",  8);
    add_matrix(repo, "x",  5, "y", 16);
    add_matrix(repo, "y", 16, "z",  5);
    return repo;
}
EvalFixture::ParamRepo param_repo = make_params();

void verify_optimized(const vespalib::string &expr, size_t vec_size, size_t res_size, bool happy) {
    EvalFixture slow_fixture(prod_engine, expr, param_repo, false);
    EvalFixture fixture(prod_engine, expr, param_repo, true);
    EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
    EXPECT_EQUAL(fixture.result(), slow_fixture.result());
    auto info = fixture.find_all<DenseXWProductFunction>();
    ASSERT_EQUAL(info.size(), 1u);
    EXPECT_TRUE(info[0]->result_is_mutable());
    EXPECT_EQUAL(info[0]->vectorSize(), vec_size);
    EXPECT_EQUAL(info[0]->resultSize(), res_size);
    EXPECT_EQUAL(info[0]->matrixHasCommonDimensionInnermost(), happy);
}

vespalib::string make_expr(const vespalib::string &a, const vespalib::string &b, const vespalib::string &common,
                           bool float_a, bool float_b)
{
    return make_string("reduce(%s%s*%s%s,sum,%s)", a.c_str(), float_a ? "f" : "", b.c_str(), float_b ? "f" : "", common.c_str());
}

void verify_optimized_multi(const vespalib::string &a, const vespalib::string &b, const vespalib::string &common,
                            size_t vec_size, size_t res_size, bool happy, First first = First(true))
{
    for (bool float_a: {false, true}) {
        for (bool float_b: {false, true}) {
            auto expr = make_expr(a, b, common, float_a, float_b);
            TEST_STATE(expr.c_str());
            TEST_DO(verify_optimized(expr, vec_size, res_size, happy));
        }
    }
    if (first) {
        TEST_DO(verify_optimized_multi(b, a, common, vec_size, res_size, happy, First(false)));
    }
}

void verify_not_optimized(const vespalib::string &expr) {
    EvalFixture slow_fixture(prod_engine, expr, param_repo, false);
    EvalFixture fixture(prod_engine, expr, param_repo, true);
    EXPECT_EQUAL(fixture.result(), EvalFixture::ref(expr, param_repo));
    EXPECT_EQUAL(fixture.result(), slow_fixture.result());
    auto info = fixture.find_all<DenseXWProductFunction>();
    EXPECT_TRUE(info.empty());
}

TEST("require that xw product gives same results as reference join/reduce") {
    // 1 -> 1 happy/unhappy
    TEST_DO(verify_optimized_multi("y1", "x1y1", "y", 1, 1, true));
    TEST_DO(verify_optimized_multi("y1", "y1z1", "y", 1, 1, false));
    // 3 -> 2 happy/unhappy
    TEST_DO(verify_optimized_multi("y3", "x2y3", "y", 3, 2, true));
    TEST_DO(verify_optimized_multi("y3", "y3z2", "y", 3, 2, false));
    // 5 -> 8 happy/unhappy
    TEST_DO(verify_optimized_multi("y5", "x8y5", "y", 5, 8, true));
    TEST_DO(verify_optimized_multi("y5", "y5z8", "y", 5, 8, false));
    // 16 -> 5 happy/unhappy
    TEST_DO(verify_optimized_multi("y16", "x5y16", "y", 16, 5, true));
    TEST_DO(verify_optimized_multi("y16", "y16z5", "y", 16, 5, false));
}

TEST("require that various variants of xw product can be optimized") {
    TEST_DO(verify_optimized("reduce(join(y3,x2y3,f(x,y)(x*y)),sum,y)", 3, 2, true));
    TEST_DO(verify_optimized("reduce(join(y3,x2y3,f(x,y)(y*x)),sum,y)", 3, 2, true));
}

TEST("require that expressions similar to xw product are not optimized") {
    TEST_DO(verify_not_optimized("reduce(y3*x2y3,sum,x)"));
    TEST_DO(verify_not_optimized("reduce(y3*x2y3,prod,y)"));
    TEST_DO(verify_not_optimized("reduce(y3*x2y3,sum)"));
    TEST_DO(verify_not_optimized("reduce(join(y3,x2y3,f(x,y)(x+y)),sum,y)"));
    TEST_DO(verify_not_optimized("reduce(join(y3,x2y3,f(x,y)(x*x)),sum,y)"));
    TEST_DO(verify_not_optimized("reduce(join(y3,x2y3,f(x,y)(y*y)),sum,y)"));
    TEST_DO(verify_not_optimized("reduce(join(y3,x2y3,f(x,y)(y*x*1)),sum,y)"));
    TEST_DO(verify_not_optimized("reduce(y3*x2z3,sum,y)"));
    TEST_DO(verify_not_optimized("reduce(y3*x2z3,sum,z)"));
}

TEST("require that xw product can be debug dumped") {
    EvalFixture fixture(prod_engine, "reduce(y5*x8y5,sum,y)", param_repo, true);
    auto info = fixture.find_all<DenseXWProductFunction>();
    ASSERT_EQUAL(info.size(), 1u);
    EXPECT_TRUE(info[0]->result_is_mutable());
    fprintf(stderr, "%s\n", info[0]->as_string().c_str());
}

TEST_MAIN() { TEST_RUN_ALL(); }
<|endoftext|>