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

// NaCl module Pepper extensions interface.  Audio API.
// This file implements the untrusted client interface to audio.

#include "native_client/src/shared/npruntime/audio.h"

#include <inttypes.h>
#include <stdlib.h>
#include <nacl/nacl_inttypes.h>
#include <sys/errno.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <limits>
#include <map>
#include <utility>

#include "native_client/src/include/portability_string.h"
#include "gen/native_client/src/shared/npruntime/npmodule_rpc.h"
#include "native_client/src/shared/npruntime/npnavigator.h"
#include "native_client/src/shared/npruntime/pointer_translations.h"
#include "native_client/src/shared/srpc/nacl_srpc.h"
#include "third_party/npapi/bindings/npapi_extensions.h"

using nacl::NPClosureTable;
using nacl::NPNavigator;
using nacl::NPPToWireFormat;
using nacl::DebugPrintf;

namespace {

static const int kInvalidDesc = -1;

struct AudioImpl {
 public:
  NPDeviceContextAudio* context;
  int shared_memory_desc;
  size_t shared_memory_size;
  int sync_desc;
};

static NPError QueryCapability(NPP instance,
                               int32 capability,
                               int32 *value) {
  // UNREFERENCED_PARAMETER(instance);
  // UNREFERENCED_PARAMETER(capability);
  // UNREFERENCED_PARAMETER(value);
  // There is no corresponding function in the trusted pepper implementation.
  return NPERR_GENERIC_ERROR;
}

static NPError QueryConfig(NPP instance,
                           const NPDeviceConfig* request,
                           NPDeviceConfig* obtain) {
  // UNREFERENCED_PARAMETER(instance);
  // UNREFERENCED_PARAMETER(request);
  // UNREFERENCED_PARAMETER(obtain);
  // There is no corresponding function in the trusted pepper implementation.
  return NPERR_GENERIC_ERROR;
}

static NPError InitializeContext(NPP instance,
                                 const NPDeviceConfig* config,
                                 NPDeviceContext* context) {
  DebugPrintf("Audio::InitializeContext %p %p\n",
              reinterpret_cast<const void*>(config),
              reinterpret_cast<void*>(context));
  const NPDeviceContextAudioConfig* config_audio =
      reinterpret_cast<const NPDeviceContextAudioConfig*>(config);
  NPDeviceContextAudio* context_audio =
      reinterpret_cast<NPDeviceContextAudio*>(context);

  // Initialize the context structure.
  context_audio->config = *config_audio;
  context_audio->outBuffer = NULL;
  context_audio->inBuffer = NULL;
  context_audio->reserved = NULL;

  DebugPrintf("Set the config and base stuff\n");
  // Get the configuration parameters for passing.
  // TODO(sehr): the SRPC generators speak int32_t, while npruntime likes
  // int32.  Find a way to avoid all these casts.
  int32_t sample_rate = static_cast<int32_t>(config_audio->sampleRate);
  int32_t sample_type = static_cast<int32_t>(config_audio->sampleType);
  int32_t output_channel_map =
      static_cast<int32_t>(config_audio->outputChannelMap);
  int32_t input_channel_map =
      static_cast<int32_t>(config_audio->inputChannelMap);
  int32_t sample_frame_count =
      static_cast<int32_t>(config_audio->sampleFrameCount);
  int32_t flags = static_cast<int32_t>(config_audio->flags);
  DebugPrintf("Set the configs\n");

  // Create an implementation structure to hold the descriptors
  // when they are returned.
  AudioImpl* impl = new(std::nothrow) AudioImpl();
  if (NULL == impl) {
    return NPERR_GENERIC_ERROR;
  }
  DebugPrintf("Created the impl\n");
  context_audio->reserved = reinterpret_cast<void*>(impl);
  // Remember the context this is for so that the callback can get it.
  impl->context = context_audio;
  // Create a closure to be called when NPModule calls us back with
  // the descriptors.  We are remembering the user-supplied callback
  // function and our implementation data.  When the RPC to invoke the
  // callback comes from the browser, we will copy some descriptors into
  // the implementation and then invoke the user-supplied callback with
  // the context.
  uint32_t id;
  NPNavigator* nav = NPNavigator::GetNavigator();
  NPClosureTable::FunctionPointer func =
      reinterpret_cast<NPClosureTable::FunctionPointer>(
          context_audio->config.callback);
  // Pedantic mode refuses zu format, hence casting to void*. The cast to size_t
  // fixes the GCC warning about the cast of function ptr to data ptr.
  DebugPrintf("Created the closure %p for %p\n",
              reinterpret_cast<void*>(reinterpret_cast<size_t>(func)),
              reinterpret_cast<void*>(
                  reinterpret_cast<size_t>(context_audio->config.callback)));
  if (NULL == nav->closure_table() ||
      !nav->closure_table()->Add(func,
                                 context_audio->reserved,
                                 &id)) {
    return NPERR_GENERIC_ERROR;
  }
  DebugPrintf("Added the closure %p\n",
              reinterpret_cast<void*>(reinterpret_cast<size_t>(func)));
  // Make the SRPC to request the setup for the context.
  NaClSrpcChannel* channel = nav->channel();
  NaClSrpcError retval =
      AudioRpcClient::AudioInitialize(
          channel,
          NPPToWireFormat(instance),
          id,
          sample_rate,
          sample_type,
          output_channel_map,
          input_channel_map,
          sample_frame_count,
          flags);
  DebugPrintf("Called init\n");
  if (NACL_SRPC_RESULT_OK != retval) {
    return NPERR_GENERIC_ERROR;
  }
  return NPERR_NO_ERROR;
}

static NPError GetStateContext(NPP instance,
                               NPDeviceContext* context,
                               int32 state,
                               intptr_t *value) {
  // UNREFERENCED_PARAMETER(context);
  NPNavigator* nav = NPNavigator::GetNavigator();
  NaClSrpcChannel* channel = nav->channel();
  // Value is only intptr_t to allow passing of the TransportDIB function
  // pointer.  Otherwise they're all int32_t.
  int32_t value32;
  NaClSrpcError retval =
      AudioRpcClient::AudioGetState(
          channel,
          NPPToWireFormat(instance),
          state,
          &value32);
  if (NACL_SRPC_RESULT_OK != retval) {
    return NPERR_GENERIC_ERROR;
  }
  *value = static_cast<intptr_t>(value32);
  return NPERR_NO_ERROR;
}

static NPError SetStateContext(NPP instance,
                               NPDeviceContext* context,
                               int32 state,
                               intptr_t value) {
  // UNREFERENCED_PARAMETER(context);
  NPNavigator* nav = NPNavigator::GetNavigator();
  NaClSrpcChannel* channel = nav->channel();
  // Value is only intptr_t to allow passing of the TransportDIB function
  // pointer.  Otherwise they're all int32_t.  Verify anyway.
  // TODO(sehr,ilewis): use checked_cast<> here.
  if (INT32_MAX < value || INT32_MIN > value) {
    return NPERR_GENERIC_ERROR;
  }
  int32_t value32 = static_cast<int32_t>(value);
  NaClSrpcError retval =
      AudioRpcClient::AudioSetState(
          channel,
          NPPToWireFormat(instance),
          state,
          value32);
  if (NACL_SRPC_RESULT_OK != retval) {
    return NPERR_GENERIC_ERROR;
  }
  return NPERR_NO_ERROR;
}

static NPError FlushContext(NPP instance,
                            NPDeviceContext* context,
                            NPDeviceFlushContextCallbackPtr callback,
                            void* userData) {
  // UNREFERENCED_PARAMETER(instance);
  // UNREFERENCED_PARAMETER(context);
  // UNREFERENCED_PARAMETER(callback);
  // UNREFERENCED_PARAMETER(userData);
  // NOTE: this method does not appear to be used in the current version of the
  // Pepper API.  Instead, the callback from InitializeContext invokes a method
  // that will synchronize by means of impl->sync_desc.
  return NPERR_GENERIC_ERROR;
}

static NPError DestroyContext(NPP instance, NPDeviceContext* context) {
  NPDeviceContextAudio* context_audio =
      reinterpret_cast<NPDeviceContextAudio*>(context);
  AudioImpl* impl = NULL;
  // If the context wasn't initialized, return an error.
  if (NULL == context_audio->reserved) {
    return NPERR_GENERIC_ERROR;
  }
  impl = reinterpret_cast<AudioImpl*>(context_audio->reserved);
  if (NULL != context_audio->outBuffer) {
    munmap(context_audio->outBuffer, impl->shared_memory_size);
    context_audio->outBuffer = NULL;
  }
  // Close the shared memory descriptor.
  if (kInvalidDesc != impl->shared_memory_desc) {
    close(impl->shared_memory_desc);
  }
  // Close the sync descriptor.
  if (kInvalidDesc != impl->sync_desc) {
    close(impl->sync_desc);
  }
  // Remove the implementation artifacts.
  delete impl;
  context_audio->reserved = NULL;
  // And destroy the corresponding structure in the renderer.
  NPNavigator* nav = NPNavigator::GetNavigator();
  NaClSrpcChannel* channel = nav->channel();
  NaClSrpcError retval =
      AudioRpcClient::AudioDestroy(
          channel,
          NPPToWireFormat(instance));
  if (NACL_SRPC_RESULT_OK != retval) {
    return NPERR_GENERIC_ERROR;
  }
  return NPERR_NO_ERROR;
}

NPError CreateBuffer(NPP instance,
                     NPDeviceContext* context,
                     size_t size,
                     int32* id) {
  // There is no corresponding function in the trusted pepper implementation.
  return NPERR_GENERIC_ERROR;
}

NPError DestroyBuffer(NPP instance,
                      NPDeviceContext* context,
                      int32 id) {
  // There is no corresponding function in the trusted pepper implementation.
  return NPERR_GENERIC_ERROR;
}

NPError MapBuffer(NPP instance,
                  NPDeviceContext* context,
                  int32 id,
                  NPDeviceBuffer* buffer) {
  // There is no corresponding function in the trusted pepper implementation.
  return NPERR_GENERIC_ERROR;
}

static void* AudioCallbackThread(void* data) {
  NPDeviceContextAudio* context_audio =
      reinterpret_cast<NPDeviceContextAudio*>(data);
  DebugPrintf("AudioCallbackThread %p\n", data);
  if (NULL == context_audio) {
    return NULL;
  }
  DebugPrintf("AudioCallbackThread impl %p\n", context_audio->reserved);
  AudioImpl* impl = reinterpret_cast<AudioImpl*>(context_audio->reserved);
  if (NULL == impl) {
    return NULL;
  }
  DebugPrintf("AudioCallbackThread entering loop\n");
  int pending_data;
  while (sizeof(pending_data) ==
         read(impl->sync_desc, &pending_data, sizeof(pending_data))) {
    DebugPrintf("invoking callback\n");
    if (NULL != context_audio->config.callback) {
      context_audio->config.callback(context_audio);
    }
  }
  return NULL;
}

}  // namespace

