<commit_before>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Gearmand client and server library.
 *
 *  Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
 *  Copyright (C) 2008 Brian Aker, Eric Day
 *  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.
 *
 *      * The names of its contributors may not 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.
 *
 */

/**
 * @file
 * @brief Gearman State Definitions
 */

#include <config.h>
#include <libgearman-server/common.h>
#include <libgearman-server/timer.h>

#include <algorithm>
#include <cerrno>
#include <cstring>
#include <ctime>

static pthread_key_t logging_key;
static pthread_once_t intitialize_log_once= PTHREAD_ONCE_INIT;

static void delete_log(void *ptr)
{
  if (ptr)
  {
    free(ptr);
  }
}

static void create_log(void)
{
  (void) pthread_key_create(&logging_key, delete_log);
}

void gearmand_initialize_thread_logging(const char *identity)
{
  (void) pthread_once(&intitialize_log_once, create_log);

  if (pthread_getspecific(logging_key) == NULL)
  {
    const char *key_to_use= strdup(identity);
    (void) pthread_setspecific(logging_key, key_to_use);
  }
}

#ifndef __INTEL_COMPILER
#pragma GCC diagnostic ignored "-Wold-style-cast"
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif

/**
 * Log a message.
 *
 * @param[in] gearman Structure previously initialized with gearman_create() or
 *  gearman_clone().
 * @param[in] verbose Logging level of the message.
 * @param[in] format Format and variable argument list of message.
 * @param[in] args Variable argument list that has been initialized.
 */

static void gearmand_log(const char *position, const char *func /* func */,
                         gearmand_verbose_t verbose,
                         const gearmand_error_t error_arg,
                         const char *format, va_list args)
{
  struct timeval current_epoch;

  if (Gearmand() and Gearmand()->verbose < GEARMAND_VERBOSE_DEBUG)
  {
    current_epoch= libgearman::server::Epoch::current();
    current_epoch.tv_usec= 0;
  }
  else
  {
    (void)gettimeofday(&current_epoch, NULL);
  }

  struct tm current_tm;
  if (current_epoch.tv_sec == 0)
  {
    (void)gettimeofday(&current_epoch, NULL);
  }

  if ((gmtime_r(&current_epoch.tv_sec, &current_tm) == NULL))
  {
    memset(&current_epoch, 0, sizeof(current_epoch));
  }

  (void) pthread_once(&intitialize_log_once, create_log);

  const char *identity= (const char *)pthread_getspecific(logging_key);

  if (identity == NULL)
  {
    identity= "[  main ]";
  }

  char log_buffer[GEARMAN_MAX_ERROR_SIZE*2] = { 0 };
  if (Gearmand() && Gearmand()->log_fn)
  {
    char *log_buffer_ptr= log_buffer;
    size_t remaining_size= sizeof(log_buffer);

    {
      int length= snprintf(log_buffer, sizeof(log_buffer), "%04d-%02d-%02d %02d:%02d:%02d.%06d %s ",
                           int(1900 + current_tm.tm_year), current_tm.tm_mon, current_tm.tm_mday, current_tm.tm_hour,
                           current_tm.tm_min, current_tm.tm_sec, int(current_epoch.tv_usec),
                           identity);
      // We just return whatever we have if this occurs
      if (length <= 0 or (size_t)length >= sizeof(log_buffer))
      {
        remaining_size= 0;
      }
      else
      {
        remaining_size-= size_t(length);
        log_buffer_ptr+= length;
      }
    }

    if (remaining_size)
    {
      int length= vsnprintf(log_buffer_ptr, remaining_size, format, args);
      if (length <= 0 or size_t(length) >= remaining_size)
      {
        remaining_size= 0;
      }
      else
      {
        remaining_size-= size_t(length);
        log_buffer_ptr+= length;
      }
    }

    if (remaining_size and error_arg != GEARMAN_SUCCESS)
    {
      int length= snprintf(log_buffer_ptr, remaining_size, " %s(%s)", func, gearmand_strerror(error_arg));
      if (length <= 0 or size_t(length) >= remaining_size)
      {
        remaining_size= 0;
      }
      else
      {
        remaining_size-= size_t(length);
        log_buffer_ptr+= length;
      }
    }

    if (remaining_size and position and verbose != GEARMAND_VERBOSE_INFO)
    {
      int length= snprintf(log_buffer_ptr, remaining_size, " -> %s", position);
      if (length <= 0 or size_t(length) >= remaining_size)
      {
        remaining_size= 0;
      }
    }

    // Make sure this is null terminated
    log_buffer[sizeof(log_buffer) -1]= 0;
  }

  if (Gearmand() and Gearmand()->log_fn)
  {
    Gearmand()->log_fn(log_buffer, verbose, (void *)Gearmand()->log_context);
  }
  else
  {
    fprintf(stderr, "%s -> %s",
            log_buffer,  gearmand_verbose_name(verbose));
    vfprintf(stderr, format, args);
    fprintf(stderr, "\n");
  }
}

void gearmand_log_fatal(const char *position, const char *func, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_FATAL)
  {
    va_start(args, format);
    gearmand_log(position, func, GEARMAND_VERBOSE_FATAL, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

void gearmand_log_fatal_perror(const char *position, const char *function, const char *message)
{
  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_FATAL)
  {
    const char *errmsg_ptr;
    char errmsg[GEARMAN_MAX_ERROR_SIZE];
    errmsg[0]= 0;

#ifdef STRERROR_R_CHAR_P
    errmsg_ptr= strerror_r(errno, errmsg, sizeof(errmsg));
#else
    strerror_r(errno, errmsg, sizeof(errmsg));
    errmsg_ptr= errmsg;
#endif

    gearmand_log_fatal(position, function, "%s(%s)", message, errmsg_ptr);
  }
}

gearmand_error_t gearmand_log_error(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() or Gearmand()->verbose >= GEARMAND_VERBOSE_ERROR)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_ERROR, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }

  return GEARMAN_UNKNOWN_OPTION;
}

void gearmand_log_warning(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_WARN)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_WARN, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

// LOG_NOTICE is only used for reporting job status.
void gearmand_log_notice(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_NOTICE)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_NOTICE, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

void gearmand_log_info(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_INFO)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_INFO, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

void gearmand_log_debug(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_DEBUG)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_DEBUG, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

gearmand_error_t gearmand_log_perror(const char *position, const char *function, const char *message)
{
  if (not Gearmand() or (Gearmand()->verbose >= GEARMAND_VERBOSE_ERROR))
  {
    const char *errmsg_ptr;
    char errmsg[GEARMAN_MAX_ERROR_SIZE];
    errmsg[0]= 0;

#ifdef STRERROR_R_CHAR_P
    errmsg_ptr= strerror_r(errno, errmsg, sizeof(errmsg));
#else
    strerror_r(errno, errmsg, sizeof(errmsg));
    errmsg_ptr= errmsg;
#endif
    gearmand_log_error(position, function, "%s(%s)", message, errmsg_ptr);
  }

  return GEARMAN_ERRNO;
}

gearmand_error_t gearmand_log_gerror(const char *position, const char *function, const gearmand_error_t rc, const char *format, ...)
{
  if (gearmand_failed(rc) and rc != GEARMAN_IO_WAIT)
  {
    va_list args;

    if (Gearmand() == NULL or Gearmand()->verbose >= GEARMAND_VERBOSE_ERROR)
    {
      va_start(args, format);
      gearmand_log(position, function, GEARMAND_VERBOSE_ERROR, rc, format, args);
      va_end(args);
    }
  }
  else if (rc == GEARMAN_IO_WAIT)
  { }

  return rc;
}

gearmand_error_t gearmand_log_gerror_warn(const char *position, const char *function, const gearmand_error_t rc, const char *format, ...)
{
  if (gearmand_failed(rc) and rc != GEARMAN_IO_WAIT)
  {
    va_list args;

    if (Gearmand() == NULL or Gearmand()->verbose >= GEARMAND_VERBOSE_WARN)
    {
      va_start(args, format);
      gearmand_log(position, function, GEARMAND_VERBOSE_WARN, rc, format, args);
      va_end(args);
    }
  }
  else if (rc == GEARMAN_IO_WAIT)
  { }

  return rc;
}

gearmand_error_t gearmand_log_gai_error(const char *position, const char *function, const int rc, const char *message)
{
  if (rc == EAI_SYSTEM)
  {
    return gearmand_log_perror(position, function, message);
  }

  gearmand_log_error(position, function, "%s getaddrinfo(%s)", message, gai_strerror(rc));

  return GEARMAN_GETADDRINFO;
}

gearmand_error_t gearmand_log_memory_error(const char *position, const char *function, const char *allocator, const char *object_type, size_t count, size_t size)
{
  if (count > 1)
  {
    gearmand_log_error(position, function, "%s(%s, count: %lu size: %lu)", allocator, object_type, static_cast<unsigned long>(count), static_cast<unsigned long>(size));
  }
  else
  {
    gearmand_log_error(position, function, "%s(%s, size: %lu)", allocator, object_type, static_cast<unsigned long>(count), static_cast<unsigned long>(size));
  }

  return GEARMAN_MEMORY_ALLOCATION_FAILURE;
}
<commit_msg>Fix month for date in log.<commit_after>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Gearmand client and server library.
 *
 *  Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
 *  Copyright (C) 2008 Brian Aker, Eric Day
 *  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.
 *
 *      * The names of its contributors may not 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.
 *
 */

/**
 * @file
 * @brief Gearman State Definitions
 */

#include <config.h>
#include <libgearman-server/common.h>
#include <libgearman-server/timer.h>

#include <algorithm>
#include <cerrno>
#include <cstring>
#include <ctime>

static pthread_key_t logging_key;
static pthread_once_t intitialize_log_once= PTHREAD_ONCE_INIT;

static void delete_log(void *ptr)
{
  if (ptr)
  {
    free(ptr);
  }
}

static void create_log(void)
{
  (void) pthread_key_create(&logging_key, delete_log);
}

void gearmand_initialize_thread_logging(const char *identity)
{
  (void) pthread_once(&intitialize_log_once, create_log);

  if (pthread_getspecific(logging_key) == NULL)
  {
    const char *key_to_use= strdup(identity);
    (void) pthread_setspecific(logging_key, key_to_use);
  }
}

#ifndef __INTEL_COMPILER
#pragma GCC diagnostic ignored "-Wold-style-cast"
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif

/**
 * Log a message.
 *
 * @param[in] gearman Structure previously initialized with gearman_create() or
 *  gearman_clone().
 * @param[in] verbose Logging level of the message.
 * @param[in] format Format and variable argument list of message.
 * @param[in] args Variable argument list that has been initialized.
 */

static void gearmand_log(const char *position, const char *func /* func */,
                         gearmand_verbose_t verbose,
                         const gearmand_error_t error_arg,
                         const char *format, va_list args)
{
  struct timeval current_epoch;

  if (Gearmand() and Gearmand()->verbose < GEARMAND_VERBOSE_DEBUG)
  {
    current_epoch= libgearman::server::Epoch::current();
    current_epoch.tv_usec= 0;
  }
  else
  {
    (void)gettimeofday(&current_epoch, NULL);
  }

  struct tm current_tm;
  if (current_epoch.tv_sec == 0)
  {
    (void)gettimeofday(&current_epoch, NULL);
  }

  if ((gmtime_r(&current_epoch.tv_sec, &current_tm) == NULL))
  {
    memset(&current_epoch, 0, sizeof(current_epoch));
  }

  (void) pthread_once(&intitialize_log_once, create_log);

  const char *identity= (const char *)pthread_getspecific(logging_key);

  if (identity == NULL)
  {
    identity= "[  main ]";
  }

  char log_buffer[GEARMAN_MAX_ERROR_SIZE*2] = { 0 };
  if (Gearmand() && Gearmand()->log_fn)
  {
    char *log_buffer_ptr= log_buffer;
    size_t remaining_size= sizeof(log_buffer);

    {
      int length= snprintf(log_buffer, sizeof(log_buffer), "%04d-%02d-%02d %02d:%02d:%02d.%06d %s ",
                           int(1900 +current_tm.tm_year), current_tm.tm_mon +1, current_tm.tm_mday, current_tm.tm_hour,
                           current_tm.tm_min, current_tm.tm_sec, int(current_epoch.tv_usec),
                           identity);
      // We just return whatever we have if this occurs
      if (length <= 0 or (size_t)length >= sizeof(log_buffer))
      {
        remaining_size= 0;
      }
      else
      {
        remaining_size-= size_t(length);
        log_buffer_ptr+= length;
      }
    }

    if (remaining_size)
    {
      int length= vsnprintf(log_buffer_ptr, remaining_size, format, args);
      if (length <= 0 or size_t(length) >= remaining_size)
      {
        remaining_size= 0;
      }
      else
      {
        remaining_size-= size_t(length);
        log_buffer_ptr+= length;
      }
    }

    if (remaining_size and error_arg != GEARMAN_SUCCESS)
    {
      int length= snprintf(log_buffer_ptr, remaining_size, " %s(%s)", func, gearmand_strerror(error_arg));
      if (length <= 0 or size_t(length) >= remaining_size)
      {
        remaining_size= 0;
      }
      else
      {
        remaining_size-= size_t(length);
        log_buffer_ptr+= length;
      }
    }

    if (remaining_size and position and verbose != GEARMAND_VERBOSE_INFO)
    {
      int length= snprintf(log_buffer_ptr, remaining_size, " -> %s", position);
      if (length <= 0 or size_t(length) >= remaining_size)
      {
        remaining_size= 0;
      }
    }

    // Make sure this is null terminated
    log_buffer[sizeof(log_buffer) -1]= 0;
  }

  if (Gearmand() and Gearmand()->log_fn)
  {
    Gearmand()->log_fn(log_buffer, verbose, (void *)Gearmand()->log_context);
  }
  else
  {
    fprintf(stderr, "%s -> %s",
            log_buffer,  gearmand_verbose_name(verbose));
    vfprintf(stderr, format, args);
    fprintf(stderr, "\n");
  }
}

void gearmand_log_fatal(const char *position, const char *func, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_FATAL)
  {
    va_start(args, format);
    gearmand_log(position, func, GEARMAND_VERBOSE_FATAL, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

void gearmand_log_fatal_perror(const char *position, const char *function, const char *message)
{
  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_FATAL)
  {
    const char *errmsg_ptr;
    char errmsg[GEARMAN_MAX_ERROR_SIZE];
    errmsg[0]= 0;

#ifdef STRERROR_R_CHAR_P
    errmsg_ptr= strerror_r(errno, errmsg, sizeof(errmsg));
#else
    strerror_r(errno, errmsg, sizeof(errmsg));
    errmsg_ptr= errmsg;
#endif

    gearmand_log_fatal(position, function, "%s(%s)", message, errmsg_ptr);
  }
}

gearmand_error_t gearmand_log_error(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() or Gearmand()->verbose >= GEARMAND_VERBOSE_ERROR)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_ERROR, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }

  return GEARMAN_UNKNOWN_OPTION;
}

void gearmand_log_warning(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_WARN)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_WARN, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

// LOG_NOTICE is only used for reporting job status.
void gearmand_log_notice(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_NOTICE)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_NOTICE, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

void gearmand_log_info(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_INFO)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_INFO, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

void gearmand_log_debug(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_DEBUG)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_DEBUG, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

gearmand_error_t gearmand_log_perror(const char *position, const char *function, const char *message)
{
  if (not Gearmand() or (Gearmand()->verbose >= GEARMAND_VERBOSE_ERROR))
  {
    const char *errmsg_ptr;
    char errmsg[GEARMAN_MAX_ERROR_SIZE];
    errmsg[0]= 0;

#ifdef STRERROR_R_CHAR_P
    errmsg_ptr= strerror_r(errno, errmsg, sizeof(errmsg));
#else
    strerror_r(errno, errmsg, sizeof(errmsg));
    errmsg_ptr= errmsg;
#endif
    gearmand_log_error(position, function, "%s(%s)", message, errmsg_ptr);
  }

  return GEARMAN_ERRNO;
}

gearmand_error_t gearmand_log_gerror(const char *position, const char *function, const gearmand_error_t rc, const char *format, ...)
{
  if (gearmand_failed(rc) and rc != GEARMAN_IO_WAIT)
  {
    va_list args;

    if (Gearmand() == NULL or Gearmand()->verbose >= GEARMAND_VERBOSE_ERROR)
    {
      va_start(args, format);
      gearmand_log(position, function, GEARMAND_VERBOSE_ERROR, rc, format, args);
      va_end(args);
    }
  }
  else if (rc == GEARMAN_IO_WAIT)
  { }

  return rc;
}

gearmand_error_t gearmand_log_gerror_warn(const char *position, const char *function, const gearmand_error_t rc, const char *format, ...)
{
  if (gearmand_failed(rc) and rc != GEARMAN_IO_WAIT)
  {
    va_list args;

    if (Gearmand() == NULL or Gearmand()->verbose >= GEARMAND_VERBOSE_WARN)
    {
      va_start(args, format);
      gearmand_log(position, function, GEARMAND_VERBOSE_WARN, rc, format, args);
      va_end(args);
    }
  }
  else if (rc == GEARMAN_IO_WAIT)
  { }

  return rc;
}

gearmand_error_t gearmand_log_gai_error(const char *position, const char *function, const int rc, const char *message)
{
  if (rc == EAI_SYSTEM)
  {
    return gearmand_log_perror(position, function, message);
  }

  gearmand_log_error(position, function, "%s getaddrinfo(%s)", message, gai_strerror(rc));

  return GEARMAN_GETADDRINFO;
}

gearmand_error_t gearmand_log_memory_error(const char *position, const char *function, const char *allocator, const char *object_type, size_t count, size_t size)
{
  if (count > 1)
  {
    gearmand_log_error(position, function, "%s(%s, count: %lu size: %lu)", allocator, object_type, static_cast<unsigned long>(count), static_cast<unsigned long>(size));
  }
  else
  {
    gearmand_log_error(position, function, "%s(%s, size: %lu)", allocator, object_type, static_cast<unsigned long>(count), static_cast<unsigned long>(size));
  }

  return GEARMAN_MEMORY_ALLOCATION_FAILURE;
}
<|endoftext|>


<commit_before><commit_msg>In system level install case go back to copying files instead of moving them.<commit_after><|endoftext|>


<commit_before>#ifndef CLUSTERING_ADMINISTRATION_PARSER_MAKER_TCC_
#define CLUSTERING_ADMINISTRATION_PARSER_MAKER_TCC_

#include "clustering/administration/parser_maker.hpp"

template<class protocol_t, class parser_t>
parser_maker_t<protocol_t, parser_t>::parser_maker_t(mailbox_manager_t *_mailbox_manager,
                               boost::shared_ptr<semilattice_read_view_t<namespaces_semilattice_metadata_t<protocol_t> > > _namespaces_semilattice_metadata,
#ifndef NDEBUG
                               boost::shared_ptr<semilattice_read_view_t<machine_semilattice_metadata_t> > _machine_semilattice_metadata,
#endif
                               namespace_repo_t<protocol_t> *_repo,
                               perfmon_collection_repo_t *_perfmon_collection_repo)
    : mailbox_manager(_mailbox_manager),
      namespaces_semilattice_metadata(_namespaces_semilattice_metadata),
#ifndef NDEBUG
      machine_semilattice_metadata(_machine_semilattice_metadata),
#endif
      repo(_repo),
      namespaces_subscription(boost::bind(&parser_maker_t::on_change, this), namespaces_semilattice_metadata),
#ifndef NDEBUG
      machine_subscription(boost::bind(&parser_maker_t::on_change, this), machine_semilattice_metadata),