namespace nacl {

const NPDevice* GetAudio() {
  static const struct NPDevice deviceAudio = {
    QueryCapability,
    QueryConfig,
    InitializeContext,
    SetStateContext,
    GetStateContext,
    FlushContext,
    DestroyContext,
    CreateBuffer,
    DestroyBuffer,
    MapBuffer
  };

  return &deviceAudio;
}

bool DoAudioCallback(NPClosureTable* closure_table,
                     int32_t number,
                     int shm_desc,
                     int32_t shm_size,
                     int sync_desc) {
  uint32_t id = static_cast<uint32_t>(number);
  NPClosureTable::FunctionPointer func;
  void* user_data;
  DebugPrintf("DoAudioCallback\n");
  if (NULL == closure_table ||
      !closure_table->Remove(id, &func, &user_data) ||
      NULL == func ||
      NULL == user_data) {
    return false;
  }
  // Place the returned handle in the struct passed as user_data.
  AudioImpl* impl = reinterpret_cast<AudioImpl*>(user_data);
  impl->sync_desc = sync_desc;
  impl->shared_memory_desc = shm_desc;
  impl->shared_memory_size = shm_size;
  void* buf = mmap(NULL,
                   shm_size,
                   PROT_READ | PROT_WRITE,
                   MAP_SHARED,
                   shm_desc,
                   0);
  if (MAP_FAILED == buf) {
    DebugPrintf("mmap failed %"NACL_PRIx32" %d %d\n",
                shm_size, shm_desc, sync_desc);
    return false;
  }
  DebugPrintf("mmap succeeded %p\n", buf);
  impl->context->outBuffer = buf;
  if (impl->context->config.startThread) {
    DebugPrintf("starting thread\n");
    pthread_t callback_thread;
    int ret = pthread_create(&callback_thread,
                             NULL,
                             AudioCallbackThread,
                             impl->context);
    if (0 != ret) {
      DebugPrintf("Thread creation failed %d %d\n", ret, errno);
      return false;
    }
  } else {
    // Invoke the function with the data.
    (*func)(reinterpret_cast<void*>(impl->context));
  }
  // Return success.
  return true;
}

}  // namespace nacl
<commit_msg>Nexuiz is specifying "--wrap read" to the linker, which changes all undefined calls to read to __wrap_read.  The audio thread needs the syscall read to read the SyncSocket, so I am adding a local definition of the wrapper for that syscall.<commit_after>// Copyright (c) 2010 The Native Client Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// NaCl module Pepper extensions interface.  Audio API.
// This file implements the untrusted client interface to audio.

#include "native_client/src/shared/npruntime/audio.h"

#include <inttypes.h>
#include <stdlib.h>
#include <nacl/nacl_inttypes.h>
#include <sys/errno.h>
#include <sys/mman.h>
#include <sys/nacl_syscalls.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <limits>
#include <map>
#include <utility>

#include "native_client/src/include/portability_string.h"
#include "gen/native_client/src/shared/npruntime/npmodule_rpc.h"
#include "native_client/src/shared/npruntime/npnavigator.h"
#include "native_client/src/shared/npruntime/pointer_translations.h"
#include "native_client/src/shared/srpc/nacl_srpc.h"
#include "native_client/src/untrusted/nacl/syscall_bindings_trampoline.h"
#include "third_party/npapi/bindings/npapi_extensions.h"

using nacl::NPClosureTable;
using nacl::NPNavigator;
using nacl::NPPToWireFormat;
using nacl::DebugPrintf;

namespace {

static const int kInvalidDesc = -1;

struct AudioImpl {
 public:
  NPDeviceContextAudio* context;
  int shared_memory_desc;
  size_t shared_memory_size;
  int sync_desc;
};

static NPError QueryCapability(NPP instance,
                               int32 capability,
                               int32 *value) {
  // UNREFERENCED_PARAMETER(instance);
  // UNREFERENCED_PARAMETER(capability);
  // UNREFERENCED_PARAMETER(value);
  // There is no corresponding function in the trusted pepper implementation.
  return NPERR_GENERIC_ERROR;
}

static NPError QueryConfig(NPP instance,
                           const NPDeviceConfig* request,
                           NPDeviceConfig* obtain) {
  // UNREFERENCED_PARAMETER(instance);
  // UNREFERENCED_PARAMETER(request);
  // UNREFERENCED_PARAMETER(obtain);
  // There is no corresponding function in the trusted pepper implementation.
  return NPERR_GENERIC_ERROR;
}

static NPError InitializeContext(NPP instance,
                                 const NPDeviceConfig* config,
                                 NPDeviceContext* context) {
  DebugPrintf("Audio::InitializeContext %p %p\n",
              reinterpret_cast<const void*>(config),
              reinterpret_cast<void*>(context));
  const NPDeviceContextAudioConfig* config_audio =
      reinterpret_cast<const NPDeviceContextAudioConfig*>(config);
  NPDeviceContextAudio* context_audio =
      reinterpret_cast<NPDeviceContextAudio*>(context);

  // Initialize the context structure.
  context_audio->config = *config_audio;
  context_audio->outBuffer = NULL;
  context_audio->inBuffer = NULL;
  context_audio->reserved = NULL;

  DebugPrintf("Set the config and base stuff\n");
  // Get the configuration parameters for passing.
  // TODO(sehr): the SRPC generators speak int32_t, while npruntime likes
  // int32.  Find a way to avoid all these casts.
  int32_t sample_rate = static_cast<int32_t>(config_audio->sampleRate);
  int32_t sample_type = static_cast<int32_t>(config_audio->sampleType);
  int32_t output_channel_map =
      static_cast<int32_t>(config_audio->outputChannelMap);
  int32_t input_channel_map =
      static_cast<int32_t>(config_audio->inputChannelMap);
  int32_t sample_frame_count =
      static_cast<int32_t>(config_audio->sampleFrameCount);
  int32_t flags = static_cast<int32_t>(config_audio->flags);
  DebugPrintf("Set the configs\n");

  // Create an implementation structure to hold the descriptors
  // when they are returned.
  AudioImpl* impl = new(std::nothrow) AudioImpl();
  if (NULL == impl) {
    return NPERR_GENERIC_ERROR;
  }
  DebugPrintf("Created the impl\n");
  context_audio->reserved = reinterpret_cast<void*>(impl);
  // Remember the context this is for so that the callback can get it.
  impl->context = context_audio;
  // Create a closure to be called when NPModule calls us back with
  // the descriptors.  We are remembering the user-supplied callback
  // function and our implementation data.  When the RPC to invoke the
  // callback comes from the browser, we will copy some descriptors into
  // the implementation and then invoke the user-supplied callback with
  // the context.
  uint32_t id;
  NPNavigator* nav = NPNavigator::GetNavigator();
  NPClosureTable::FunctionPointer func =
      reinterpret_cast<NPClosureTable::FunctionPointer>(
          context_audio->config.callback);
  // Pedantic mode refuses zu format, hence casting to void*. The cast to size_t
  // fixes the GCC warning about the cast of function ptr to data ptr.
  DebugPrintf("Created the closure %p for %p\n",
              reinterpret_cast<void*>(reinterpret_cast<size_t>(func)),
              reinterpret_cast<void*>(
                  reinterpret_cast<size_t>(context_audio->config.callback)));
  if (NULL == nav->closure_table() ||
      !nav->closure_table()->Add(func,
                                 context_audio->reserved,
                                 &id)) {
    return NPERR_GENERIC_ERROR;
  }
  DebugPrintf("Added the closure %p\n",
              reinterpret_cast<void*>(reinterpret_cast<size_t>(func)));
  // Make the SRPC to request the setup for the context.
  NaClSrpcChannel* channel = nav->channel();
  NaClSrpcError retval =
      AudioRpcClient::AudioInitialize(
          channel,
          NPPToWireFormat(instance),
          id,
          sample_rate,
          sample_type,
          output_channel_map,
          input_channel_map,
          sample_frame_count,
          flags);
  DebugPrintf("Called init\n");
  if (NACL_SRPC_RESULT_OK != retval) {
    return NPERR_GENERIC_ERROR;
  }
  return NPERR_NO_ERROR;
}

static NPError GetStateContext(NPP instance,
                               NPDeviceContext* context,
                               int32 state,
                               intptr_t *value) {
  // UNREFERENCED_PARAMETER(context);
  NPNavigator* nav = NPNavigator::GetNavigator();
  NaClSrpcChannel* channel = nav->channel();
  // Value is only intptr_t to allow passing of the TransportDIB function
  // pointer.  Otherwise they're all int32_t.
  int32_t value32;
  NaClSrpcError retval =
      AudioRpcClient::AudioGetState(
          channel,
          NPPToWireFormat(instance),
          state,
          &value32);
  if (NACL_SRPC_RESULT_OK != retval) {
    return NPERR_GENERIC_ERROR;
  }
  *value = static_cast<intptr_t>(value32);
  return NPERR_NO_ERROR;
}

static NPError SetStateContext(NPP instance,
                               NPDeviceContext* context,
                               int32 state,
                               intptr_t value) {
  // UNREFERENCED_PARAMETER(context);
  NPNavigator* nav = NPNavigator::GetNavigator();
  NaClSrpcChannel* channel = nav->channel();
  // Value is only intptr_t to allow passing of the TransportDIB function
  // pointer.  Otherwise they're all int32_t.  Verify anyway.
  // TODO(sehr,ilewis): use checked_cast<> here.
  if (INT32_MAX < value || INT32_MIN > value) {
    return NPERR_GENERIC_ERROR;
  }
  int32_t value32 = static_cast<int32_t>(value);
  NaClSrpcError retval =
      AudioRpcClient::AudioSetState(
          channel,
          NPPToWireFormat(instance),
          state,
          value32);
  if (NACL_SRPC_RESULT_OK != retval) {
    return NPERR_GENERIC_ERROR;
  }
  return NPERR_NO_ERROR;
}

static NPError FlushContext(NPP instance,
                            NPDeviceContext* context,
                            NPDeviceFlushContextCallbackPtr callback,
                            void* userData) {
  // UNREFERENCED_PARAMETER(instance);
  // UNREFERENCED_PARAMETER(context);
  // UNREFERENCED_PARAMETER(callback);
  // UNREFERENCED_PARAMETER(userData);
  // NOTE: this method does not appear to be used in the current version of the
  // Pepper API.  Instead, the callback from InitializeContext invokes a method
  // that will synchronize by means of impl->sync_desc.
  return NPERR_GENERIC_ERROR;
}

static NPError DestroyContext(NPP instance, NPDeviceContext* context) {
  NPDeviceContextAudio* context_audio =
      reinterpret_cast<NPDeviceContextAudio*>(context);
  AudioImpl* impl = NULL;
  // If the context wasn't initialized, return an error.
  if (NULL == context_audio->reserved) {
    return NPERR_GENERIC_ERROR;
  }
  impl = reinterpret_cast<AudioImpl*>(context_audio->reserved);
  if (NULL != context_audio->outBuffer) {
    munmap(context_audio->outBuffer, impl->shared_memory_size);
    context_audio->outBuffer = NULL;
  }
  // Close the shared memory descriptor.
  if (kInvalidDesc != impl->shared_memory_desc) {
    close(impl->shared_memory_desc);
  }
  // Close the sync descriptor.
  if (kInvalidDesc != impl->sync_desc) {
    close(impl->sync_desc);
  }
  // Remove the implementation artifacts.
  delete impl;
  context_audio->reserved = NULL;
  // And destroy the corresponding structure in the renderer.
  NPNavigator* nav = NPNavigator::GetNavigator();
  NaClSrpcChannel* channel = nav->channel();
  NaClSrpcError retval =
      AudioRpcClient::AudioDestroy(
          channel,
          NPPToWireFormat(instance));
  if (NACL_SRPC_RESULT_OK != retval) {
    return NPERR_GENERIC_ERROR;
  }
  return NPERR_NO_ERROR;
}

NPError CreateBuffer(NPP instance,
                     NPDeviceContext* context,
                     size_t size,
                     int32* id) {
  // There is no corresponding function in the trusted pepper implementation.
  return NPERR_GENERIC_ERROR;
}

NPError DestroyBuffer(NPP instance,
                      NPDeviceContext* context,
                      int32 id) {
  // There is no corresponding function in the trusted pepper implementation.
  return NPERR_GENERIC_ERROR;
}

NPError MapBuffer(NPP instance,
                  NPDeviceContext* context,
                  int32 id,
                  NPDeviceBuffer* buffer) {
  // There is no corresponding function in the trusted pepper implementation.
  return NPERR_GENERIC_ERROR;
}

// Some clients may use --wrap read, which replaces read by a user-specified
// alternate function.  That will cause major problems here as we need to use
// the real read syscall.  To handle this, we add a static binding to the
// real system call.
// TODO(sehr): All of this support will be unnecessary once we have file
// system access from Pepper.  Remove this once we do.
static ssize_t socketread(int desc, void *buf, size_t count) {
  ssize_t retval = NACL_SYSCALL(read)(desc, buf, count);
  if (retval < 0) {
    errno = -retval;
    return -1;
  }
  return retval;
}

static void* AudioCallbackThread(void* data) {
  NPDeviceContextAudio* context_audio =
      reinterpret_cast<NPDeviceContextAudio*>(data);
  DebugPrintf("AudioCallbackThread %p\n", data);
  if (NULL == context_audio) {
    return NULL;
  }
  DebugPrintf("AudioCallbackThread impl %p\n", context_audio->reserved);
  AudioImpl* impl = reinterpret_cast<AudioImpl*>(context_audio->reserved);
  if (NULL == impl) {
    return NULL;
  }
  DebugPrintf("AudioCallbackThread entering loop\n");
  int pending_data;
  while (sizeof(pending_data) ==
         socketread(impl->sync_desc, &pending_data, sizeof(pending_data))) {
    DebugPrintf("invoking callback\n");
    if (NULL != context_audio->config.callback) {
      context_audio->config.callback(context_audio);
    }
  }
  return NULL;
}

}  // namespace