#endif
      perfmon_collection_repo(_perfmon_collection_repo)
{
    on_change();
}

template<class protocol_t>
int get_port(const namespace_semilattice_metadata_t<protocol_t> &ns
#ifndef NDEBUG
    , const machine_semilattice_metadata_t &us
#endif
    ) {
#ifndef NDEBUG
    if (ns.port.get() == 0)
        return 0;

    return ns.port.get() + us.port_offset.get();
#else
    return ns.port.get();
#endif
}

template<class protocol_t, class parser_t>
void parser_maker_t<protocol_t, parser_t>::on_change() {
    ASSERT_NO_CORO_WAITING;

    namespaces_semilattice_metadata_t<protocol_t> snapshot = namespaces_semilattice_metadata->get();
#ifndef NDEBUG
    machine_semilattice_metadata_t machine_metadata_snapshot = machine_semilattice_metadata->get();
#endif

    for (typename namespaces_semilattice_metadata_t<protocol_t>::namespace_map_t::iterator it  = snapshot.namespaces.begin();
                                                                                it != snapshot.namespaces.end();
                                                                                it++) {
        typename boost::ptr_map<namespace_id_t, ns_record_t>::iterator h_it = namespaces_being_handled.find(it->first);

        /* Destroy parsers as necessary, by pulsing the `stopper` cond on the
        `ns_record_t` so that the `serve_queries()` coroutine will stop */
        if (h_it != namespaces_being_handled.end() && (
                it->second.is_deleted() ||
                it->second.get().port.in_conflict() ||
                h_it->second->port != get_port(it->second.get()
#ifndef NDEBUG
                                               , machine_metadata_snapshot
#endif
                ))) {
            if (!h_it->second->stopper.is_pulsed()) {
                h_it->second->stopper.pulse();
            }
        }

        /* Create parsers as necessary by spawning instances of
        `serve_queries()` */
        if (h_it == namespaces_being_handled.end() && !it->second.is_deleted() && !it->second.get().port.in_conflict()) {
            vclock_t<std::string> v_ns_name = it->second.get().name;
            std::string ns_name(v_ns_name.in_conflict() ? "<in conflict>" : v_ns_name.get());

            int port = get_port(it->second.get()
#ifndef NDEBUG
                                , machine_metadata_snapshot
#endif
                                );
            namespace_id_t tmp = it->first;
            namespaces_being_handled.insert(tmp, new ns_record_t(port));
            coro_t::spawn_sometime(boost::bind(
                &parser_maker_t::serve_queries, this,
                ns_name, it->first, port, auto_drainer_t::lock_t(&drainer)
                ));
        }
    }
}

template<class protocol_t, class parser_t>
void parser_maker_t<protocol_t, parser_t>::serve_queries(std::string ns_name, namespace_id_t ns, int port, auto_drainer_t::lock_t keepalive) {
    try {
        printf("Starting to serve queries for the namespace '%s' %s on port %d...\n", ns_name.c_str(), uuid_to_str(ns).c_str(), port);
        wait_any_t interruptor(&namespaces_being_handled.find(ns)->second->stopper, keepalive.get_drain_signal());
        typename namespace_repo_t<protocol_t>::access_t access(repo, ns, &interruptor);
        parser_t parser(port, access.get_namespace_if(), perfmon_collection_repo->get_perfmon_collection_for_namespace(ns));
        interruptor.wait_lazily_unordered();
    } catch (interrupted_exc_t) {
        /* pass */
    }

    namespaces_being_handled.erase(ns);

    if (!keepalive.get_drain_signal()->is_pulsed()) {
        /* If we were stopped due to a port change, make sure that a new
        instance of `serve_queries()` gets started with the correct port */
        on_change();
    }
}

#endif /* CLUSTERING_ADMINISTRATION_PARSER_MAKER_TCC_ */
<commit_msg>Print a message when stopping to serve the queries for a namespace<commit_after>#ifndef CLUSTERING_ADMINISTRATION_PARSER_MAKER_TCC_
#define CLUSTERING_ADMINISTRATION_PARSER_MAKER_TCC_

#include "clustering/administration/parser_maker.hpp"

template<class protocol_t, class parser_t>
parser_maker_t<protocol_t, parser_t>::parser_maker_t(mailbox_manager_t *_mailbox_manager,
                               boost::shared_ptr<semilattice_read_view_t<namespaces_semilattice_metadata_t<protocol_t> > > _namespaces_semilattice_metadata,
#ifndef NDEBUG
                               boost::shared_ptr<semilattice_read_view_t<machine_semilattice_metadata_t> > _machine_semilattice_metadata,
#endif
                               namespace_repo_t<protocol_t> *_repo,
                               perfmon_collection_repo_t *_perfmon_collection_repo)
    : mailbox_manager(_mailbox_manager),
      namespaces_semilattice_metadata(_namespaces_semilattice_metadata),
#ifndef NDEBUG
      machine_semilattice_metadata(_machine_semilattice_metadata),
#endif
      repo(_repo),
      namespaces_subscription(boost::bind(&parser_maker_t::on_change, this), namespaces_semilattice_metadata),
#ifndef NDEBUG
      machine_subscription(boost::bind(&parser_maker_t::on_change, this), machine_semilattice_metadata),
#endif
      perfmon_collection_repo(_perfmon_collection_repo)
{
    on_change();
}

template<class protocol_t>
int get_port(const namespace_semilattice_metadata_t<protocol_t> &ns
             DEBUG_ONLY(, const machine_semilattice_metadata_t &us)
            ) {
#ifndef NDEBUG
    if (ns.port.get() == 0)
        return 0;

    return ns.port.get() + us.port_offset.get();
#else
    return ns.port.get();
#endif
}

static const char * ns_name_in_conflict = "<in conflict>";

template<class protocol_t, class parser_t>
void parser_maker_t<protocol_t, parser_t>::on_change() {
    ASSERT_NO_CORO_WAITING;

    namespaces_semilattice_metadata_t<protocol_t> snapshot = namespaces_semilattice_metadata->get();
#ifndef NDEBUG
    machine_semilattice_metadata_t machine_metadata_snapshot = machine_semilattice_metadata->get();
#endif

    for (typename namespaces_semilattice_metadata_t<protocol_t>::namespace_map_t::iterator it  = snapshot.namespaces.begin();
                                                                                it != snapshot.namespaces.end();
                                                                                it++) {
        typename boost::ptr_map<namespace_id_t, ns_record_t>::iterator handled_ns = namespaces_being_handled.find(it->first);

        /* Destroy parsers as necessary, by pulsing the `stopper` cond on the
        `ns_record_t` so that the `serve_queries()` coroutine will stop */
        if (handled_ns != namespaces_being_handled.end() && (
                          it->second.is_deleted() ||
                          it->second.get().port.in_conflict() ||
                          handled_ns->second->port != get_port(it->second.get()
                                                               DEBUG_ONLY(, machine_metadata_snapshot)
                                                              )
                          )) {

            vclock_t<std::string> v_ns_name = it->second.get().name;
            std::string ns_name(v_ns_name.in_conflict() ? ns_name_in_conflict : v_ns_name.get());

            printf("Stopping serving queries for the namespace '%s' %s on port %d...\n", ns_name.c_str(), uuid_to_str(it->first).c_str(), handled_ns->second->port);

            if (!handled_ns->second->stopper.is_pulsed()) {
                handled_ns->second->stopper.pulse();
            }
        }

        /* Create parsers as necessary by spawning instances of
        `serve_queries()` */
        if (handled_ns == namespaces_being_handled.end() && !it->second.is_deleted() && !it->second.get().port.in_conflict()) {
            vclock_t<std::string> v_ns_name = it->second.get().name;
            std::string ns_name(v_ns_name.in_conflict() ? ns_name_in_conflict : v_ns_name.get());

            int port = get_port(it->second.get()
                                DEBUG_ONLY(, machine_metadata_snapshot)
                               );
            namespace_id_t tmp = it->first;
            namespaces_being_handled.insert(tmp, new ns_record_t(port));
            coro_t::spawn_sometime(boost::bind(
                &parser_maker_t::serve_queries, this,
                ns_name, it->first, port, auto_drainer_t::lock_t(&drainer)
                ));
        }
    }
}

template<class protocol_t, class parser_t>
void parser_maker_t<protocol_t, parser_t>::serve_queries(std::string ns_name, namespace_id_t ns, int port, auto_drainer_t::lock_t keepalive) {
    try {
        printf("Starting to serve queries for the namespace '%s' %s on port %d...\n", ns_name.c_str(), uuid_to_str(ns).c_str(), port);
        wait_any_t interruptor(&namespaces_being_handled.find(ns)->second->stopper, keepalive.get_drain_signal());
        typename namespace_repo_t<protocol_t>::access_t access(repo, ns, &interruptor);
        parser_t parser(port, access.get_namespace_if(), perfmon_collection_repo->get_perfmon_collection_for_namespace(ns));
        interruptor.wait_lazily_unordered();
    } catch (interrupted_exc_t) {
        /* pass */
    }

    namespaces_being_handled.erase(ns);

    if (!keepalive.get_drain_signal()->is_pulsed()) {
        /* If we were stopped due to a port change, make sure that a new
        instance of `serve_queries()` gets started with the correct port */
        on_change();
    }
}

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


<commit_before>#include <cstdio>
#include <fstream>
#include <unistd.h>

#include <kms++/kms++.h>
#include <kms++util/kms++util.h>

using namespace std;
using namespace kms;

static void read_frame(ifstream& is, DumbFramebuffer* fb, Crtc* crtc, Plane* plane)
{
	for (unsigned i = 0; i < fb->num_planes(); ++i)
		is.read((char*)fb->map(i), fb->size(i));

	unsigned w = min(crtc->width(), fb->width());
	unsigned h = min(crtc->height(), fb->height());

	int r = crtc->set_plane(plane, *fb,
				0, 0, w, h,
				0, 0, fb->width(), fb->height());

	ASSERT(r == 0);
}