namespace nacl {

const NPDevice* GetAudio() {
  static const struct NPDevice deviceAudio = {
    QueryCapability,
    QueryConfig,
    InitializeContext,
    SetStateContext,
    GetStateContext,
    FlushContext,
    DestroyContext,
    CreateBuffer,
    DestroyBuffer,
    MapBuffer
  };

  return &deviceAudio;
}

bool DoAudioCallback(NPClosureTable* closure_table,
                     int32_t number,
                     int shm_desc,
                     int32_t shm_size,
                     int sync_desc) {
  uint32_t id = static_cast<uint32_t>(number);
  NPClosureTable::FunctionPointer func;
  void* user_data;
  DebugPrintf("DoAudioCallback\n");
  if (NULL == closure_table ||
      !closure_table->Remove(id, &func, &user_data) ||
      NULL == func ||
      NULL == user_data) {
    return false;
  }
  // Place the returned handle in the struct passed as user_data.
  AudioImpl* impl = reinterpret_cast<AudioImpl*>(user_data);
  impl->sync_desc = sync_desc;
  impl->shared_memory_desc = shm_desc;
  impl->shared_memory_size = shm_size;
  void* buf = mmap(NULL,
                   shm_size,
                   PROT_READ | PROT_WRITE,
                   MAP_SHARED,
                   shm_desc,
                   0);
  if (MAP_FAILED == buf) {
    DebugPrintf("mmap failed %"NACL_PRIx32" %d %d\n",
                shm_size, shm_desc, sync_desc);
    return false;
  }
  DebugPrintf("mmap succeeded %p\n", buf);
  impl->context->outBuffer = buf;
  if (impl->context->config.startThread) {
    DebugPrintf("starting thread\n");
    pthread_t callback_thread;
    int ret = pthread_create(&callback_thread,
                             NULL,
                             AudioCallbackThread,
                             impl->context);
    if (0 != ret) {
      DebugPrintf("Thread creation failed %d %d\n", ret, errno);
      return false;
    }
  } else {
    // Invoke the function with the data.
    (*func)(reinterpret_cast<void*>(impl->context));
  }
  // Return success.
  return true;
}

}  // namespace nacl
<|endoftext|>


<commit_before>/*
 * Monitor which expects a string on a TCP connection.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "lb_expect_monitor.hxx"
#include "lb_monitor.hxx"
#include "lb_config.hxx"
#include "pool.hxx"
#include "async.hxx"
#include "gerrno.h"
#include "net/ConnectSocket.hxx"
#include "net/SocketDescriptor.hxx"
#include "net/SocketAddress.hxx"
#include "util/Cast.hxx"

#include <event.h>
#include <unistd.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>

struct ExpectMonitor {
    struct pool *pool;
    const lb_monitor_config *config;

    int fd;

    struct event event;

    LBMonitorHandler *handler;

    struct async_operation_ref *async_ref;
    struct async_operation async_operation;

    ExpectMonitor(struct pool *_pool, const lb_monitor_config *_config,
                  LBMonitorHandler &_handler,
                  async_operation_ref *_async_ref)
        :pool(_pool), config(_config),
         handler(&_handler),
         async_ref(_async_ref) {}

    ExpectMonitor(const ExpectMonitor &other) = delete;
};

static bool
check_expectation(char *received, size_t received_length,
                  const char *expect)
{
    return g_strrstr_len(received, received_length, expect) != NULL;
}

/*
 * async operation
 *
 */

static void
expect_monitor_request_abort(struct async_operation *ao)
{
    ExpectMonitor *expect =
        &ContainerCast2(*ao, &ExpectMonitor::async_operation);

    event_del(&expect->event);
    close(expect->fd);
    pool_unref(expect->pool);
    delete expect;
}

static const struct async_operation_class expect_monitor_async_operation = {
    .abort = expect_monitor_request_abort,
};

/*
 * libevent callback
 *
 */

static void
expect_monitor_event_callback(gcc_unused int fd, short event, void *ctx)
{
    ExpectMonitor *expect =
        (ExpectMonitor *)ctx;

    expect->async_operation.Finished();

    if (event & EV_TIMEOUT) {
        close(expect->fd);
        expect->handler->Timeout();
    } else {
        char buffer[1024];

        ssize_t nbytes = recv(expect->fd, buffer, sizeof(buffer),
                              MSG_DONTWAIT);
        if (nbytes < 0) {
            GError *error = new_error_errno();
            close(fd);
            expect->handler->Error(error);
        } else if (!expect->config->fade_expect.empty() &&
                   check_expectation(buffer, nbytes,
                                     expect->config->fade_expect.c_str())) {
            close(fd);
            expect->handler->Fade();
        } else if (expect->config->expect.empty() ||
                   check_expectation(buffer, nbytes,
                                     expect->config->expect.c_str())) {
            close(fd);
            expect->handler->Success();
        } else {
            close(fd);
            GError *error = g_error_new_literal(g_file_error_quark(), 0,
                                                "Expectation failed");
            expect->handler->Error(error);
        }
    }

    pool_unref(expect->pool);
    delete expect;
    pool_commit();
}

/*
 * client_socket handler
 *
 */

static void
expect_monitor_success(SocketDescriptor &&fd, void *ctx)
{
    ExpectMonitor *expect =
        (ExpectMonitor *)ctx;

    if (!expect->config->send.empty()) {
        ssize_t nbytes = send(fd.Get(), expect->config->send.data(),
                              expect->config->send.length(),
                              MSG_DONTWAIT);
        if (nbytes < 0) {
            GError *error = new_error_errno();
            expect->handler->Error(error);
            return;
        }
    }

    struct timeval expect_timeout = {
        time_t(expect->config->timeout > 0 ? expect->config->timeout : 10),
        0,
    };

    expect->fd = fd.Steal();
    event_set(&expect->event, expect->fd, EV_READ|EV_TIMEOUT,
              expect_monitor_event_callback, expect);
    event_add(&expect->event, &expect_timeout);

    expect->async_operation.Init(expect_monitor_async_operation);
    expect->async_ref->Set(expect->async_operation);

    pool_ref(expect->pool);
}

static void
expect_monitor_timeout(void *ctx)
{
    ExpectMonitor *expect =
        (ExpectMonitor *)ctx;
    expect->handler->Timeout();
    delete expect;
}

static void
expect_monitor_error(GError *error, void *ctx)
{
    ExpectMonitor *expect =
        (ExpectMonitor *)ctx;
    expect->handler->Error(error);
    delete expect;
}

static constexpr ConnectSocketHandler expect_monitor_handler = {
    .success = expect_monitor_success,
    .timeout = expect_monitor_timeout,
    .error = expect_monitor_error,
};

/*
 * lb_monitor_class
 *
 */

static void
expect_monitor_run(struct pool *pool, const struct lb_monitor_config *config,
                   SocketAddress address,
                   LBMonitorHandler &handler,
                   struct async_operation_ref *async_ref)
{
    ExpectMonitor *expect = new ExpectMonitor(pool, config,
                                              handler,
                                              async_ref);

    const unsigned connect_timeout = config->connect_timeout > 0
        ? config->connect_timeout
        : (config->timeout > 0
           ? config->timeout
           : 30);

    client_socket_new(*pool, address.GetFamily(), SOCK_STREAM, 0,
                      false,
                      SocketAddress::Null(),
                      address,
                      connect_timeout,
                      expect_monitor_handler, expect,
                      *async_ref);
}

const struct lb_monitor_class expect_monitor_class = {
    .run = expect_monitor_run,
};
<commit_msg>lb_expect_monitor: use class Event<commit_after>/*
 * Monitor which expects a string on a TCP connection.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "lb_expect_monitor.hxx"
#include "lb_monitor.hxx"
#include "lb_config.hxx"
#include "pool.hxx"
#include "async.hxx"
#include "gerrno.h"
#include "net/ConnectSocket.hxx"
#include "net/SocketDescriptor.hxx"
#include "net/SocketAddress.hxx"
#include "event/Event.hxx"
#include "util/Cast.hxx"

#include <unistd.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>

struct ExpectMonitor {
    struct pool *pool;
    const lb_monitor_config *config;

    int fd;

    Event event;

    LBMonitorHandler *handler;

    struct async_operation_ref *async_ref;
    struct async_operation async_operation;

    ExpectMonitor(struct pool *_pool, const lb_monitor_config *_config,
                  LBMonitorHandler &_handler,
                  async_operation_ref *_async_ref)
        :pool(_pool), config(_config),
         handler(&_handler),
         async_ref(_async_ref) {}

    ExpectMonitor(const ExpectMonitor &other) = delete;
};

static bool
check_expectation(char *received, size_t received_length,
                  const char *expect)
{
    return g_strrstr_len(received, received_length, expect) != NULL;
}

/*
 * async operation
 *
 */

static void
expect_monitor_request_abort(struct async_operation *ao)
{
    ExpectMonitor *expect =
        &ContainerCast2(*ao, &ExpectMonitor::async_operation);

    expect->event.Delete();
    close(expect->fd);
    pool_unref(expect->pool);
    delete expect;
}

static const struct async_operation_class expect_monitor_async_operation = {
    .abort = expect_monitor_request_abort,
};

/*
 * libevent callback
 *
 */

static void
expect_monitor_event_callback(gcc_unused int fd, short event, void *ctx)
{
    ExpectMonitor *expect =
        (ExpectMonitor *)ctx;

    expect->async_operation.Finished();

    if (event & EV_TIMEOUT) {
        close(expect->fd);
        expect->handler->Timeout();
    } else {
        char buffer[1024];

        ssize_t nbytes = recv(expect->fd, buffer, sizeof(buffer),
                              MSG_DONTWAIT);
        if (nbytes < 0) {
            GError *error = new_error_errno();
            close(fd);
            expect->handler->Error(error);
        } else if (!expect->config->fade_expect.empty() &&
                   check_expectation(buffer, nbytes,
                                     expect->config->fade_expect.c_str())) {
            close(fd);
            expect->handler->Fade();
        } else if (expect->config->expect.empty() ||
                   check_expectation(buffer, nbytes,
                                     expect->config->expect.c_str())) {
            close(fd);
            expect->handler->Success();
        } else {
            close(fd);
            GError *error = g_error_new_literal(g_file_error_quark(), 0,
                                                "Expectation failed");
            expect->handler->Error(error);
        }
    }

    pool_unref(expect->pool);
    delete expect;
    pool_commit();
}

/*
 * client_socket handler
 *
 */

static void
expect_monitor_success(SocketDescriptor &&fd, void *ctx)
{
    ExpectMonitor *expect =
        (ExpectMonitor *)ctx;

    if (!expect->config->send.empty()) {
        ssize_t nbytes = send(fd.Get(), expect->config->send.data(),
                              expect->config->send.length(),
                              MSG_DONTWAIT);
        if (nbytes < 0) {
            GError *error = new_error_errno();
            expect->handler->Error(error);
            return;
        }
    }

    struct timeval expect_timeout = {
        time_t(expect->config->timeout > 0 ? expect->config->timeout : 10),
        0,
    };

    expect->fd = fd.Steal();
    expect->event.Set(expect->fd, EV_READ|EV_TIMEOUT,
                      expect_monitor_event_callback, expect);
    expect->event.Add(expect_timeout);

    expect->async_operation.Init(expect_monitor_async_operation);
    expect->async_ref->Set(expect->async_operation);

    pool_ref(expect->pool);
}

static void
expect_monitor_timeout(void *ctx)
{
    ExpectMonitor *expect =
        (ExpectMonitor *)ctx;
    expect->handler->Timeout();
    delete expect;
}

static void
expect_monitor_error(GError *error, void *ctx)
{
    ExpectMonitor *expect =
        (ExpectMonitor *)ctx;
    expect->handler->Error(error);
    delete expect;
}

static constexpr ConnectSocketHandler expect_monitor_handler = {
    .success = expect_monitor_success,
    .timeout = expect_monitor_timeout,
    .error = expect_monitor_error,
};

/*
 * lb_monitor_class
 *
 */

static void
expect_monitor_run(struct pool *pool, const struct lb_monitor_config *config,
                   SocketAddress address,
                   LBMonitorHandler &handler,
                   struct async_operation_ref *async_ref)
{
    ExpectMonitor *expect = new ExpectMonitor(pool, config,
                                              handler,
                                              async_ref);

    const unsigned connect_timeout = config->connect_timeout > 0
        ? config->connect_timeout
        : (config->timeout > 0
           ? config->timeout
           : 30);

    client_socket_new(*pool, address.GetFamily(), SOCK_STREAM, 0,
                      false,
                      SocketAddress::Null(),
                      address,
                      connect_timeout,
                      expect_monitor_handler, expect,
                      *async_ref);
}

const struct lb_monitor_class expect_monitor_class = {
    .run = expect_monitor_run,
};
<|endoftext|>


<commit_before>#include "vector.h"
#include "MinIMU9.h"
#include <stdio.h>

MinIMU9::MinIMU9(I2CBus& i2c) : compass(i2c), gyro(i2c)
{
}

void MinIMU9::checkConnection()
{
    uint8_t result = compass.readMagReg(LSM303_WHO_AM_I_M);
    if (result != 0x3C)
    {
        fprintf(stderr, "Error getting \"Who Am I\" register.\n");
        exit(2);
    }
}

void MinIMU9::enableSensors()
{
    //compass.enableDefault();
    //gyro.enableDefault();

    compass.writeAccReg(LSM303_CTRL_REG1_A, 0x47); // normal power mode, all axes enabled, 50 Hz
    compass.writeAccReg(LSM303_CTRL_REG4_A, 0x20); // 8 g full scale

    compass.writeMagReg(LSM303_MR_REG_M, 0x00); // continuous conversion mode
    // 15 Hz default

    gyro.writeReg(L3G_CTRL_REG1, 0x0F); // normal power mode, all axes enabled, 100 Hz
    gyro.writeReg(L3G_CTRL_REG4, 0x20); // 2000 dps full scale
}

void MinIMU9::loadCalibration()
{
    // TODO: load from ~/.lsm303_mag_cal instead of hardcoding
    mag_min = int_vector(-550, -800, -780);
    mag_max = int_vector(770, 640, 680);
}

// Calculate offsets, assuming the MinIMU is resting
// with is z axis pointing up.
void MinIMU9::measureOffsets()
{
    // LSM303 accelerometer: 8 g sensitivity.  3.8 mg/digit; 1 g = 256.
    // TODO: unify this with the other place in the code where we scale accelerometer readings.
    const int gravity = 256;

    gyro_offset = accel_offset = vector::Zero();
    const int sampleCount = 32;
    for(int i = 0; i < sampleCount; i++)
    {
        gyro.read();
        compass.readAcc();
        gyro_offset += vector_from_ints(&gyro.g);
        accel_offset += vector_from_ints(&compass.a);
        usleep(20*1000);
    }
    gyro_offset /= sampleCount;
    accel_offset /= sampleCount;
    accel_offset(2) -= gravity;

    if (accel_offset.norm() > 50)
    {
        fprintf(stderr, "Unable to calculate accelerometer offset because board was not resting in the correct orientation.\n");
        accel_offset = vector::Zero();
    }
}

vector MinIMU9::readMag()
{
    compass.readMag();
    IMU::m = int_vector_from_ints(&compass.m);

    vector v;
    v(0) = (float)(compass.m[0] - mag_min(0)) / (mag_max(0) - mag_min(0)) * 2 - 1;
    v(1) = (float)(compass.m[1] - mag_min(1)) / (mag_max(1) - mag_min(1)) * 2 - 1;
    v(2) = (float)(compass.m[2] - mag_min(2)) / (mag_max(2) - mag_min(2)) * 2 - 1;
    return v;
}

vector MinIMU9::readAcc()
{
    // LSM303 accelerometer: At 8 g sensitivity, the datasheet says
    // we get 3.9 mg/digit.
    // TODO: double check this figure using the correct datasheet
    const float accel_scale = 0.0039;

    compass.readAcc();
    IMU::a = int_vector_from_ints(&compass.a);
    return ( vector_from_ints(&compass.a) - accel_offset ) * accel_scale;
}

vector MinIMU9::readGyro()
{
    // At the full-scale=2000 dps setting, the gyro datasheet says
    // we get 0.07 dps/digit.
    const float gyro_scale = 0.07 * 3.14159265 / 180;

    gyro.read();
    IMU::g = int_vector_from_ints(&gyro.g);
    return ( vector_from_ints(&gyro.g) - gyro_offset ) * gyro_scale;
}
<commit_msg>New mag calibration<commit_after>#include "vector.h"
#include "MinIMU9.h"
#include <stdio.h>

MinIMU9::MinIMU9(I2CBus& i2c) : compass(i2c), gyro(i2c)
{
}