static const char* usage_str =
		"Usage: kmsview [-t <ms>] <file> <width> <height> <fourcc>\n\n"
		"Options:\n"
		"  -t, --time        Milliseconds to sleep between frames\n"
		;

static void usage()
{
	puts(usage_str);
}

int main(int argc, char** argv)
{
	uint32_t time = 0;
	string dev_path = "/dev/dri/card0";

	OptionSet optionset = {
		Option("|device=", [&dev_path](string s)
		{
			dev_path = s;
		}),
		Option("t|time=", [&time](const string& str)
		{
			time = stoul(str);
		}),
		Option("h|help", []()
		{
			usage();
			exit(-1);
		}),
	};

	optionset.parse(argc, argv);

	vector<string> params = optionset.params();

	if (params.size() != 4) {
		usage();
		exit(-1);
	}

	string filename = params[0];
	uint32_t w = stoi(params[1]);
	uint32_t h = stoi(params[2]);
	string modestr = params[3];

	auto pixfmt = FourCCToPixelFormat(modestr);

	ifstream is(filename, ifstream::binary);

	is.seekg(0, std::ios::end);
	unsigned fsize = is.tellg();
	is.seekg(0);

	Card card(dev_path);

	auto conn = card.get_first_connected_connector();
	auto crtc = conn->get_current_crtc();

	auto fb = new DumbFramebuffer(card, w, h, pixfmt);

	Plane* plane = 0;

	for (Plane* p : crtc->get_possible_planes()) {
		if (p->plane_type() != PlaneType::Overlay)
			continue;

		if (!p->supports_format(pixfmt))
			continue;

		plane = p;
		break;
	}

	FAIL_IF(!plane, "available plane not found");

	unsigned frame_size = 0;
	for (unsigned i = 0; i < fb->num_planes(); ++i)
		frame_size += fb->size(i);

	unsigned num_frames = fsize / frame_size;
	printf("file size %u, frame size %u, frames %u\n", fsize, frame_size, num_frames);

	for (unsigned i = 0; i < num_frames; ++i) {
		printf("frame %d", i); fflush(stdout);
		read_frame(is, fb, crtc, plane);
		if (!time) {
			getchar();
		} else {
			usleep(time * 1000);
			printf("\n");
		}
	}

	is.close();

	if (time) {
		printf("press enter to exit\n");
		getchar();
	}

	delete fb;
}
<commit_msg>kmsview: use resman<commit_after>#include <cstdio>
#include <fstream>
#include <unistd.h>

#include <kms++/kms++.h>
#include <kms++util/kms++util.h>

using namespace std;
using namespace kms;

static void read_frame(ifstream& is, DumbFramebuffer* fb, Crtc* crtc, Plane* plane)
{
	for (unsigned i = 0; i < fb->num_planes(); ++i)
		is.read((char*)fb->map(i), fb->size(i));

	unsigned w = min(crtc->width(), fb->width());
	unsigned h = min(crtc->height(), fb->height());

	int r = crtc->set_plane(plane, *fb,
				0, 0, w, h,
				0, 0, fb->width(), fb->height());

	ASSERT(r == 0);
}

static const char* usage_str =
		"Usage: kmsview [-t <ms>] <file> <width> <height> <fourcc>\n\n"
		"Options:\n"
		"  -t, --time        Milliseconds to sleep between frames\n"
		;

static void usage()
{
	puts(usage_str);
}

int main(int argc, char** argv)
{
	uint32_t time = 0;
	string dev_path = "/dev/dri/card0";

	OptionSet optionset = {
		Option("|device=", [&dev_path](string s)
		{
			dev_path = s;
		}),
		Option("t|time=", [&time](const string& str)
		{
			time = stoul(str);
		}),
		Option("h|help", []()
		{
			usage();
			exit(-1);
		}),
	};

	optionset.parse(argc, argv);

	vector<string> params = optionset.params();

	if (params.size() != 4) {
		usage();
		exit(-1);
	}

	string filename = params[0];
	uint32_t w = stoi(params[1]);
	uint32_t h = stoi(params[2]);
	string modestr = params[3];

	auto pixfmt = FourCCToPixelFormat(modestr);

	ifstream is(filename, ifstream::binary);

	is.seekg(0, std::ios::end);
	unsigned fsize = is.tellg();
	is.seekg(0);

	Card card(dev_path);
	ResourceManager res(card);

	auto conn = res.reserve_connector();
	auto crtc = res.reserve_crtc(conn);
	auto plane = res.reserve_overlay_plane(crtc, pixfmt);
	FAIL_IF(!plane, "available plane not found");

	auto fb = new DumbFramebuffer(card, w, h, pixfmt);

	unsigned frame_size = 0;
	for (unsigned i = 0; i < fb->num_planes(); ++i)
		frame_size += fb->size(i);

	unsigned num_frames = fsize / frame_size;
	printf("file size %u, frame size %u, frames %u\n", fsize, frame_size, num_frames);

	for (unsigned i = 0; i < num_frames; ++i) {
		printf("frame %d", i); fflush(stdout);
		read_frame(is, fb, crtc, plane);
		if (!time) {
			getchar();
		} else {
			usleep(time * 1000);
			printf("\n");
		}
	}

	is.close();

	if (time) {
		printf("press enter to exit\n");
		getchar();
	}

	delete fb;
}
<|endoftext|>


<commit_before>//===- PrettyStackTrace.cpp - Pretty Crash Handling -----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines some helpful functions for dealing with the possibility of
// Unix signals occurring while your program is running.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/PrettyStackTrace.h"
#include "llvm-c/Core.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/config.h"     // Get autoconf configuration settings
#include "llvm/Support/Signals.h"
#include "llvm/Support/Watchdog.h"
#include "llvm/Support/raw_ostream.h"

#ifdef HAVE_CRASHREPORTERCLIENT_H
#include <CrashReporterClient.h>
#endif

using namespace llvm;

// We need a thread local pointer to manage the stack of our stack trace
// objects, but we *really* cannot tolerate destructors running and do not want
// to pay any overhead of synchronizing. As a consequence, we use a raw
// thread-local variable. Some day, we should be able to use a limited subset
// of C++11's thread_local, but compilers aren't up for it today.
// FIXME: This should be moved to a Compiler.h abstraction.
#ifdef _MSC_VER // MSVC supports this with a __declspec.
static __declspec(thread) const PrettyStackTraceEntry
    *PrettyStackTraceHead = nullptr;
#else // Clang, GCC, and all compatible compilers tend to use __thread.
static __thread const PrettyStackTraceEntry *PrettyStackTraceHead = nullptr;
#endif

static unsigned PrintStack(const PrettyStackTraceEntry *Entry, raw_ostream &OS){
  unsigned NextID = 0;
  if (Entry->getNextEntry())
    NextID = PrintStack(Entry->getNextEntry(), OS);
  OS << NextID << ".\t";
  {
    sys::Watchdog W(5);
    Entry->print(OS);
  }

  return NextID+1;
}

/// PrintCurStackTrace - Print the current stack trace to the specified stream.
static void PrintCurStackTrace(raw_ostream &OS) {
  // Don't print an empty trace.
  if (!PrettyStackTraceHead) return;

  // If there are pretty stack frames registered, walk and emit them.
  OS << "Stack dump:\n";

  PrintStack(PrettyStackTraceHead, OS);
  OS.flush();
}

// Integrate with crash reporter libraries.
#if defined (__APPLE__) && HAVE_CRASHREPORTERCLIENT_H
//  If any clients of llvm try to link to libCrashReporterClient.a themselves,
//  only one crash info struct will be used.
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 };
}
#elif defined (__APPLE__) && HAVE_CRASHREPORTER_INFO
static const char *__crashreporter_info__ = 0;
asm(".desc ___crashreporter_info__, 0x10");
#endif

/// CrashHandler - This callback is run if a fatal signal is delivered to the
/// process, it prints the pretty stack trace.
static void CrashHandler(void *) {
#ifndef __APPLE__
  // On non-apple systems, just emit the crash stack trace to stderr.
  PrintCurStackTrace(errs());
#else
  // Otherwise, emit to a smallvector of chars, send *that* to stderr, but also
  // put it into __crashreporter_info__.
  SmallString<2048> TmpStr;
  {
    raw_svector_ostream Stream(TmpStr);
    PrintCurStackTrace(Stream);
  }

  if (!TmpStr.empty()) {
#ifdef HAVE_CRASHREPORTERCLIENT_H
    // Cast to void to avoid warning.
    (void)CRSetCrashLogMessage(std::string(TmpStr.str()).c_str());
#elif HAVE_CRASHREPORTER_INFO
    __crashreporter_info__ = strdup(std::string(TmpStr.str()).c_str());
#endif
    errs() << TmpStr.str();
  }

#endif
}

PrettyStackTraceEntry::PrettyStackTraceEntry() {
  // Link ourselves.
  NextEntry = PrettyStackTraceHead;
  PrettyStackTraceHead = this;
}

PrettyStackTraceEntry::~PrettyStackTraceEntry() {
  assert(PrettyStackTraceHead == this &&
         "Pretty stack trace entry destruction is out of order");
  PrettyStackTraceHead = getNextEntry();
}

void PrettyStackTraceString::print(raw_ostream &OS) const {
  OS << Str << "\n";
}

void PrettyStackTraceProgram::print(raw_ostream &OS) const {
  OS << "Program arguments: ";
  // Print the argument list.
  for (unsigned i = 0, e = ArgC; i != e; ++i)
    OS << ArgV[i] << ' ';
  OS << '\n';
}

static bool RegisterCrashPrinter() {
  sys::AddSignalHandler(CrashHandler, nullptr);
  return false;
}

void llvm::EnablePrettyStackTrace() {
  // The first time this is called, we register the crash printer.
  static bool HandlerRegistered = RegisterCrashPrinter();
  (void)HandlerRegistered;
}