void MinIMU9::checkConnection()
{
    uint8_t result = compass.readMagReg(LSM303_WHO_AM_I_M);
    if (result != 0x3C)
    {
        fprintf(stderr, "Error getting \"Who Am I\" register.\n");
        exit(2);
    }
}

void MinIMU9::enableSensors()
{
    //compass.enableDefault();
    //gyro.enableDefault();

    compass.writeAccReg(LSM303_CTRL_REG1_A, 0x47); // normal power mode, all axes enabled, 50 Hz
    compass.writeAccReg(LSM303_CTRL_REG4_A, 0x20); // 8 g full scale

    compass.writeMagReg(LSM303_MR_REG_M, 0x00); // continuous conversion mode
    // 15 Hz default

    gyro.writeReg(L3G_CTRL_REG1, 0x0F); // normal power mode, all axes enabled, 100 Hz
    gyro.writeReg(L3G_CTRL_REG4, 0x20); // 2000 dps full scale
}

void MinIMU9::loadCalibration()
{
    // TODO: load from ~/.lsm303_mag_cal instead of hardcoding
    mag_min = int_vector(-525, -746, -728);
    mag_max = int_vector(737, 665, 633);
}

// Calculate offsets, assuming the MinIMU is resting
// with is z axis pointing up.
void MinIMU9::measureOffsets()
{
    // LSM303 accelerometer: 8 g sensitivity.  3.8 mg/digit; 1 g = 256.
    // TODO: unify this with the other place in the code where we scale accelerometer readings.
    const int gravity = 256;

    gyro_offset = accel_offset = vector::Zero();
    const int sampleCount = 32;
    for(int i = 0; i < sampleCount; i++)
    {
        gyro.read();
        compass.readAcc();
        gyro_offset += vector_from_ints(&gyro.g);
        accel_offset += vector_from_ints(&compass.a);
        usleep(20*1000);
    }
    gyro_offset /= sampleCount;
    accel_offset /= sampleCount;
    accel_offset(2) -= gravity;

    if (accel_offset.norm() > 50)
    {
        fprintf(stderr, "Unable to calculate accelerometer offset because board was not resting in the correct orientation.\n");
        accel_offset = vector::Zero();
    }
}

vector MinIMU9::readMag()
{
    compass.readMag();
    IMU::m = int_vector_from_ints(&compass.m);

    vector v;
    v(0) = (float)(compass.m[0] - mag_min(0)) / (mag_max(0) - mag_min(0)) * 2 - 1;
    v(1) = (float)(compass.m[1] - mag_min(1)) / (mag_max(1) - mag_min(1)) * 2 - 1;
    v(2) = (float)(compass.m[2] - mag_min(2)) / (mag_max(2) - mag_min(2)) * 2 - 1;
    return v;
}

vector MinIMU9::readAcc()
{
    // LSM303 accelerometer: At 8 g sensitivity, the datasheet says
    // we get 3.9 mg/digit.
    // TODO: double check this figure using the correct datasheet
    const float accel_scale = 0.0039;

    compass.readAcc();
    IMU::a = int_vector_from_ints(&compass.a);
    return ( vector_from_ints(&compass.a) - accel_offset ) * accel_scale;
}

vector MinIMU9::readGyro()
{
    // At the full-scale=2000 dps setting, the gyro datasheet says
    // we get 0.07 dps/digit.
    const float gyro_scale = 0.07 * 3.14159265 / 180;

    gyro.read();
    IMU::g = int_vector_from_ints(&gyro.g);
    return ( vector_from_ints(&gyro.g) - gyro_offset ) * gyro_scale;
}
<|endoftext|>


<commit_before>
<commit_msg>Delete 1.cpp<commit_after><|endoftext|>


<commit_before>#include <nan.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <v8.h>

#include "napi.h"

extern "C" {
#include "rpi_ws281x/ws2811.h"
}

using namespace v8;

#define DEFAULT_TARGET_FREQ 800000
#define DEFAULT_GPIO_PIN 18
#define DEFAULT_DMANUM 10

#define PARAM_FREQ 1
#define PARAM_DMANUM 2
#define PARAM_GPIONUM 3
#define PARAM_COUNT 4
#define PARAM_INVERT 5
#define PARAM_BRIGHTNESS 6
#define PARAM_STRIP_TYPE 7

ws2811_t ws281x;

/**
 * ws281x.setParam(param:Number, value:Number)
 * wrap setting global params in ws2811_t
 */
void setParam(const Nan::FunctionCallbackInfo<v8::Value> &info) {
  if (info.Length() != 2) {
    Nan::ThrowTypeError("setParam(): expected two params");
    return;
  }

  if (!info[0]->IsNumber()) {
    Nan::ThrowTypeError(
        "setParam(): expected argument 1 to be the parameter-id");
    return;
  }

  if (!info[1]->IsNumber()) {
    Nan::ThrowTypeError("setParam(): expected argument 2 to be the value");
    return;
  }

  const int param = Nan::To<int32_t>(info[0]).FromJust();
  const int value = Nan::To<int32_t>(info[1]).FromJust();

  switch (param) {
    case PARAM_FREQ:
      ws281x.freq = value;
      break;
    case PARAM_DMANUM:
      ws281x.dmanum = value;
      break;

    default:
      Nan::ThrowTypeError("setParam(): invalid parameter-id");
      return;
  }
}
/**
 * ws281x.setChannelParam(channel:Number, param:Number, value:Number)
 *
 * wrap setting params in ws2811_channel_t
 */
void setChannelParam(const Nan::FunctionCallbackInfo<v8::Value> &info) {
  if (info.Length() != 3) {
    Nan::ThrowTypeError("setChannelParam(): missing argument");
    return;
  }

  // retrieve channelNumber from argument 1
  if (!info[0]->IsNumber()) {
    Nan::ThrowTypeError(
        "setChannelParam(): expected argument 1 to be the channel-number");
    return;
  }

  const int channelNumber = Nan::To<int32_t>(info[0]).FromJust();
  if (channelNumber > 1 || channelNumber < 0) {
    Nan::ThrowError("setChannelParam(): invalid chanel-number");
    return;
  }

  if (!info[1]->IsNumber()) {
    Nan::ThrowTypeError(
        "setChannelParam(): expected argument 2 to be the parameter-id");
    return;
  }

  if (!info[2]->IsNumber() && !info[2]->IsBoolean()) {
    Nan::ThrowTypeError(
        "setChannelParam(): expected argument 3 to be the value");
    return;
  }

  ws2811_channel_t *channel = &ws281x.channel[channelNumber];
  const int param = Nan::To<int32_t>(info[1]).FromJust();
  const int value = Nan::To<int32_t>(info[2]).FromJust();

  switch (param) {
    case PARAM_GPIONUM:
      channel->gpionum = value;
      break;
    case PARAM_COUNT:
      channel->count = value;
      break;
    case PARAM_INVERT:
      channel->invert = value;
      break;
    case PARAM_BRIGHTNESS:
      channel->brightness = (uint8_t)value;
      break;
    case PARAM_STRIP_TYPE:
      channel->strip_type = value;
      break;

    default:
      Nan::ThrowTypeError("setChannelParam(): invalid parameter-id");
      return;
  }
}

/**
 * ws281x.setChannelData(channel:Number, buffer:Buffer)
 *
 * wrap copying data to ws2811_channel_t.leds
 */
void setChannelData(const Nan::FunctionCallbackInfo<v8::Value> &info) {
  if (info.Length() != 2) {
    Nan::ThrowTypeError("setChannelData(): missing argument.");
    return;
  }

  // retrieve channelNumber from argument 1
  if (!info[0]->IsNumber()) {
    Nan::ThrowTypeError(
        "setChannelData(): expected argument 1 to be the channel-number.");
    return;
  }

  int channelNumber = Nan::To<int32_t>(info[0]).FromJust();
  if (channelNumber > 1 || channelNumber < 0) {
    Nan::ThrowError("setChannelData(): invalid chanel-number");
    return;
  }
  ws2811_channel_t channel = ws281x.channel[channelNumber];

  // retrieve buffer from argument 2
  if (!node::Buffer::HasInstance(info[1])) {
    Nan::ThrowTypeError("setChannelData(): expected argument 2 to be a Buffer");
    return;
  }
  v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
  auto buffer = info[1]->ToObject(context).ToLocalChecked();
  uint32_t *data = (uint32_t *)node::Buffer::Data(buffer);

  if (channel.count == 0 || channel.leds == NULL) {
    Nan::ThrowError("setChannelData(): channel not ready");
    return;
  }

  const int numBytes = std::min(node::Buffer::Length(buffer),
                                sizeof(ws2811_led_t) * channel.count);

  // FIXME: handle memcpy-result
  memcpy(channel.leds, data, numBytes);
}

/**
 * ws281x.init()
 *
 * wrap ws2811_init()
 */
void init(const Nan::FunctionCallbackInfo<v8::Value> &info) {
  ws2811_return_t ret;

  ret = ws2811_init(&ws281x);
  if (ret != WS2811_SUCCESS) {
    Nan::ThrowError(ws2811_get_return_t_str(ret));
    return;
  }
}

/**
 * ws281x.render()
 *
 * wrap ws2811_wait() and ws2811_render()
 */
void render(const Nan::FunctionCallbackInfo<v8::Value> &info) {
  ws2811_return_t ret;

  ret = ws2811_wait(&ws281x);
  if (ret != WS2811_SUCCESS) {
    Nan::ThrowError(ws2811_get_return_t_str(ret));
    return;
  }

  ret = ws2811_render(&ws281x);
  if (ret != WS2811_SUCCESS) {
    Nan::ThrowError(ws2811_get_return_t_str(ret));
    return;
  }
}

/**
 * ws281x.finalize()
 *
 * wrap ws2811_wait() and ws2811_fini()
 */
void finalize(const Nan::FunctionCallbackInfo<v8::Value> &info) {
  ws2811_return_t ret;

  ret = ws2811_wait(&ws281x);
  if (ret != WS2811_SUCCESS) {
    Nan::ThrowError(ws2811_get_return_t_str(ret));
    return;
  }

  ws2811_fini(&ws281x);
}

/**
 * initializes the module.
 */
void initialize(Local<Object> exports) {
  ws281x.freq = DEFAULT_TARGET_FREQ;
  ws281x.dmanum = DEFAULT_DMANUM;

  NAN_EXPORT(exports, setParam);
  NAN_EXPORT(exports, setChannelParam);
  NAN_EXPORT(exports, setChannelData);
  NAN_EXPORT(exports, init);
  NAN_EXPORT(exports, render);
  NAN_EXPORT(exports, finalize);
}

Napi::Object Init(Napi::Env env, Napi::Object exports) {
    exports.Set(Napi::String::New(env, "init"), Napi::Function::New(env, init));
    exports.Set(Napi::String::New(env, "setBrightness"), Napi::Function::New(env, setBrightness));
    exports.Set(Napi::String::New(env, "reset"), Napi::Function::New(env, reset));
    exports.Set(Napi::String::New(env, "render"), Napi::Function::New(env, render));

    return exports;
}

// vi: ts=2 sw=2 expandtab<commit_msg>fix: remove napi.h dependency<commit_after>#include <nan.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <v8.h>

extern "C" {
#include "rpi_ws281x/ws2811.h"
}

using namespace v8;

#define DEFAULT_TARGET_FREQ 800000
#define DEFAULT_GPIO_PIN 18
#define DEFAULT_DMANUM 10

#define PARAM_FREQ 1
#define PARAM_DMANUM 2
#define PARAM_GPIONUM 3
#define PARAM_COUNT 4
#define PARAM_INVERT 5
#define PARAM_BRIGHTNESS 6
#define PARAM_STRIP_TYPE 7

ws2811_t ws281x;

/**
 * ws281x.setParam(param:Number, value:Number)
 * wrap setting global params in ws2811_t
 */
void setParam(const Nan::FunctionCallbackInfo<v8::Value> &info) {
  if (info.Length() != 2) {
    Nan::ThrowTypeError("setParam(): expected two params");
    return;
  }

  if (!info[0]->IsNumber()) {
    Nan::ThrowTypeError(
        "setParam(): expected argument 1 to be the parameter-id");
    return;
  }

  if (!info[1]->IsNumber()) {
    Nan::ThrowTypeError("setParam(): expected argument 2 to be the value");
    return;
  }

  const int param = Nan::To<int32_t>(info[0]).FromJust();
  const int value = Nan::To<int32_t>(info[1]).FromJust();

  switch (param) {
    case PARAM_FREQ:
      ws281x.freq = value;
      break;
    case PARAM_DMANUM:
      ws281x.dmanum = value;
      break;

    default:
      Nan::ThrowTypeError("setParam(): invalid parameter-id");
      return;
  }
}
/**
 * ws281x.setChannelParam(channel:Number, param:Number, value:Number)
 *
 * wrap setting params in ws2811_channel_t
 */
void setChannelParam(const Nan::FunctionCallbackInfo<v8::Value> &info) {
  if (info.Length() != 3) {
    Nan::ThrowTypeError("setChannelParam(): missing argument");
    return;
  }

  // retrieve channelNumber from argument 1
  if (!info[0]->IsNumber()) {
    Nan::ThrowTypeError(
        "setChannelParam(): expected argument 1 to be the channel-number");
    return;
  }

  const int channelNumber = Nan::To<int32_t>(info[0]).FromJust();
  if (channelNumber > 1 || channelNumber < 0) {
    Nan::ThrowError("setChannelParam(): invalid chanel-number");
    return;
  }

  if (!info[1]->IsNumber()) {
    Nan::ThrowTypeError(
        "setChannelParam(): expected argument 2 to be the parameter-id");
    return;
  }

  if (!info[2]->IsNumber() && !info[2]->IsBoolean()) {
    Nan::ThrowTypeError(
        "setChannelParam(): expected argument 3 to be the value");
    return;
  }

  ws2811_channel_t *channel = &ws281x.channel[channelNumber];
  const int param = Nan::To<int32_t>(info[1]).FromJust();
  const int value = Nan::To<int32_t>(info[2]).FromJust();

  switch (param) {
    case PARAM_GPIONUM:
      channel->gpionum = value;
      break;
    case PARAM_COUNT:
      channel->count = value;
      break;
    case PARAM_INVERT:
      channel->invert = value;
      break;
    case PARAM_BRIGHTNESS:
      channel->brightness = (uint8_t)value;
      break;
    case PARAM_STRIP_TYPE:
      channel->strip_type = value;
      break;

    default:
      Nan::ThrowTypeError("setChannelParam(): invalid parameter-id");
      return;
  }
}

/**
 * ws281x.setChannelData(channel:Number, buffer:Buffer)
 *
 * wrap copying data to ws2811_channel_t.leds
 */
void setChannelData(const Nan::FunctionCallbackInfo<v8::Value> &info) {
  if (info.Length() != 2) {
    Nan::ThrowTypeError("setChannelData(): missing argument.");
    return;
  }

  // retrieve channelNumber from argument 1
  if (!info[0]->IsNumber()) {
    Nan::ThrowTypeError(
        "setChannelData(): expected argument 1 to be the channel-number.");
    return;
  }

  int channelNumber = Nan::To<int32_t>(info[0]).FromJust();
  if (channelNumber > 1 || channelNumber < 0) {
    Nan::ThrowError("setChannelData(): invalid chanel-number");
    return;
  }
  ws2811_channel_t channel = ws281x.channel[channelNumber];

  // retrieve buffer from argument 2
  if (!node::Buffer::HasInstance(info[1])) {
    Nan::ThrowTypeError("setChannelData(): expected argument 2 to be a Buffer");
    return;
  }
  v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
  auto buffer = info[1]->ToObject(context).ToLocalChecked();
  uint32_t *data = (uint32_t *)node::Buffer::Data(buffer);

  if (channel.count == 0 || channel.leds == NULL) {
    Nan::ThrowError("setChannelData(): channel not ready");
    return;
  }

  const int numBytes = std::min(node::Buffer::Length(buffer),
                                sizeof(ws2811_led_t) * channel.count);

  // FIXME: handle memcpy-result
  memcpy(channel.leds, data, numBytes);
}

/**
 * ws281x.init()
 *
 * wrap ws2811_init()
 */
void init(const Nan::FunctionCallbackInfo<v8::Value> &info) {
  ws2811_return_t ret;

  ret = ws2811_init(&ws281x);
  if (ret != WS2811_SUCCESS) {
    Nan::ThrowError(ws2811_get_return_t_str(ret));
    return;
  }
}

/**
 * ws281x.render()
 *
 * wrap ws2811_wait() and ws2811_render()
 */
void render(const Nan::FunctionCallbackInfo<v8::Value> &info) {
  ws2811_return_t ret;

  ret = ws2811_wait(&ws281x);
  if (ret != WS2811_SUCCESS) {
    Nan::ThrowError(ws2811_get_return_t_str(ret));
    return;
  }

  ret = ws2811_render(&ws281x);
  if (ret != WS2811_SUCCESS) {
    Nan::ThrowError(ws2811_get_return_t_str(ret));
    return;
  }
}

/**
 * ws281x.finalize()
 *
 * wrap ws2811_wait() and ws2811_fini()
 */
void finalize(const Nan::FunctionCallbackInfo<v8::Value> &info) {
  ws2811_return_t ret;

  ret = ws2811_wait(&ws281x);
  if (ret != WS2811_SUCCESS) {
    Nan::ThrowError(ws2811_get_return_t_str(ret));
    return;
  }

  ws2811_fini(&ws281x);
}

NAN_MODULE_INIT(InitAll) {
  Set(target, New<String>("init").ToLocalChecked(),
    GetFunction(New<FunctionTemplate>(init)).ToLocalChecked());

  Set(target, New<String>("setBrightness").ToLocalChecked(),
    GetFunction(New<FunctionTemplate>(setBrightness)).ToLocalChecked());

  Set(target, New<String>("reset").ToLocalChecked(),
    GetFunction(New<FunctionTemplate>(reset)).ToLocalChecked());

  Set(target, New<String>("render").ToLocalChecked(),
    GetFunction(New<FunctionTemplate>(render)).ToLocalChecked());

  Set(target, New<String>("finalize").ToLocalChecked(),
    GetFunction(New<FunctionTemplate>(finalize)).ToLocalChecked());
}

NODE_MODULE(addon, InitAll)

// vi: ts=2 sw=2 expandtab<|endoftext|>


<commit_before><commit_msg>sim: Fix clang warning for unused variable<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2009, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// The ExceptionHandler object installs signal handlers for a number of
// signals. We rely on the signal handler running on the thread which crashed
// in order to identify it. This is true of the synchronous signals (SEGV etc),
// but not true of ABRT. Thus, if you send ABRT to yourself in a program which
// uses ExceptionHandler, you need to use tgkill to direct it to the current
// thread.
//
// The signal flow looks like this:
//
//   SignalHandler (uses a global stack of ExceptionHandler objects to find
//        |         one to handle the signal. If the first rejects it, try
//        |         the second etc...)
//        V
//   HandleSignal ----------------------------| (clones a new process which
//        |                                   |  shares an address space with
//   (wait for cloned                         |  the crashed process. This
//     process)                               |  allows us to ptrace the crashed
//        |                                   |  process)
//        V                                   V
//   (set signal handler to             ThreadEntry (static function to bounce
//    SIG_DFL and rethrow,                    |      back into the object)
//    killing the crashed                     |
//    process)                                V
//                                          DoDump  (writes minidump)
//                                            |
//                                            V
//                                         sys_exit
//

// This code is a little fragmented. Different functions of the ExceptionHandler
// class run in a number of different contexts. Some of them run in a normal
// context and are easy to code, others run in a compromised context and the
// restrictions at the top of minidump_writer.cc apply: no libc and use the
// alternative malloc. Each function should have comment above it detailing the
// context which it runs in.

#include "breakpad/linux/exception_handler.h"

#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include <signal.h>
#include <sys/signal.h>
#include <sys/ucontext.h>
#include <sys/user.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <sched.h>

#include "breakpad/linux/linux_syscall_support.h"
#include "breakpad/linux/memory.h"
#include "breakpad/linux/minidump_writer.h"
#include "common/linux/guid_creator.h"

// A wrapper for the tgkill syscall: send a signal to a specific thread.
static int tgkill(pid_t tgid, pid_t tid, int sig) {
  syscall(__NR_tgkill, tgid, tid, sig);
}