void LLVMEnablePrettyStackTrace() {
  EnablePrettyStackTrace();
}
<commit_msg>[LPM] Try to work around a bug with local-dynamic TLS on PowerPC 64.<commit_after>//===- PrettyStackTrace.cpp - Pretty Crash Handling -----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines some helpful functions for dealing with the possibility of
// Unix signals occurring while your program is running.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/PrettyStackTrace.h"
#include "llvm-c/Core.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/config.h"     // Get autoconf configuration settings
#include "llvm/Support/Signals.h"
#include "llvm/Support/Watchdog.h"
#include "llvm/Support/raw_ostream.h"

#ifdef HAVE_CRASHREPORTERCLIENT_H
#include <CrashReporterClient.h>
#endif

using namespace llvm;

// We need a thread local pointer to manage the stack of our stack trace
// objects, but we *really* cannot tolerate destructors running and do not want
// to pay any overhead of synchronizing. As a consequence, we use a raw
// thread-local variable. Some day, we should be able to use a limited subset
// of C++11's thread_local, but compilers aren't up for it today.
// FIXME: This should be moved to a Compiler.h abstraction.
#ifdef _MSC_VER
// MSVC supports this with a __declspec.
#define LLVM_THREAD_LOCAL __declspec(thread)
#else
// Clang, GCC, and all compatible compilers tend to use __thread. But we need
// to work aronud a bug in the combination of Clang's compilation of
// local-dynamic TLS and the ppc64 linker relocations which we do by forcing to
// general-dynamic.
// FIXME: Make this conditional on the Clang version once this is fixed in
// top-of-tree.
#if defined(__clang__) && defined(__powerpc64__)
#define LLVM_THREAD_LOCAL __thread __attribute__((tls_model("general-dynamic")))
#else
#define LLVM_THREAD_LOCAL __thread
#endif
#endif

static LLVM_THREAD_LOCAL const PrettyStackTraceEntry *PrettyStackTraceHead =
    nullptr;

static unsigned PrintStack(const PrettyStackTraceEntry *Entry, raw_ostream &OS){
  unsigned NextID = 0;
  if (Entry->getNextEntry())
    NextID = PrintStack(Entry->getNextEntry(), OS);
  OS << NextID << ".\t";
  {
    sys::Watchdog W(5);
    Entry->print(OS);
  }

  return NextID+1;
}

/// PrintCurStackTrace - Print the current stack trace to the specified stream.
static void PrintCurStackTrace(raw_ostream &OS) {
  // Don't print an empty trace.
  if (!PrettyStackTraceHead) return;

  // If there are pretty stack frames registered, walk and emit them.
  OS << "Stack dump:\n";

  PrintStack(PrettyStackTraceHead, OS);
  OS.flush();
}

// Integrate with crash reporter libraries.
#if defined (__APPLE__) && HAVE_CRASHREPORTERCLIENT_H
//  If any clients of llvm try to link to libCrashReporterClient.a themselves,
//  only one crash info struct will be used.
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 };
}
#elif defined (__APPLE__) && HAVE_CRASHREPORTER_INFO
static const char *__crashreporter_info__ = 0;
asm(".desc ___crashreporter_info__, 0x10");
#endif

/// CrashHandler - This callback is run if a fatal signal is delivered to the
/// process, it prints the pretty stack trace.
static void CrashHandler(void *) {
#ifndef __APPLE__
  // On non-apple systems, just emit the crash stack trace to stderr.
  PrintCurStackTrace(errs());
#else
  // Otherwise, emit to a smallvector of chars, send *that* to stderr, but also
  // put it into __crashreporter_info__.
  SmallString<2048> TmpStr;
  {
    raw_svector_ostream Stream(TmpStr);
    PrintCurStackTrace(Stream);
  }

  if (!TmpStr.empty()) {
#ifdef HAVE_CRASHREPORTERCLIENT_H
    // Cast to void to avoid warning.
    (void)CRSetCrashLogMessage(std::string(TmpStr.str()).c_str());
#elif HAVE_CRASHREPORTER_INFO
    __crashreporter_info__ = strdup(std::string(TmpStr.str()).c_str());
#endif
    errs() << TmpStr.str();
  }

#endif
}

PrettyStackTraceEntry::PrettyStackTraceEntry() {
  // Link ourselves.
  NextEntry = PrettyStackTraceHead;
  PrettyStackTraceHead = this;
}

PrettyStackTraceEntry::~PrettyStackTraceEntry() {
  assert(PrettyStackTraceHead == this &&
         "Pretty stack trace entry destruction is out of order");
  PrettyStackTraceHead = getNextEntry();
}

void PrettyStackTraceString::print(raw_ostream &OS) const {
  OS << Str << "\n";
}

void PrettyStackTraceProgram::print(raw_ostream &OS) const {
  OS << "Program arguments: ";
  // Print the argument list.
  for (unsigned i = 0, e = ArgC; i != e; ++i)
    OS << ArgV[i] << ' ';
  OS << '\n';
}

static bool RegisterCrashPrinter() {
  sys::AddSignalHandler(CrashHandler, nullptr);
  return false;
}

void llvm::EnablePrettyStackTrace() {
  // The first time this is called, we register the crash printer.
  static bool HandlerRegistered = RegisterCrashPrinter();
  (void)HandlerRegistered;
}

void LLVMEnablePrettyStackTrace() {
  EnablePrettyStackTrace();
}
<|endoftext|>


<commit_before>//===---- X86FixupSetCC.cpp - optimize usage of LEA instructions ----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines a pass that fixes zero-extension of setcc patterns.
// X86 setcc instructions are modeled to have no input arguments, and a single
// GR8 output argument. This is consistent with other similar instructions
// (e.g. movb), but means it is impossible to directly generate a setcc into
// the lower GR8 of a specified GR32.
// This means that ISel must select (zext (setcc)) into something like
// seta %al; movzbl %al, %eax.
// Unfortunately, this can cause a stall due to the partial register write
// performed by the setcc. Instead, we can use:
// xor %eax, %eax; seta %al
// This both avoids the stall, and encodes shorter.
//===----------------------------------------------------------------------===//

#include "X86.h"
#include "X86InstrInfo.h"
#include "X86Subtarget.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"

using namespace llvm;

#define DEBUG_TYPE "x86-fixup-setcc"

STATISTIC(NumSubstZexts, "Number of setcc + zext pairs substituted");

namespace {
class X86FixupSetCCPass : public MachineFunctionPass {
public:
  X86FixupSetCCPass() : MachineFunctionPass(ID) {}

  StringRef getPassName() const override { return "X86 Fixup SetCC"; }

  bool runOnMachineFunction(MachineFunction &MF) override;

private:
  // Find the preceding instruction that imp-defs eflags.
  MachineInstr *findFlagsImpDef(MachineBasicBlock *MBB,
                                MachineBasicBlock::reverse_iterator MI);

  // Return true if MI imp-uses eflags.
  bool impUsesFlags(MachineInstr *MI);

  // Return true if this is the opcode of a SetCC instruction with a register
  // output.
  bool isSetCCr(unsigned Opode);

  MachineRegisterInfo *MRI;
  const X86InstrInfo *TII;

  enum { SearchBound = 16 };

  static char ID;
};

char X86FixupSetCCPass::ID = 0;
}

FunctionPass *llvm::createX86FixupSetCC() { return new X86FixupSetCCPass(); }

bool X86FixupSetCCPass::isSetCCr(unsigned Opcode) {
  switch (Opcode) {
  default:
    return false;
  case X86::SETOr:
  case X86::SETNOr:
  case X86::SETBr:
  case X86::SETAEr:
  case X86::SETEr:
  case X86::SETNEr:
  case X86::SETBEr:
  case X86::SETAr:
  case X86::SETSr:
  case X86::SETNSr:
  case X86::SETPr:
  case X86::SETNPr:
  case X86::SETLr:
  case X86::SETGEr:
  case X86::SETLEr:
  case X86::SETGr:
    return true;
  }
}

// We expect the instruction *immediately* before the setcc to imp-def
// EFLAGS (because of scheduling glue). To make this less brittle w.r.t
// scheduling, look backwards until we hit the beginning of the
// basic-block, or a small bound (to avoid quadratic behavior).
MachineInstr *
X86FixupSetCCPass::findFlagsImpDef(MachineBasicBlock *MBB,
                                   MachineBasicBlock::reverse_iterator MI) {
  // FIXME: Should this be instr_rend(), and MI be reverse_instr_iterator?
  auto MBBStart = MBB->rend();
  for (int i = 0; (i < SearchBound) && (MI != MBBStart); ++i, ++MI)
    for (auto &Op : MI->implicit_operands())
      if ((Op.getReg() == X86::EFLAGS) && (Op.isDef()))
        return &*MI;

  return nullptr;
}

bool X86FixupSetCCPass::impUsesFlags(MachineInstr *MI) {
  for (auto &Op : MI->implicit_operands())
    if ((Op.getReg() == X86::EFLAGS) && (Op.isUse()))
      return true;

  return false;
}

bool X86FixupSetCCPass::runOnMachineFunction(MachineFunction &MF) {
  bool Changed = false;
  MRI = &MF.getRegInfo();
  TII = MF.getSubtarget<X86Subtarget>().getInstrInfo();

  SmallVector<MachineInstr*, 4> ToErase;

  for (auto &MBB : MF) {
    for (auto &MI : MBB) {
      // Find a setcc that is used by a zext.
      // This doesn't have to be the only use, the transformation is safe
      // regardless.
      if (!isSetCCr(MI.getOpcode()))
        continue;

      MachineInstr *ZExt = nullptr;
      for (auto &Use : MRI->use_instructions(MI.getOperand(0).getReg()))
        if (Use.getOpcode() == X86::MOVZX32rr8)
          ZExt = &Use;

      if (!ZExt)
        continue;

      // Find the preceding instruction that imp-defs eflags.
      MachineInstr *FlagsDefMI = findFlagsImpDef(
          MI.getParent(), MachineBasicBlock::reverse_iterator(&MI));
      if (!FlagsDefMI)
        continue;

      // We'd like to put something that clobbers eflags directly before
      // FlagsDefMI. This can't hurt anything after FlagsDefMI, because
      // it, itself, by definition, clobbers eflags. But it may happen that
      // FlagsDefMI also *uses* eflags, in which case the transformation is
      // invalid.
      if (impUsesFlags(FlagsDefMI))
        continue;

      ++NumSubstZexts;
      Changed = true;

      // On 32-bit, we need to be careful to force an ABCD register.
      const TargetRegisterClass *RC = MF.getSubtarget<X86Subtarget>().is64Bit()
                                          ? &X86::GR32RegClass
                                          : &X86::GR32_ABCDRegClass;
      unsigned ZeroReg = MRI->createVirtualRegister(RC);
      unsigned InsertReg = MRI->createVirtualRegister(RC);

      // Initialize a register with 0. This must go before the eflags def
      BuildMI(MBB, FlagsDefMI, MI.getDebugLoc(), TII->get(X86::MOV32r0),
              ZeroReg);

      // X86 setcc only takes an output GR8, so fake a GR32 input by inserting
      // the setcc result into the low byte of the zeroed register.
      BuildMI(*ZExt->getParent(), ZExt, ZExt->getDebugLoc(),
              TII->get(X86::INSERT_SUBREG), InsertReg)
          .addReg(ZeroReg)
          .addReg(MI.getOperand(0).getReg())
          .addImm(X86::sub_8bit);
      MRI->replaceRegWith(ZExt->getOperand(0).getReg(), InsertReg);
      ToErase.push_back(ZExt);
    }
  }

  for (auto &I : ToErase)
    I->eraseFromParent();

  return Changed;
}
<commit_msg>[X86] Add missing isReg() guards in FixupSetCCs pass.<commit_after>//===---- X86FixupSetCC.cpp - optimize usage of LEA instructions ----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines a pass that fixes zero-extension of setcc patterns.
// X86 setcc instructions are modeled to have no input arguments, and a single
// GR8 output argument. This is consistent with other similar instructions
// (e.g. movb), but means it is impossible to directly generate a setcc into
// the lower GR8 of a specified GR32.
// This means that ISel must select (zext (setcc)) into something like
// seta %al; movzbl %al, %eax.
// Unfortunately, this can cause a stall due to the partial register write
// performed by the setcc. Instead, we can use:
// xor %eax, %eax; seta %al
// This both avoids the stall, and encodes shorter.
//===----------------------------------------------------------------------===//

#include "X86.h"
#include "X86InstrInfo.h"
#include "X86Subtarget.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"

using namespace llvm;

#define DEBUG_TYPE "x86-fixup-setcc"

STATISTIC(NumSubstZexts, "Number of setcc + zext pairs substituted");

namespace {
class X86FixupSetCCPass : public MachineFunctionPass {
public:
  X86FixupSetCCPass() : MachineFunctionPass(ID) {}

  StringRef getPassName() const override { return "X86 Fixup SetCC"; }

  bool runOnMachineFunction(MachineFunction &MF) override;

private:
  // Find the preceding instruction that imp-defs eflags.
  MachineInstr *findFlagsImpDef(MachineBasicBlock *MBB,
                                MachineBasicBlock::reverse_iterator MI);

  // Return true if MI imp-uses eflags.
  bool impUsesFlags(MachineInstr *MI);

  // Return true if this is the opcode of a SetCC instruction with a register
  // output.
  bool isSetCCr(unsigned Opode);

  MachineRegisterInfo *MRI;
  const X86InstrInfo *TII;

  enum { SearchBound = 16 };

  static char ID;
};

char X86FixupSetCCPass::ID = 0;
}

FunctionPass *llvm::createX86FixupSetCC() { return new X86FixupSetCCPass(); }

bool X86FixupSetCCPass::isSetCCr(unsigned Opcode) {
  switch (Opcode) {
  default:
    return false;
  case X86::SETOr:
  case X86::SETNOr:
  case X86::SETBr:
  case X86::SETAEr:
  case X86::SETEr:
  case X86::SETNEr:
  case X86::SETBEr:
  case X86::SETAr:
  case X86::SETSr:
  case X86::SETNSr:
  case X86::SETPr:
  case X86::SETNPr:
  case X86::SETLr:
  case X86::SETGEr:
  case X86::SETLEr:
  case X86::SETGr:
    return true;
  }
}

// We expect the instruction *immediately* before the setcc to imp-def
// EFLAGS (because of scheduling glue). To make this less brittle w.r.t
// scheduling, look backwards until we hit the beginning of the
// basic-block, or a small bound (to avoid quadratic behavior).
MachineInstr *
X86FixupSetCCPass::findFlagsImpDef(MachineBasicBlock *MBB,
                                   MachineBasicBlock::reverse_iterator MI) {
  // FIXME: Should this be instr_rend(), and MI be reverse_instr_iterator?
  auto MBBStart = MBB->rend();
  for (int i = 0; (i < SearchBound) && (MI != MBBStart); ++i, ++MI)
    for (auto &Op : MI->implicit_operands())
      if (Op.isReg() && (Op.getReg() == X86::EFLAGS) && Op.isDef())
        return &*MI;

  return nullptr;
}

bool X86FixupSetCCPass::impUsesFlags(MachineInstr *MI) {
  for (auto &Op : MI->implicit_operands())
    if (Op.isReg() && (Op.getReg() == X86::EFLAGS) && Op.isUse())
      return true;

  return false;
}

bool X86FixupSetCCPass::runOnMachineFunction(MachineFunction &MF) {
  bool Changed = false;
  MRI = &MF.getRegInfo();
  TII = MF.getSubtarget<X86Subtarget>().getInstrInfo();

  SmallVector<MachineInstr*, 4> ToErase;

  for (auto &MBB : MF) {
    for (auto &MI : MBB) {
      // Find a setcc that is used by a zext.
      // This doesn't have to be the only use, the transformation is safe
      // regardless.
      if (!isSetCCr(MI.getOpcode()))
        continue;

      MachineInstr *ZExt = nullptr;
      for (auto &Use : MRI->use_instructions(MI.getOperand(0).getReg()))
        if (Use.getOpcode() == X86::MOVZX32rr8)
          ZExt = &Use;

      if (!ZExt)
        continue;

      // Find the preceding instruction that imp-defs eflags.
      MachineInstr *FlagsDefMI = findFlagsImpDef(
          MI.getParent(), MachineBasicBlock::reverse_iterator(&MI));
      if (!FlagsDefMI)
        continue;

      // We'd like to put something that clobbers eflags directly before
      // FlagsDefMI. This can't hurt anything after FlagsDefMI, because
      // it, itself, by definition, clobbers eflags. But it may happen that
      // FlagsDefMI also *uses* eflags, in which case the transformation is
      // invalid.
      if (impUsesFlags(FlagsDefMI))
        continue;

      ++NumSubstZexts;
      Changed = true;

      // On 32-bit, we need to be careful to force an ABCD register.
      const TargetRegisterClass *RC = MF.getSubtarget<X86Subtarget>().is64Bit()
                                          ? &X86::GR32RegClass
                                          : &X86::GR32_ABCDRegClass;
      unsigned ZeroReg = MRI->createVirtualRegister(RC);
      unsigned InsertReg = MRI->createVirtualRegister(RC);

      // Initialize a register with 0. This must go before the eflags def
      BuildMI(MBB, FlagsDefMI, MI.getDebugLoc(), TII->get(X86::MOV32r0),
              ZeroReg);

      // X86 setcc only takes an output GR8, so fake a GR32 input by inserting
      // the setcc result into the low byte of the zeroed register.
      BuildMI(*ZExt->getParent(), ZExt, ZExt->getDebugLoc(),
              TII->get(X86::INSERT_SUBREG), InsertReg)
          .addReg(ZeroReg)
          .addReg(MI.getOperand(0).getReg())
          .addImm(X86::sub_8bit);
      MRI->replaceRegWith(ZExt->getOperand(0).getReg(), InsertReg);
      ToErase.push_back(ZExt);
    }
  }

  for (auto &I : ToErase)
    I->eraseFromParent();

  return Changed;
}
<|endoftext|>


<commit_before><commit_msg>statement aligned as second statement in if body but not in a statement block<commit_after><|endoftext|>


<commit_before>// ===============================================================
// Computer Graphics Homework Solutions
// Copyright (C) 2017 by George Wolberg
//
// HW2b.cpp - HW2b class
//
// Written by: George Wolberg, 2017
// ===============================================================

#include "HW2b.h"

// shader ID
enum {HW2B};