namespace google_breakpad {

// The list of signals which we consider to be crashes. The default action for
// all these signals must be Core (see man 7 signal) because we rethrow the
// signal after handling it and expect that it'll be fatal.
static const int kExceptionSignals[] = {
  SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, -1
};

// We can stack multiple exception handlers. In that case, this is the global
// which holds the stack.
std::vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL;
unsigned ExceptionHandler::handler_stack_index_ = 0;
pthread_mutex_t ExceptionHandler::handler_stack_mutex_ =
    PTHREAD_MUTEX_INITIALIZER;

// Runs before crashing: normal context.
ExceptionHandler::ExceptionHandler(const std::string &dump_path,
                                   FilterCallback filter,
                                   MinidumpCallback callback,
                                   void *callback_context,
                                   bool install_handler)
    : filter_(filter),
      callback_(callback),
      callback_context_(callback_context),
      dump_path_(),
      handler_installed_(install_handler),
      crash_handler_(NULL) {
  set_dump_path(dump_path);

  if (install_handler) {
    InstallHandlers();

    pthread_mutex_lock(&handler_stack_mutex_);
      if (handler_stack_ == NULL)
        handler_stack_ = new std::vector<ExceptionHandler *>;
      handler_stack_->push_back(this);
    pthread_mutex_unlock(&handler_stack_mutex_);
  }
}

// Runs before crashing: normal context.
ExceptionHandler::~ExceptionHandler() {
  UninstallHandlers();
}

// Runs before crashing: normal context.
bool ExceptionHandler::InstallHandlers() {
  // We run the signal handlers on an alternative stack because we might have
  // crashed because of a stack overflow.

  // We use this value rather than SIGSTKSZ because we would end up overrunning
  // such a small stack.
  static const unsigned kSigStackSize = 8192;

  signal_stack = malloc(kSigStackSize);
  stack_t stack;
  memset(&stack, 0, sizeof(stack));
  stack.ss_sp = signal_stack;
  stack.ss_size = kSigStackSize;

  if (sigaltstack(&stack, NULL) == -1)
    return false;

  struct sigaction sa;
  memset(&sa, 0, sizeof(sa));
  sigemptyset(&sa.sa_mask);

  // mask all exception signals when we're handling one of them.
  for (unsigned i = 0; kExceptionSignals[i] != -1; ++i)
    sigaddset(&sa.sa_mask, kExceptionSignals[i]);

  sa.sa_sigaction = SignalHandler;
  sa.sa_flags = SA_ONSTACK | SA_SIGINFO;

  for (unsigned i = 0; kExceptionSignals[i] != -1; ++i) {
    struct sigaction* old = new struct sigaction;
    if (sigaction(kExceptionSignals[i], &sa, old) == -1)
      return false;
    old_handlers_.push_back(std::make_pair(kExceptionSignals[i], old));
  }
}

// Runs before crashing: normal context.
void ExceptionHandler::UninstallHandlers() {
  for (unsigned i = 0; i < old_handlers_.size(); ++i) {
    struct sigaction *action =
        reinterpret_cast<struct sigaction*>(old_handlers_[i].second);
    sigaction(old_handlers_[i].first, action, NULL);
    delete action;
  }

  old_handlers_.clear();
}

// Runs before crashing: normal context.
void ExceptionHandler::UpdateNextID() {
  GUID guid;
  char guid_str[kGUIDStringLength + 1];
  if (CreateGUID(&guid) && GUIDToString(&guid, guid_str, sizeof(guid_str))) {
    next_minidump_id_ = guid_str;
    next_minidump_id_c_ = next_minidump_id_.c_str();

    char minidump_path[PATH_MAX];
    snprintf(minidump_path, sizeof(minidump_path), "%s/%s.dmp",
             dump_path_c_,
             guid_str);

    next_minidump_path_ = minidump_path;
    next_minidump_path_c_ = next_minidump_path_.c_str();
  }
}

// This function runs in a compromised context: see the top of the file.
// Runs on the crashing thread.
// static
void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
  // All the exception signals are blocked at this point.

  pthread_mutex_lock(&handler_stack_mutex_);

  if (!handler_stack_->size()) {
    pthread_mutex_unlock(&handler_stack_mutex_);
    return;
  }

  for (int i = handler_stack_->size() - 1; i >= 0; --i) {
    if ((*handler_stack_)[i]->HandleSignal(sig, info, uc)) {
      // successfully handled: We are in an invalid state since an exception
      // signal has been delivered. We don't call the exit handlers because
      // they could end up corrupting on-disk state.
      break;
    }
  }

  pthread_mutex_unlock(&handler_stack_mutex_);

  // Terminate ourselves with the same signal so that our parent knows that we
  // crashed. The default action for all the signals which we catch is Core, so
  // this is the end of us.
  signal(sig, SIG_DFL);
  tgkill(getpid(), sys_gettid(), sig);

  // not reached.
}

struct ThreadArgument {
  pid_t pid;  // the crashing process
  ExceptionHandler* handler;
  const void* context;  // a CrashContext structure
  size_t context_size;
};

// This is the entry function for the cloned process. We are in a compromised
// context here: see the top of the file.
// static
int ExceptionHandler::ThreadEntry(void *arg) {
  const ThreadArgument *thread_arg = reinterpret_cast<ThreadArgument*>(arg);
  return thread_arg->handler->DoDump(thread_arg->pid, thread_arg->context,
                                     thread_arg->context_size) == false;
}

// This function runs in a compromised context: see the top of the file.
// Runs on the crashing thread.
bool ExceptionHandler::HandleSignal(int sig, siginfo_t* info, void* uc) {
  if (filter_ && !filter_(callback_context_))
    return false;

  CrashContext context;
  memcpy(&context.siginfo, info, sizeof(siginfo_t));
  memcpy(&context.context, uc, sizeof(struct ucontext));
  context.tid = sys_gettid();

  if (crash_handler_ && crash_handler_(&context, sizeof(context),
                                       callback_context_))
    return true;

  PageAllocator allocator;
  void* const stack = allocator.Alloc(8000);

  ThreadArgument thread_arg;
  thread_arg.handler = this;
  thread_arg.pid = getpid();
  thread_arg.context = &context;
  thread_arg.context_size = sizeof(context);

  const pid_t child = sys_clone(
      ThreadEntry, stack, CLONE_FILES | CLONE_FS | CLONE_UNTRACED,
      &thread_arg, NULL, NULL, NULL);
  int r, status;
  do {
    r = sys_waitpid(child, &status, __WALL);
  } while (r == -1 && errno == EINTR);

  if (r == -1) {
    static const char msg[] = "ExceptionHandler::HandleSignal: waitpid failed:";
    sys_write(2, msg, sizeof(msg) - 1);
    sys_write(2, strerror(errno), strlen(strerror(errno)));
    sys_write(2, "\n", 1);
  }

  bool success = r != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0;

  if (callback_)
    success = callback_(dump_path_c_, next_minidump_id_c_,
                        callback_context_, success);

  return success;
}

// This function runs in a compromised context: see the top of the file.
// Runs on the cloned process.
bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context,
                              size_t context_size) {
  return google_breakpad::WriteMinidump(
      next_minidump_path_c_, crashing_process, context, context_size);
}

}  // namespace google_breakpad
<commit_msg>Fix a missing include in exception_handler.cc, fix compilation on Jaunty. Review URL: http://codereview.chromium.org/113774<commit_after>// Copyright (c) 2009, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// The ExceptionHandler object installs signal handlers for a number of
// signals. We rely on the signal handler running on the thread which crashed
// in order to identify it. This is true of the synchronous signals (SEGV etc),
// but not true of ABRT. Thus, if you send ABRT to yourself in a program which
// uses ExceptionHandler, you need to use tgkill to direct it to the current
// thread.
//
// The signal flow looks like this:
//
//   SignalHandler (uses a global stack of ExceptionHandler objects to find
//        |         one to handle the signal. If the first rejects it, try
//        |         the second etc...)
//        V
//   HandleSignal ----------------------------| (clones a new process which
//        |                                   |  shares an address space with
//   (wait for cloned                         |  the crashed process. This
//     process)                               |  allows us to ptrace the crashed
//        |                                   |  process)
//        V                                   V
//   (set signal handler to             ThreadEntry (static function to bounce
//    SIG_DFL and rethrow,                    |      back into the object)
//    killing the crashed                     |
//    process)                                V
//                                          DoDump  (writes minidump)
//                                            |
//                                            V
//                                         sys_exit
//

// This code is a little fragmented. Different functions of the ExceptionHandler
// class run in a number of different contexts. Some of them run in a normal
// context and are easy to code, others run in a compromised context and the
// restrictions at the top of minidump_writer.cc apply: no libc and use the
// alternative malloc. Each function should have comment above it detailing the
// context which it runs in.

#include "breakpad/linux/exception_handler.h"

#include <errno.h>
#include <fcntl.h>
#include <linux/limits.h>
#include <sched.h>
#include <signal.h>
#include <sys/mman.h>
#include <sys/signal.h>
#include <sys/syscall.h>
#include <sys/ucontext.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <unistd.h>

#include "breakpad/linux/linux_syscall_support.h"
#include "breakpad/linux/memory.h"
#include "breakpad/linux/minidump_writer.h"
#include "common/linux/guid_creator.h"

// A wrapper for the tgkill syscall: send a signal to a specific thread.
static int tgkill(pid_t tgid, pid_t tid, int sig) {
  syscall(__NR_tgkill, tgid, tid, sig);
}