// uniform ID
enum {
	MV,
	PROJ,
	THETA,
	SUBDIV,
	TWIST
};

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::HW2b:
//
// HW2b constructor.
//
HW2b::HW2b(const QGLFormat &glf, QWidget *parent) : HW(glf, parent)
{
	// init vars
	m_theta = 0.0f;
	m_subdivisions = 4;
	m_twist = true;
	m_modelview .setToIdentity();
	m_projection.setToIdentity();
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::initializeGL:
//
// Initialization routine before display loop.
// Gets called once before the first time resizeGL() or paintGL() is called.
//
void
HW2b::initializeGL()
{
	// initialize GL function resolution for current context
	initializeGLFunctions();

	// init vertex and fragment shaders
	initShaders();

	// initialize vertex buffer and write positions to vertex shader
	initVertexBuffer();

	// init state variables
	glClearColor(0.0, 0.0, 0.0, 0.0);	// set background color
	glColor3f   (1.0, 1.0, 0.0);		// set foreground color
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::resizeGL:
//
// Resize event handler.
// The input parameters are the window width (w) and height (h).
//
void
HW2b::resizeGL(int w, int h)
{
	// PUT YOUR CODE HERE
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::paintGL:
//
// Update GL scene.
//
void
HW2b::paintGL()
{
	// PUT YOUR CODE HERE
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::controlPanel:
//
// Create control panel groupbox.
//
QGroupBox*
HW2b::controlPanel()
{
	// init group box
	QGroupBox *groupBox = new QGroupBox("Homework 2b");
	groupBox->setStyleSheet(GroupBoxStyle);

	// create labels
	QLabel *label[2];
	label[0] = new QLabel("Theta");
	label[1] = new QLabel("Subdivide");

	// create sliders
	m_sliderTheta  = new QSlider(Qt::Horizontal);
	m_sliderSubdiv = new QSlider(Qt::Horizontal);

	// init sliders
	m_sliderTheta->setRange(0, 360);
	m_sliderTheta->setValue(0);
	m_sliderSubdiv->setRange(0, 6);
	m_sliderSubdiv->setValue(m_subdivisions);

	// create spinBoxes
	m_spinBoxTheta = new QSpinBox;
	m_spinBoxTheta->setRange(0, 360);
	m_spinBoxTheta->setValue(0);
	m_spinBoxSubdiv = new QSpinBox;
	m_spinBoxSubdiv->setRange(0, 6);
	m_spinBoxSubdiv->setValue(m_subdivisions);

	// init checkbox
	m_checkBoxTwist = new QCheckBox("Twist");
	m_checkBoxTwist->setChecked(m_twist);

	// layout for assembling widgets
	QGridLayout *layout = new QGridLayout;
	layout->addWidget(label[0],	   0, 0);
	layout->addWidget(m_sliderTheta,   0, 1);
	layout->addWidget(m_spinBoxTheta,  0, 2);
	layout->addWidget(label[1],	   1, 0);
	layout->addWidget(m_sliderSubdiv,  1, 1);
	layout->addWidget(m_spinBoxSubdiv, 1, 2);
	layout->addWidget(m_checkBoxTwist, 2, 0);

	// assign layout to group box
	groupBox->setLayout(layout);

	// init signal/slot connections
	connect(m_sliderTheta,   SIGNAL(valueChanged(int)), this, SLOT(changeTheta (int)));
	connect(m_sliderSubdiv,  SIGNAL(valueChanged(int)), this, SLOT(changeSubdiv(int)));
	connect(m_spinBoxTheta,  SIGNAL(valueChanged(int)), this, SLOT(changeTheta (int)));
	connect(m_spinBoxSubdiv, SIGNAL(valueChanged(int)), this, SLOT(changeSubdiv(int)));
	connect(m_checkBoxTwist, SIGNAL(stateChanged(int)), this, SLOT(changeTwist (int)));

	return(groupBox);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::reset:
//
// Reset parameters.
//
void
HW2b::reset()
{
	// reset parameters
	m_theta		= 0.0f;
	m_subdivisions	= 4;
	m_twist		= true;

	// reset sliders and spinboxes
	m_sliderTheta->blockSignals(true);
	m_sliderTheta->setValue(0.0f);
	m_sliderTheta->blockSignals(false);

	m_spinBoxTheta->blockSignals(true);
	m_spinBoxTheta->setValue(0.0f);
	m_spinBoxTheta->blockSignals(false);
	m_sliderSubdiv->blockSignals(true);
	m_sliderSubdiv->setValue(m_subdivisions);
	m_sliderSubdiv->blockSignals(false);

	m_spinBoxSubdiv->blockSignals(true);
	m_spinBoxSubdiv->setValue(m_subdivisions);
	m_spinBoxSubdiv->blockSignals(false);

	// reset twist checkbox
	m_checkBoxTwist->setChecked(m_twist);

	// recompute geometry
	initVertexBuffer();

	// reset 4x4 modelview matrix
	m_modelview.setToIdentity();

	// draw
	updateGL();
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::initShaders:
//
// Initialize vertex and fragment shaders.
//
void
HW2b::initShaders()
{

	// init uniforms hash table based on uniform variable names and location IDs
	UniformMap uniforms;
	uniforms["u_Modelview" ] = MV;
	uniforms["u_Projection"] = PROJ;
	uniforms["u_Theta"     ] = THETA;
	uniforms["u_Twist"     ] = TWIST;

	// compile shader, bind attribute vars, link shader, and initialize uniform var table
	initShader(HW2B, QString(":/hw2/vshader2b.glsl"), QString(":/hw2/fshader2b.glsl"), uniforms);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::initVertexBuffer:
//
// Initialize vertex buffer.
//
void
HW2b::initVertexBuffer()
{
	// set flag for creating buffers (1st time only)
	static bool flag = 1;

	// verify that we have valid vertex/color buffers
	static GLuint vertexBuffer = -1;
	static GLuint colorBuffer  = -1;
	if(flag) {      // create vertex and color buffers
		glGenBuffers(1, &vertexBuffer);
		glGenBuffers(1, &colorBuffer );
		flag = 0;       // reset flag
	}

	// init geometry data
	const vec2 vertices[] = {
		vec2( 0.0f,   0.75f ),
		vec2( 0.65f, -0.375f),
		vec2(-0.65f, -0.375f)
	};

	// recursively subdivide triangle into triangular facets;
	// store vertex positions and colors in m_points and m_colors, respectively
	divideTriangle(vertices[0], vertices[1], vertices[2], m_subdivisions);
	m_numPoints = (int) m_points.size();		// save number of vertices

	// bind vertex buffer to the GPU and copy the vertices from CPU to GPU
	glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
	glBufferData(GL_ARRAY_BUFFER, m_numPoints*sizeof(vec2), &m_points[0], GL_STATIC_DRAW);

	// bind color buffer to the GPU and copy the colors from CPU to GPU
	glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
	glBufferData(GL_ARRAY_BUFFER, m_numPoints*sizeof(vec3), &m_colors[0], GL_STATIC_DRAW);

	// clear vertex and color vectors because they have already been copied into GPU
	m_points.clear();
	m_colors.clear();
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::divideTriangle:
//
// Recursive subdivision of triangle (a,b,c). Recurse count times.
//
void
HW2b::divideTriangle(vec2 a, vec2 b, vec2 c, int count)
{
	// PUT YOUR CODE HERE
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::triangle:
//
// Push positions and colors of the three triangle vertices.
//
void
HW2b::triangle(vec2 v1, vec2 v2, vec2 v3)
{
	// init geometry
	m_points.push_back(v1);
	m_points.push_back(v2);
	m_points.push_back(v3);

	// init color
	float r = (float) rand() / RAND_MAX;
	float g = (float) rand() / RAND_MAX;
	float b = (float) rand() / RAND_MAX;
	m_colors.push_back(vec3(r, g, b));
	m_colors.push_back(vec3(r, g, b));
	m_colors.push_back(vec3(r, g, b));
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::changeTheta:
//
// Slot function to change rotation angle.
//
void
HW2b::changeTheta(int angle)
{
	// update slider and spinbox
	m_sliderTheta->blockSignals(true);
	m_sliderTheta->setValue(angle);
	m_sliderTheta->blockSignals(false);

	m_spinBoxTheta->blockSignals(true);
	m_spinBoxTheta->setValue(angle);
	m_spinBoxTheta->blockSignals(false);

	// init vars
	m_theta = angle * (M_PI / 180.);	// convert angle to radians

	// update model's rotation matrix
	m_modelview.setToIdentity();
	m_modelview.rotate(angle, QVector3D(0.0f, 0.0f, 1.0f));

	// draw
	updateGL();
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::changeSubdiv:
//
// Slot function to change number of recursive subdivisions.
//
void
HW2b::changeSubdiv(int subdivisions)
{
	// update slider and spinbox
	m_sliderSubdiv->blockSignals(true);
	m_sliderSubdiv->setValue(subdivisions);
	m_sliderSubdiv->blockSignals(false);

	m_spinBoxSubdiv->blockSignals(true);
	m_spinBoxSubdiv->setValue(subdivisions);
	m_spinBoxSubdiv->blockSignals(false);

	// init vars
	m_subdivisions = subdivisions;

	// compute new vertices and colors
	initVertexBuffer();

	// draw
	updateGL();
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::changeTwist:
//
// Slot function to turn on/off m_twist;
//
void
HW2b::changeTwist(int twist)
{
	// init vars
	m_twist = twist;

	// draw
	updateGL();
}
<commit_msg>Begin HW2B.<commit_after>// ===============================================================
// Computer Graphics Homework Solutions
// Copyright (C) 2017 by George Wolberg
//
// HW2b.cpp - HW2b class
//
// Written by: George Wolberg, 2017
// ===============================================================

#include "HW2b.h"

// shader ID
enum {HW2B};

// uniform ID
enum {
	MV,
	PROJ,
	THETA,
	SUBDIV,
	TWIST
};

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::HW2b:
//
// HW2b constructor.
//
HW2b::HW2b(const QGLFormat &glf, QWidget *parent) : HW(glf, parent)
{
	// init vars
	m_theta = 0.0f;
	m_subdivisions = 4;
	m_twist = true;
	m_modelview .setToIdentity();
	m_projection.setToIdentity();
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::initializeGL:
//
// Initialization routine before display loop.
// Gets called once before the first time resizeGL() or paintGL() is called.
//
void
HW2b::initializeGL()
{
	// initialize GL function resolution for current context
	initializeGLFunctions();

	// init vertex and fragment shaders
	initShaders();

	// initialize vertex buffer and write positions to vertex shader
	initVertexBuffer();

	// init state variables
	glClearColor(0.0, 0.0, 0.0, 0.0);	// set background color
	glColor3f   (1.0, 1.0, 0.0);		// set foreground color
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::resizeGL:
//
// Resize event handler.
// The input parameters are the window width (w) and height (h).
//
void
HW2b::resizeGL(int w, int h)
{
	// PUT YOUR CODE HERE
	m_winW = w;
	m_winH = h;

	// compute aspect ratio
	float ar = (float) w / h;

	// set xmax, ymax;
	float xmax, ymax;
	if(ar > 1.0) {		// wide screen
		xmax = ar;
		ymax = 1.;
	} else {		// tall screen
		xmax = 1.;
		ymax = 1 / ar;
	}

	// set viewport to occupy full canvas
	glViewport(0, 0, w, h);

	// init viewing coordinates for orthographic projection
	glLoadIdentity();
	glOrtho(-xmax, xmax, -ymax, ymax, -1.0, 1.0);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::paintGL:
//
// Update GL scene.
//
void
HW2b::paintGL()
{
	// PUT YOUR CODE HERE
	glClear(GL_COLOR_BUFFER_BIT);

	glDrawArrays(GL_TRIANGLES, 0, 3);

	// for(uint i=0, j=0; i<m_colors.size(); ++i) {
	// 	glColor3f(m_colors[i][0], m_colors[i][1], m_colors[i][2]);

	// 	glBegin(GL_TRIANGLES);
	// 		glVertex2f(m_points[j][0], m_points[j][1]); j++;
	// 		glVertex2f(m_points[j][0], m_points[j][1]); j++;
	// 		glVertex2f(m_points[j][0], m_points[j][1]); j++;
	// 	glEnd();
	// }
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::controlPanel:
//
// Create control panel groupbox.
//
QGroupBox*
HW2b::controlPanel()
{
	// init group box
	QGroupBox *groupBox = new QGroupBox("Homework 2b");
	groupBox->setStyleSheet(GroupBoxStyle);

	// create labels
	QLabel *label[2];
	label[0] = new QLabel("Theta");
	label[1] = new QLabel("Subdivide");

	// create sliders
	m_sliderTheta  = new QSlider(Qt::Horizontal);
	m_sliderSubdiv = new QSlider(Qt::Horizontal);

	// init sliders
	m_sliderTheta->setRange(0, 360);
	m_sliderTheta->setValue(0);
	m_sliderSubdiv->setRange(0, 6);
	m_sliderSubdiv->setValue(m_subdivisions);

	// create spinBoxes
	m_spinBoxTheta = new QSpinBox;
	m_spinBoxTheta->setRange(0, 360);
	m_spinBoxTheta->setValue(0);
	m_spinBoxSubdiv = new QSpinBox;
	m_spinBoxSubdiv->setRange(0, 6);
	m_spinBoxSubdiv->setValue(m_subdivisions);

	// init checkbox
	m_checkBoxTwist = new QCheckBox("Twist");
	m_checkBoxTwist->setChecked(m_twist);

	// layout for assembling widgets
	QGridLayout *layout = new QGridLayout;
	layout->addWidget(label[0],	   0, 0);
	layout->addWidget(m_sliderTheta,   0, 1);
	layout->addWidget(m_spinBoxTheta,  0, 2);
	layout->addWidget(label[1],	   1, 0);
	layout->addWidget(m_sliderSubdiv,  1, 1);
	layout->addWidget(m_spinBoxSubdiv, 1, 2);
	layout->addWidget(m_checkBoxTwist, 2, 0);

	// assign layout to group box
	groupBox->setLayout(layout);

	// init signal/slot connections
	connect(m_sliderTheta,   SIGNAL(valueChanged(int)), this, SLOT(changeTheta (int)));
	connect(m_sliderSubdiv,  SIGNAL(valueChanged(int)), this, SLOT(changeSubdiv(int)));
	connect(m_spinBoxTheta,  SIGNAL(valueChanged(int)), this, SLOT(changeTheta (int)));
	connect(m_spinBoxSubdiv, SIGNAL(valueChanged(int)), this, SLOT(changeSubdiv(int)));
	connect(m_checkBoxTwist, SIGNAL(stateChanged(int)), this, SLOT(changeTwist (int)));

	return(groupBox);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::reset:
//
// Reset parameters.
//
void
HW2b::reset()
{
	// reset parameters
	m_theta		= 0.0f;
	m_subdivisions	= 4;
	m_twist		= true;

	// reset sliders and spinboxes
	m_sliderTheta->blockSignals(true);
	m_sliderTheta->setValue(0.0f);
	m_sliderTheta->blockSignals(false);

	m_spinBoxTheta->blockSignals(true);
	m_spinBoxTheta->setValue(0.0f);
	m_spinBoxTheta->blockSignals(false);
	m_sliderSubdiv->blockSignals(true);
	m_sliderSubdiv->setValue(m_subdivisions);
	m_sliderSubdiv->blockSignals(false);

	m_spinBoxSubdiv->blockSignals(true);
	m_spinBoxSubdiv->setValue(m_subdivisions);
	m_spinBoxSubdiv->blockSignals(false);

	// reset twist checkbox
	m_checkBoxTwist->setChecked(m_twist);

	// recompute geometry
	initVertexBuffer();

	// reset 4x4 modelview matrix
	m_modelview.setToIdentity();

	// draw
	updateGL();
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::initShaders:
//
// Initialize vertex and fragment shaders.
//
void
HW2b::initShaders()
{

	// init uniforms hash table based on uniform variable names and location IDs
	UniformMap uniforms;
	uniforms["u_Modelview" ] = MV;
	uniforms["u_Projection"] = PROJ;
	uniforms["u_Theta"     ] = THETA;
	uniforms["u_Twist"     ] = TWIST;

	// compile shader, bind attribute vars, link shader, and initialize uniform var table
	initShader(HW2B, QString(":/hw2/vshader2b.glsl"), QString(":/hw2/fshader2b.glsl"), uniforms);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::initVertexBuffer:
//
// Initialize vertex buffer.
//
void
HW2b::initVertexBuffer()
{
	// set flag for creating buffers (1st time only)
	static bool flag = 1;

	// verify that we have valid vertex/color buffers
	static GLuint vertexBuffer = -1;
	static GLuint colorBuffer  = -1;
	if(flag) {      // create vertex and color buffers
		glGenBuffers(1, &vertexBuffer);
		glGenBuffers(1, &colorBuffer );
		flag = 0;       // reset flag
	}

	// init geometry data
	const vec2 vertices[] = {
		vec2( 0.0f,   0.75f ),
		vec2( 0.65f, -0.375f),
		vec2(-0.65f, -0.375f)
	};

	// recursively subdivide triangle into triangular facets;
	// store vertex positions and colors in m_points and m_colors, respectively
	divideTriangle(vertices[0], vertices[1], vertices[2], m_subdivisions);
	m_numPoints = (int) m_points.size();		// save number of vertices

	// bind vertex buffer to the GPU and copy the vertices from CPU to GPU
	glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
	glBufferData(GL_ARRAY_BUFFER, m_numPoints*sizeof(vec2), &m_points[0], GL_STATIC_DRAW);

	// bind color buffer to the GPU and copy the colors from CPU to GPU
	glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
	glBufferData(GL_ARRAY_BUFFER, m_numPoints*sizeof(vec3), &m_colors[0], GL_STATIC_DRAW);

	// clear vertex and color vectors because they have already been copied into GPU
	m_points.clear();
	m_colors.clear();
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::divideTriangle:
//
// Recursive subdivision of triangle (a,b,c). Recurse count times.
//
void
HW2b::divideTriangle(vec2 a, vec2 b, vec2 c, int count)
{
	// PUT YOUR CODE HERE
	if(count > 0) {
		vec2 ab = vec2((a[0] + b[0]) / 2.0, (a[1]+b[1]) / 2.0);
		vec2 ac = vec2((a[0] + c[0]) / 2.0, (a[1]+c[1]) / 2.0);
		vec2 bc = vec2((b[0] + c[0]) / 2.0, (b[1]+c[1]) / 2.0);
		divideTriangle( a, ab, ac, count - 1);
		divideTriangle( b, bc, ab, count - 1);
		divideTriangle( c, ac, bc, count - 1);
		divideTriangle(ab, ac, bc, count - 1);
	} else triangle(a, b, c);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::triangle:
//
// Push positions and colors of the three triangle vertices.
//
void
HW2b::triangle(vec2 v1, vec2 v2, vec2 v3)
{
	// init geometry
	m_points.push_back(v1);
	m_points.push_back(v2);
	m_points.push_back(v3);

	// init color
	float r = (float) rand() / RAND_MAX;
	float g = (float) rand() / RAND_MAX;
	float b = (float) rand() / RAND_MAX;
	m_colors.push_back(vec3(r, g, b));
	m_colors.push_back(vec3(r, g, b));
	m_colors.push_back(vec3(r, g, b));
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::changeTheta:
//
// Slot function to change rotation angle.
//
void
HW2b::changeTheta(int angle)
{
	// update slider and spinbox
	m_sliderTheta->blockSignals(true);
	m_sliderTheta->setValue(angle);
	m_sliderTheta->blockSignals(false);

	m_spinBoxTheta->blockSignals(true);
	m_spinBoxTheta->setValue(angle);
	m_spinBoxTheta->blockSignals(false);

	// init vars
	m_theta = angle * (M_PI / 180.);	// convert angle to radians

	// update model's rotation matrix
	m_modelview.setToIdentity();
	m_modelview.rotate(angle, QVector3D(0.0f, 0.0f, 1.0f));

	// draw
	updateGL();
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::changeSubdiv:
//
// Slot function to change number of recursive subdivisions.
//
void
HW2b::changeSubdiv(int subdivisions)
{
	// update slider and spinbox
	m_sliderSubdiv->blockSignals(true);
	m_sliderSubdiv->setValue(subdivisions);
	m_sliderSubdiv->blockSignals(false);

	m_spinBoxSubdiv->blockSignals(true);
	m_spinBoxSubdiv->setValue(subdivisions);
	m_spinBoxSubdiv->blockSignals(false);

	// init vars
	m_subdivisions = subdivisions;

	// compute new vertices and colors
	initVertexBuffer();

	// draw
	updateGL();
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HW2b::changeTwist:
//
// Slot function to turn on/off m_twist;
//
void
HW2b::changeTwist(int twist)
{
	// init vars
	m_twist = twist;

	// draw
	updateGL();
}
<|endoftext|>