namespace google_breakpad {

// The list of signals which we consider to be crashes. The default action for
// all these signals must be Core (see man 7 signal) because we rethrow the
// signal after handling it and expect that it'll be fatal.
static const int kExceptionSignals[] = {
  SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, -1
};

// We can stack multiple exception handlers. In that case, this is the global
// which holds the stack.
std::vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL;
unsigned ExceptionHandler::handler_stack_index_ = 0;
pthread_mutex_t ExceptionHandler::handler_stack_mutex_ =
    PTHREAD_MUTEX_INITIALIZER;

// Runs before crashing: normal context.
ExceptionHandler::ExceptionHandler(const std::string &dump_path,
                                   FilterCallback filter,
                                   MinidumpCallback callback,
                                   void *callback_context,
                                   bool install_handler)
    : filter_(filter),
      callback_(callback),
      callback_context_(callback_context),
      dump_path_(),
      handler_installed_(install_handler),
      crash_handler_(NULL) {
  set_dump_path(dump_path);

  if (install_handler) {
    InstallHandlers();

    pthread_mutex_lock(&handler_stack_mutex_);
      if (handler_stack_ == NULL)
        handler_stack_ = new std::vector<ExceptionHandler *>;
      handler_stack_->push_back(this);
    pthread_mutex_unlock(&handler_stack_mutex_);
  }
}

// Runs before crashing: normal context.
ExceptionHandler::~ExceptionHandler() {
  UninstallHandlers();
}

// Runs before crashing: normal context.
bool ExceptionHandler::InstallHandlers() {
  // We run the signal handlers on an alternative stack because we might have
  // crashed because of a stack overflow.

  // We use this value rather than SIGSTKSZ because we would end up overrunning
  // such a small stack.
  static const unsigned kSigStackSize = 8192;

  signal_stack = malloc(kSigStackSize);
  stack_t stack;
  memset(&stack, 0, sizeof(stack));
  stack.ss_sp = signal_stack;
  stack.ss_size = kSigStackSize;

  if (sigaltstack(&stack, NULL) == -1)
    return false;

  struct sigaction sa;
  memset(&sa, 0, sizeof(sa));
  sigemptyset(&sa.sa_mask);

  // mask all exception signals when we're handling one of them.
  for (unsigned i = 0; kExceptionSignals[i] != -1; ++i)
    sigaddset(&sa.sa_mask, kExceptionSignals[i]);

  sa.sa_sigaction = SignalHandler;
  sa.sa_flags = SA_ONSTACK | SA_SIGINFO;

  for (unsigned i = 0; kExceptionSignals[i] != -1; ++i) {
    struct sigaction* old = new struct sigaction;
    if (sigaction(kExceptionSignals[i], &sa, old) == -1)
      return false;
    old_handlers_.push_back(std::make_pair(kExceptionSignals[i], old));
  }
}

// Runs before crashing: normal context.
void ExceptionHandler::UninstallHandlers() {
  for (unsigned i = 0; i < old_handlers_.size(); ++i) {
    struct sigaction *action =
        reinterpret_cast<struct sigaction*>(old_handlers_[i].second);
    sigaction(old_handlers_[i].first, action, NULL);
    delete action;
  }

  old_handlers_.clear();
}

// Runs before crashing: normal context.
void ExceptionHandler::UpdateNextID() {
  GUID guid;
  char guid_str[kGUIDStringLength + 1];
  if (CreateGUID(&guid) && GUIDToString(&guid, guid_str, sizeof(guid_str))) {
    next_minidump_id_ = guid_str;
    next_minidump_id_c_ = next_minidump_id_.c_str();

    char minidump_path[PATH_MAX];
    snprintf(minidump_path, sizeof(minidump_path), "%s/%s.dmp",
             dump_path_c_,
             guid_str);

    next_minidump_path_ = minidump_path;
    next_minidump_path_c_ = next_minidump_path_.c_str();
  }
}

// This function runs in a compromised context: see the top of the file.
// Runs on the crashing thread.
// static
void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
  // All the exception signals are blocked at this point.

  pthread_mutex_lock(&handler_stack_mutex_);

  if (!handler_stack_->size()) {
    pthread_mutex_unlock(&handler_stack_mutex_);
    return;
  }

  for (int i = handler_stack_->size() - 1; i >= 0; --i) {
    if ((*handler_stack_)[i]->HandleSignal(sig, info, uc)) {
      // successfully handled: We are in an invalid state since an exception
      // signal has been delivered. We don't call the exit handlers because
      // they could end up corrupting on-disk state.
      break;
    }
  }

  pthread_mutex_unlock(&handler_stack_mutex_);

  // Terminate ourselves with the same signal so that our parent knows that we
  // crashed. The default action for all the signals which we catch is Core, so
  // this is the end of us.
  signal(sig, SIG_DFL);
  tgkill(getpid(), sys_gettid(), sig);

  // not reached.
}

struct ThreadArgument {
  pid_t pid;  // the crashing process
  ExceptionHandler* handler;
  const void* context;  // a CrashContext structure
  size_t context_size;
};

// This is the entry function for the cloned process. We are in a compromised
// context here: see the top of the file.
// static
int ExceptionHandler::ThreadEntry(void *arg) {
  const ThreadArgument *thread_arg = reinterpret_cast<ThreadArgument*>(arg);
  return thread_arg->handler->DoDump(thread_arg->pid, thread_arg->context,
                                     thread_arg->context_size) == false;
}

// This function runs in a compromised context: see the top of the file.
// Runs on the crashing thread.
bool ExceptionHandler::HandleSignal(int sig, siginfo_t* info, void* uc) {
  if (filter_ && !filter_(callback_context_))
    return false;

  CrashContext context;
  memcpy(&context.siginfo, info, sizeof(siginfo_t));
  memcpy(&context.context, uc, sizeof(struct ucontext));
  context.tid = sys_gettid();

  if (crash_handler_ && crash_handler_(&context, sizeof(context),
                                       callback_context_))
    return true;

  PageAllocator allocator;
  void* const stack = allocator.Alloc(8000);

  ThreadArgument thread_arg;
  thread_arg.handler = this;
  thread_arg.pid = getpid();
  thread_arg.context = &context;
  thread_arg.context_size = sizeof(context);

  const pid_t child = sys_clone(
      ThreadEntry, stack, CLONE_FILES | CLONE_FS | CLONE_UNTRACED,
      &thread_arg, NULL, NULL, NULL);
  int r, status;
  do {
    r = sys_waitpid(child, &status, __WALL);
  } while (r == -1 && errno == EINTR);

  if (r == -1) {
    static const char msg[] = "ExceptionHandler::HandleSignal: waitpid failed:";
    sys_write(2, msg, sizeof(msg) - 1);
    sys_write(2, strerror(errno), strlen(strerror(errno)));
    sys_write(2, "\n", 1);
  }

  bool success = r != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0;

  if (callback_)
    success = callback_(dump_path_c_, next_minidump_id_c_,
                        callback_context_, success);

  return success;
}

// This function runs in a compromised context: see the top of the file.
// Runs on the cloned process.
bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context,
                              size_t context_size) {
  return google_breakpad::WriteMinidump(
      next_minidump_path_c_, crashing_process, context, context_size);
}

}  // namespace google_breakpad
<|endoftext|>


<commit_before>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

Bohrium is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3
of the License, or (at your option) any later version.

Bohrium is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the
GNU Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include "BhBase.hpp"
#include "util.hpp"
#include <ostream>
#include <vector>

namespace bhxx {

template <typename T>
class BhArray {
  public:
    // The data type of each array element
    typedef T scalar_type;
    // The array offset (from the start of the base in number of elements)
    size_t offset;
    // The array shape (size of each dimension in number of elements)
    Shape shape;
    // The array stride (the absolute stride of each dimension in number of elements)
    Stride stride;
    // Pointer to the base of this array
    std::shared_ptr<BhBase> base;

    // Create a new view that points to a new base
    BhArray(Shape shape, Stride stride, const size_t offset = 0)
          : offset(offset),
            shape(std::move(shape)),
            stride(std::move(stride)),
            base(new BhBase(shape.prod()), BhBaseDeleter{}) {
        base->set_type<T>();
    }

    // Create a new view that points to a new base (contiguous stride, row-major)
    BhArray(Shape shape, const size_t offset = 0)
          : BhArray(shape, contiguous_stride(shape), offset) {}

    // Create a view that points to the given base
    BhArray(std::shared_ptr<BhBase> base, Shape shape, Stride stride,
            const size_t offset = 0)
          : offset(offset),
            shape(std::move(shape)),
            stride(std::move(stride)),
            base(std::move(base)) {}

    // Create a view that points to the given base (contiguous stride, row-major)
    BhArray(std::shared_ptr<BhBase> base, Shape shape, const size_t offset = 0)
          : BhArray(std::move(base), shape, contiguous_stride(shape), offset) {}

    // Pretty printing the content of the array
    // TODO: for now it always print the flatten array
    void pprint(std::ostream& os) const;

    //@{
    /** Obtain the data pointer of the base array, not taking
     *  ownership of any kind.
     *
     *  \note This pointer might be a nullptr if the data in
     *        the base is not yet initialised
     *
     * \note You can always force initialisation using
     *  ```
     *      sync(array);
     *      Runtime::instance().flush();
     *  ```
     *  after which ``data()`` should not be nullptr.
     */
    const T* data() const { return static_cast<T*>(base->data); }
    T*       data() { return static_cast<T*>(base->data); }
    //@}
};

template <typename T>
std::ostream& operator<<(std::ostream& os, const BhArray<T>& ary) {
    ary.pprint(os);
    return os;
}

}  // namespace bhxx
<commit_msg>Don't move stuff we still need<commit_after>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

Bohrium is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3
of the License, or (at your option) any later version.

Bohrium is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the
GNU Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include "BhBase.hpp"
#include "util.hpp"
#include <ostream>
#include <vector>

namespace bhxx {

template <typename T>
class BhArray {
  public:
    // The data type of each array element
    typedef T scalar_type;
    // The array offset (from the start of the base in number of elements)
    size_t offset;
    // The array shape (size of each dimension in number of elements)
    Shape shape;
    // The array stride (the absolute stride of each dimension in number of elements)
    Stride stride;
    // Pointer to the base of this array
    std::shared_ptr<BhBase> base;

    // Create a new view that points to a new base
    BhArray(Shape shape, Stride stride, const size_t offset = 0)
          : offset(offset),
            shape(shape),
            stride(std::move(stride)),
            base(new BhBase(shape.prod()), BhBaseDeleter{}) {
        base->set_type<T>();
    }

    // Create a new view that points to a new base (contiguous stride, row-major)
    BhArray(Shape shape, const size_t offset = 0)
          : BhArray(shape, contiguous_stride(shape), offset) {}

    // Create a view that points to the given base
    BhArray(std::shared_ptr<BhBase> base, Shape shape, Stride stride,
            const size_t offset = 0)
          : offset(offset),
            shape(std::move(shape)),
            stride(std::move(stride)),
            base(std::move(base)) {}

    // Create a view that points to the given base (contiguous stride, row-major)
    BhArray(std::shared_ptr<BhBase> base, Shape shape, const size_t offset = 0)
          : BhArray(std::move(base), shape, contiguous_stride(shape), offset) {}

    // Pretty printing the content of the array
    // TODO: for now it always print the flatten array
    void pprint(std::ostream& os) const;

    //@{
    /** Obtain the data pointer of the base array, not taking
     *  ownership of any kind.
     *
     *  \note This pointer might be a nullptr if the data in
     *        the base is not yet initialised
     *
     * \note You can always force initialisation using
     *  ```
     *      sync(array);
     *      Runtime::instance().flush();
     *  ```
     *  after which ``data()`` should not be nullptr.
     */
    const T* data() const { return static_cast<T*>(base->data); }
    T*       data() { return static_cast<T*>(base->data); }
    //@}
};

template <typename T>
std::ostream& operator<<(std::ostream& os, const BhArray<T>& ary) {
    ary.pprint(os);
    return os;
}

}  // namespace bhxx
<|endoftext|>