<commit_before>#include "../bart_builder.h"
#include "../problem_definition.h"

#include "gtest/gtest.h"
#include "../../test_helpers/bart_test_helper.h"

class BARTBuilderTest : public ::testing::Test {
 protected:
  void SetUp ();

  // FE builder test
  template <int dim>
  void FEBuilderTest ();

  // AQ builder test
  template <int dim>
  void AQBuilderTest ();

  dealii::ParameterHandler prm;
};

void BARTBuilderTest::SetUp () {
  prm.declare_entry("have reflective BC", "false",
                     dealii::Patterns::Bool(), "");
  prm.declare_entry("angular quadrature order", "4",
                     dealii::Patterns::Integer(), "");
  prm.declare_entry("angular quadrature name", "gl",
                     dealii::Patterns::Selection("gl"), "");
  prm.declare_entry("number of groups", "1", dealii::Patterns::Integer(), "");
  prm.declare_entry("transport model", "regular",
                     dealii::Patterns::Selection("regular|ep"), "");

  prm.declare_entry("finite element polynomial degree", "1",
                    dealii::Patterns::Integer(), "");
  prm.declare_entry("do nda", "true",
                    dealii::Patterns::Bool(), "");
  prm.declare_entry("ho spatial discretization", "",
                    dealii::Patterns::Anything(), "");
  prm.declare_entry("nda spatial discretization", "",
                    dealii::Patterns::Anything(), "");

}

template <int dim>
void BARTBuilderTest::FEBuilderTest () {
  BARTBuilder<dim> builders (prm);

  // set values to parameters
  prm.set ("ho spatial discretization", "cfem");
  prm.set ("nda spatial discretization", "cfem");
  builders.SetParams (prm);
  std::vector<dealii::FiniteElement<dim, dim>*> fe_ptrs;
  builders.BuildFESpaces (fe_ptrs);

  // testing for FE names
  EXPECT_EQ (fe_ptrs.front()->get_name(),
      "FE_Q<"+dealii::Utilities::int_to_string(dim)+">(1)");
  EXPECT_EQ (fe_ptrs.back()->get_name(),
      "FE_Q<"+dealii::Utilities::int_to_string(dim)+">(1)");

  // changing FE types
  prm.set ("ho spatial discretization", "dfem");
  prm.set ("nda spatial discretization", "dfem");
  builders.SetParams (prm);
  fe_ptrs.clear ();
  builders.BuildFESpaces (fe_ptrs);
  EXPECT_EQ (fe_ptrs.front()->get_name(),
      "FE_DGQ<"+dealii::Utilities::int_to_string(dim)+">(1)");
  EXPECT_EQ (fe_ptrs.back()->get_name(),
      "FE_DGQ<"+dealii::Utilities::int_to_string(dim)+">(1)");

  // changing NDA FE type
  prm.set ("nda spatial discretization", "cmfd");
  builders.SetParams (prm);
  fe_ptrs.clear ();
  builders.BuildFESpaces (fe_ptrs);
  EXPECT_EQ (fe_ptrs.back()->get_name(),
      "FE_DGQ<"+dealii::Utilities::int_to_string(dim)+">(0)");

  // changing NDA FE type
  prm.set ("nda spatial discretization", "rtk");
  builders.SetParams (prm);
  fe_ptrs.clear ();
  builders.BuildFESpaces (fe_ptrs);
  EXPECT_EQ (fe_ptrs.back()->get_name(),
      "FE_RaviartThomas<"+dealii::Utilities::int_to_string(dim)+">(1)");
}

TEST_F (BARTBuilderTest, FEBuilder2DTest) {
  FEBuilderTest<2> ();
}

TEST_F (BARTBuilderTest, FEBuilder3DTest) {
  FEBuilderTest<3> ();
}

template <int dim>
void BARTBuilderTest::AQBuilderTest () {
  BARTBuilder<dim> builders (prm);
  std::unique_ptr<AQBase<dim>> aq_ptr;
  std::string aq_name = (dim==1) ? "gl" : "lsgc";
  prm.set ("angular quadrature name", aq_name);
  prm.set ("angular quadrature order", "4");

  // call builder function to build aq
  builders.BuildAQ (prm, aq_ptr);
  aq_ptr->MakeAQ();
  auto wi = aq_ptr->GetAQWeights();
  auto omega_i = aq_ptr->GetAQDirs();

  // check output
  std::string filename = "aq_builder_"+dealii::Utilities::int_to_string(dim)+"d";
  btest::GoldTestInit(filename);
  for (unsigned int i=0; i<wi.size(); ++i)
  {
    dealii::deallog << "Weight: " << wi[i] << "; Omega: ";
    for (int j=0; j<dim; ++j)
      dealii::deallog << omega_i[i][j] << " ";
    dealii::deallog << std::endl;
  }
  btest::GoldTestRun(filename);
}

TEST_F (BARTBuilderTest, AQBuilder1DTest) {
  AQBuilderTest<1> ();
}

TEST_F (BARTBuilderTest, AQBuilder2DTest) {
  AQBuilderTest<2> ();
}

TEST_F (BARTBuilderTest, AQBuilder3DTest) {
  AQBuilderTest<3> ();
}
<commit_msg>Fixed aq builder test failure #80<commit_after>#include "../bart_builder.h"
#include "../problem_definition.h"

#include "gtest/gtest.h"
#include "../../test_helpers/bart_test_helper.h"

class BARTBuilderTest : public ::testing::Test {
 protected:
  void SetUp ();

  // FE builder test
  template <int dim>
  void FEBuilderTest ();

  // AQ builder test
  template <int dim>
  void AQBuilderTest ();

  dealii::ParameterHandler prm;
};

void BARTBuilderTest::SetUp () {
  prm.declare_entry("have reflective BC", "false",
                     dealii::Patterns::Bool(), "");
  prm.declare_entry("angular quadrature order", "4",
                     dealii::Patterns::Integer(), "");
  prm.declare_entry("angular quadrature name", "gl",
                     dealii::Patterns::Selection("gl|lsgc"), "");
  prm.declare_entry("number of groups", "1", dealii::Patterns::Integer(), "");
  prm.declare_entry("transport model", "regular",
                     dealii::Patterns::Selection("regular|ep"), "");

  prm.declare_entry("finite element polynomial degree", "1",
                    dealii::Patterns::Integer(), "");
  prm.declare_entry("do nda", "true",
                    dealii::Patterns::Bool(), "");
  prm.declare_entry("ho spatial discretization", "",
                    dealii::Patterns::Anything(), "");
  prm.declare_entry("nda spatial discretization", "",
                    dealii::Patterns::Anything(), "");

}

template <int dim>
void BARTBuilderTest::FEBuilderTest () {
  BARTBuilder<dim> builders (prm);

  // set values to parameters
  prm.set ("ho spatial discretization", "cfem");
  prm.set ("nda spatial discretization", "cfem");
  builders.SetParams (prm);
  std::vector<dealii::FiniteElement<dim, dim>*> fe_ptrs;
  builders.BuildFESpaces (fe_ptrs);

  // testing for FE names
  EXPECT_EQ (fe_ptrs.front()->get_name(),
      "FE_Q<"+dealii::Utilities::int_to_string(dim)+">(1)");
  EXPECT_EQ (fe_ptrs.back()->get_name(),
      "FE_Q<"+dealii::Utilities::int_to_string(dim)+">(1)");

  // changing FE types
  prm.set ("ho spatial discretization", "dfem");
  prm.set ("nda spatial discretization", "dfem");
  builders.SetParams (prm);
  fe_ptrs.clear ();
  builders.BuildFESpaces (fe_ptrs);
  EXPECT_EQ (fe_ptrs.front()->get_name(),
      "FE_DGQ<"+dealii::Utilities::int_to_string(dim)+">(1)");
  EXPECT_EQ (fe_ptrs.back()->get_name(),
      "FE_DGQ<"+dealii::Utilities::int_to_string(dim)+">(1)");

  // changing NDA FE type
  prm.set ("nda spatial discretization", "cmfd");
  builders.SetParams (prm);
  fe_ptrs.clear ();
  builders.BuildFESpaces (fe_ptrs);
  EXPECT_EQ (fe_ptrs.back()->get_name(),
      "FE_DGQ<"+dealii::Utilities::int_to_string(dim)+">(0)");

  // changing NDA FE type
  prm.set ("nda spatial discretization", "rtk");
  builders.SetParams (prm);
  fe_ptrs.clear ();
  builders.BuildFESpaces (fe_ptrs);
  EXPECT_EQ (fe_ptrs.back()->get_name(),
      "FE_RaviartThomas<"+dealii::Utilities::int_to_string(dim)+">(1)");
}

TEST_F (BARTBuilderTest, FEBuilder2DTest) {
  FEBuilderTest<2> ();
}

TEST_F (BARTBuilderTest, FEBuilder3DTest) {
  FEBuilderTest<3> ();
}

template <int dim>
void BARTBuilderTest::AQBuilderTest () {
  BARTBuilder<dim> builders (prm);
  std::unique_ptr<AQBase<dim>> aq_ptr;
  std::string aq_name = (dim==1) ? "gl" : "lsgc";
  prm.set ("angular quadrature name", aq_name);
  prm.set ("angular quadrature order", "4");

  // call builder function to build aq
  builders.BuildAQ (prm, aq_ptr);
  aq_ptr->MakeAQ();
  auto wi = aq_ptr->GetAQWeights();
  auto omega_i = aq_ptr->GetAQDirs();

  // check output
  std::string filename = "aq_builder_"+dealii::Utilities::int_to_string(dim)+"d";
  btest::GoldTestInit(filename);
  for (unsigned int i=0; i<wi.size(); ++i)
  {
    dealii::deallog << "Weight: " << wi[i] << "; Omega: ";
    for (int j=0; j<dim; ++j)
      dealii::deallog << omega_i[i][j] << " ";
    dealii::deallog << std::endl;
  }
  btest::GoldTestRun(filename);
}

TEST_F (BARTBuilderTest, AQBuilder1DTest) {
  AQBuilderTest<1> ();
}

TEST_F (BARTBuilderTest, AQBuilder2DTest) {
  AQBuilderTest<2> ();
}

TEST_F (BARTBuilderTest, AQBuilder3DTest) {
  AQBuilderTest<3> ();
}
<|endoftext|>


<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

// This is a wrapper program that we use for things we launch via glexec,
// in order to get around glexec's inability to pass environment variables.
// The basic procedure is:
//   1) Condor sets up a UNIX domain socket pair
//   2) Condor invokes this wrapper via glexec, passing one of the sockets
//      to the wrapper as it's standard input stream.
//   3) A stream of environment variables is sent over the socket pair and
//      merged into the environment that will be used for the job.
//   4) The job's "real" standard input FD is sent over the socket pair. The
//      wrapper's socket end is dup'ed and FD 0 is then set to use the
//      received FD.
//   5) The wrapper's socket end is set close-on-exec, and the wrapper then
//      exec's the job.

#define _CONDOR_ALLOW_OPEN

#include "condor_common.h"
#include "MyString.h"
#include "env.h"
#include "fdpass.h"

static char* read_env(int);
static int read_fd(int);

int
main(int, char* argv[])
{
	MyString err;

	// dup FD 0 since well will later replace FD 0 with the job's stdin
	//
	int sock_fd = dup(0);
	if (sock_fd == -1) {
		err.sprintf("dup error on FD 0: %s", strerror(errno));
		write(0, err.Value(), err.Length() + 1);
		exit(1);
	}

	// set up an Env object that we'll use for the job. we'll initialize
	// it with the environment that glexec prepared for us then merge on
	// top of that the environment that Condor sends us
	//
	Env env;
	env.MergeFrom(environ);
	char* env_buf = read_env(sock_fd);
	env.MergeFrom(env_buf);
	delete[] env_buf;

	// now receive an FD on our stdin (which is a UNIX domain socket)
	// that we'll use as the job's stdin
	//
	int job_fd = read_fd(sock_fd);
	if (dup2(job_fd, 0) == -1) {
		err.sprintf("dup2 to FD 0 error: %s", strerror(errno));
		write(sock_fd, err.Value(), err.Length() + 1);
		exit(1);
	}
	close(job_fd);
	if (fcntl(sock_fd, F_SETFD, FD_CLOEXEC) == -1) {
		err.sprintf("fcntl error setting close-on-exec: %s",
		            strerror(errno));
		write(sock_fd, err.Value(), err.Length() + 1);
		exit(1);
	}

	// now we can exec the job. for arguments, we shift this wrappers
	// arguments by one. similarly, the job's executable path is taken
	// as our argv[1]
	//
	char** envp = env.getStringArray();
	execve(argv[1], &argv[1], envp);
	err.sprintf("execve error: %s", strerror(errno));
	write(sock_fd, err.Value(), err.Length() + 1);
	exit(1);
}

static char*
read_env(int sock_fd)
{
	MyString err;
	int env_len;
	if (fread(&env_len, sizeof(env_len), 1, stdin) != 1) {
		if (feof(stdin)) {
			err = "unexpected EOF reading env size";
		}
		else {
			err.sprintf("fread error reading env size: %s",
			            strerror(errno));
		}
		write(sock_fd, err.Value(), err.Length() + 1);
		exit(1);
	}
	if (env_len <= 0) {
		err.sprintf("invalid env size %d read from stdin", env_len);
		write(sock_fd, err.Value(), err.Length() + 1);
		exit(1);
	}
	char* env_buf = new char[env_len];
	if (env_buf == NULL) {
		err.sprintf("failure to allocate %d bytes", env_len);
		write(sock_fd, err.Value(), err.Length() + 1);
		exit(1);
	}
	if (fread(env_buf, env_len, 1, stdin) != 1) {
		if (feof(stdin)) {
			err = "unexpected EOF reading env";
		}
		else {
			err.sprintf("fread error reading env: %s",
			            strerror(errno));
		}
		write(sock_fd, err.Value(), err.Length() + 1);
		exit(1);
	}
	return env_buf;
}

static int
read_fd(int sock_fd)
{
	MyString err;
	int flag;
	if (fread(&flag, sizeof(flag), 1, stdin) != 1) {
		if (feof(stdin)) {
			err = "unexpected EOF reading FD flag";
		}
		else {
			err.sprintf("fread error reading FD flag: %s",
			            strerror(errno));
		}
		write(sock_fd, err.Value(), err.Length() + 1);
		exit(1);
	}
	int fd;
	if (flag) {
		fd = fdpass_recv(sock_fd);
		if (fd == -1) {
			err.sprintf("fdpass_recv failed\n");
			write(sock_fd, err.Value(), err.Length() + 1);
			exit(1);
		}
	}
	else {
		fd = open("/dev/null", O_RDONLY);
		if (fd == -1) {
			err.sprintf("error opening /dev/null: %s",
			            strerror(errno));
			write(sock_fd, err.Value(), err.Length() + 1);
			exit(1);
		}
	}
	return fd;
}
<commit_msg>Revert "Changed environment precedence in condor_glexec_wrapper"<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

// This is a wrapper program that we use for things we launch via glexec,
// in order to get around glexec's inability to pass environment variables.
// The basic procedure is:
//   1) Condor sets up a UNIX domain socket pair
//   2) Condor invokes this wrapper via glexec, passing one of the sockets
//      to the wrapper as it's standard input stream.
//   3) A stream of environment variables is sent over the socket pair and
//      merged into the environment that will be used for the job.
//   4) The job's "real" standard input FD is sent over the socket pair. The
//      wrapper's socket end is dup'ed and FD 0 is then set to use the
//      received FD.
//   5) The wrapper's socket end is set close-on-exec, and the wrapper then
//      exec's the job.

#define _CONDOR_ALLOW_OPEN

#include "condor_common.h"
#include "MyString.h"
#include "env.h"
#include "fdpass.h"

static char* read_env(int);
static int read_fd(int);

int
main(int, char* argv[])
{
	MyString err;

	// dup FD 0 since well will later replace FD 0 with the job's stdin
	//
	int sock_fd = dup(0);
	if (sock_fd == -1) {
		err.sprintf("dup error on FD 0: %s", strerror(errno));
		write(0, err.Value(), err.Length() + 1);
		exit(1);
	}

	// set up an Env object that we'll use for the job. we'll initialize
	// it with the environment that Condor sends us then merge on top of
	// that the environment that glexec prepared for us
	//
	Env env;
	char* env_buf = read_env(sock_fd);
	env.MergeFrom(env_buf);
	env.MergeFrom(environ);
	delete[] env_buf;

	// now receive an FD on our stdin (which is a UNIX domain socket)
	// that we'll use as the job's stdin
	//
	int job_fd = read_fd(sock_fd);
	if (dup2(job_fd, 0) == -1) {
		err.sprintf("dup2 to FD 0 error: %s", strerror(errno));
		write(sock_fd, err.Value(), err.Length() + 1);
		exit(1);
	}
	close(job_fd);
	if (fcntl(sock_fd, F_SETFD, FD_CLOEXEC) == -1) {
		err.sprintf("fcntl error setting close-on-exec: %s",
		            strerror(errno));
		write(sock_fd, err.Value(), err.Length() + 1);
		exit(1);
	}

	// now we can exec the job. for arguments, we shift this wrappers
	// arguments by one. similarly, the job's executable path is taken
	// as our argv[1]
	//
	char** envp = env.getStringArray();
	execve(argv[1], &argv[1], envp);
	err.sprintf("execve error: %s", strerror(errno));
	write(sock_fd, err.Value(), err.Length() + 1);
	exit(1);
}

static char*
read_env(int sock_fd)
{
	MyString err;
	int env_len;
	if (fread(&env_len, sizeof(env_len), 1, stdin) != 1) {
		if (feof(stdin)) {
			err = "unexpected EOF reading env size";
		}
		else {
			err.sprintf("fread error reading env size: %s",
			            strerror(errno));
		}
		write(sock_fd, err.Value(), err.Length() + 1);
		exit(1);
	}
	if (env_len <= 0) {
		err.sprintf("invalid env size %d read from stdin", env_len);
		write(sock_fd, err.Value(), err.Length() + 1);
		exit(1);
	}
	char* env_buf = new char[env_len];
	if (env_buf == NULL) {
		err.sprintf("failure to allocate %d bytes", env_len);
		write(sock_fd, err.Value(), err.Length() + 1);
		exit(1);
	}
	if (fread(env_buf, env_len, 1, stdin) != 1) {
		if (feof(stdin)) {
			err = "unexpected EOF reading env";
		}
		else {
			err.sprintf("fread error reading env: %s",
			            strerror(errno));
		}
		write(sock_fd, err.Value(), err.Length() + 1);
		exit(1);
	}
	return env_buf;
}

static int
read_fd(int sock_fd)
{
	MyString err;
	int flag;
	if (fread(&flag, sizeof(flag), 1, stdin) != 1) {
		if (feof(stdin)) {
			err = "unexpected EOF reading FD flag";
		}
		else {
			err.sprintf("fread error reading FD flag: %s",
			            strerror(errno));
		}
		write(sock_fd, err.Value(), err.Length() + 1);
		exit(1);
	}
	int fd;
	if (flag) {
		fd = fdpass_recv(sock_fd);
		if (fd == -1) {
			err.sprintf("fdpass_recv failed\n");
			write(sock_fd, err.Value(), err.Length() + 1);
			exit(1);
		}
	}
	else {
		fd = open("/dev/null", O_RDONLY);
		if (fd == -1) {
			err.sprintf("error opening /dev/null: %s",
			            strerror(errno));
			write(sock_fd, err.Value(), err.Length() + 1);
			exit(1);
		}
	}
	return fd;
}
<|endoftext|>


<commit_before>#ifndef WEAKPOINTER_HPP
#define WEAKPOINTER_HPP

#include "List.hpp"

namespace org_pqrs_Karabiner {

#define DECLARE_WEAKPOINTER(TYPENAME)                                                            \
  class TYPENAME;                                                                                \
  class WeakPointerManager_##TYPENAME final {                                                    \
  public:                                                                                \
    /* Call WeakPointerManager::add in constructor. */                                           \
    /* For example: */                                                                           \
                                                                                \
    /* ----------------------------------------------- */                                        \
    /* DECLARE_WEAKPOINTER(TestClass);                 */                                        \
    /*                                                 */                                        \
    /* class TestClass final {                         */                                        \
    /* public:                                         */                                        \
    /*   TestClass(void) {                             */                                        \
    /*     WeakPointerManager_TestClass::add(this);    */                                        \
    /*   }                                             */                                        \
    /*   ~TestClass(void) {                            */                                        \
    /*     WeakPointerManager_TestClass::remove(this); */                                        \
    /*   }                                             */                                        \
    /* };                                              */                                        \
    /* ----------------------------------------------- */                                        \
                                                                                \
    /* Note: */                                                                                \
    /* DO NOT call WeakPointerManager::add twice with same pointer. */                           \
    /* If you call WeakPointerManager::add twice, */                                             \
    /* WeakPointerManager::expired will return false with deleted pointer. */                    \
                                                                                \
    static void add(const TYPENAME* p) {                                                         \
      auto item = new WeakPointerManagerItem(p);                                                 \
      if (item) {                                                                                \
        list_.push_back(item);                                                                   \
      }                                                                                \
    }                                                                                \
                                                                                \
    static void remove(const TYPENAME* pointer) {                                                \
      for (WeakPointerManagerItem* p = static_cast<WeakPointerManagerItem*>(list_.safe_front()); \
           p;                                                                                \
           p = static_cast<WeakPointerManagerItem*>(p->getnext())) {                             \
        if (p->pointer == pointer) {                                                             \
          list_.erase_and_delete(p);                                                             \
          break;                                                                                \
        }                                                                                \
      }                                                                                \
    }                                                                                \
                                                                                \
    static bool expired(const TYPENAME* pointer) {                                               \
      for (WeakPointerManagerItem* p = static_cast<WeakPointerManagerItem*>(list_.safe_front()); \
           p;                                                                                \
           p = static_cast<WeakPointerManagerItem*>(p->getnext())) {                             \
        if (p->pointer == pointer) {                                                             \
          return false;                                                                          \
        }                                                                                \
      }                                                                                \
      return true;                                                                               \
    }                                                                                \
                                                                                \
  private:                                                                                \
    class WeakPointerManagerItem : public List::Item {                                           \
    public:                                                                                \
      WeakPointerManagerItem(const TYPENAME* p) : pointer(p) {}                                  \
      virtual ~WeakPointerManagerItem(void) {}                                                   \
                                                                                \
      const TYPENAME* pointer;                                                                   \
    };                                                                                \
                                                                                \
    static List list_;                                                                           \
  };                                                                                \
                                                                                \
  class WeakPointer_##TYPENAME final {                                                           \
  public:                                                                                \
    WeakPointer_##TYPENAME(TYPENAME* p) : pointer_(p) {}                                         \
    bool expired(void) const { return WeakPointerManager_##TYPENAME::expired(pointer_); }        \
                                                                                \
    TYPENAME* operator->(void) const { return pointer_; }                                        \
    TYPENAME* get(void) const { return pointer_; }                                               \
                                                                                \
  private:                                                                                \
    TYPENAME* pointer_;                                                                          \
  };

#define DEFINE_WEAKPOINTER(TYPENAME) \
  List WeakPointerManager_##TYPENAME::list_;

#define DEFINE_WEAKPOINTER_IN_CLASS(CLASS, TYPENAME) \
  List CLASS::WeakPointerManager_##TYPENAME::list_;
}

#endif
<commit_msg>improved WeakPointer for reuse address<commit_after>#ifndef WEAKPOINTER_HPP
#define WEAKPOINTER_HPP

#include "List.hpp"

namespace org_pqrs_Karabiner {

#define DECLARE_WEAKPOINTER(TYPENAME)                                                            \
  class TYPENAME;                                                                                \
  class WeakPointerManager_##TYPENAME final {                                                    \
  public:                                                                                \
    /* Call WeakPointerManager::add in constructor. */                                           \
    /* For example: */                                                                           \
                                                                                \
    /* ----------------------------------------------- */                                        \
    /* DECLARE_WEAKPOINTER(TestClass);                 */                                        \
    /*                                                 */                                        \
    /* class TestClass final {                         */                                        \
    /* public:                                         */                                        \
    /*   TestClass(void) {                             */                                        \
    /*     WeakPointerManager_TestClass::add(this);    */                                        \
    /*   }                                             */                                        \
    /*   ~TestClass(void) {                            */                                        \
    /*     WeakPointerManager_TestClass::remove(this); */                                        \
    /*   }                                             */                                        \
    /* };                                              */                                        \
    /* ----------------------------------------------- */                                        \
                                                                                \
    /* Note: */                                                                                \
    /* DO NOT call WeakPointerManager::add twice with same pointer. */                           \
    /* If you call WeakPointerManager::add twice, */                                             \
    /* WeakPointerManager::expired will return false with deleted pointer. */                    \
                                                                                \
    static void add(const TYPENAME* p) {                                                         \
      auto item = new WeakPointerManagerItem(p, ++lastid_);                                      \
      if (item) {                                                                                \
        list_.push_back(item);                                                                   \
      }                                                                                \
    }                                                                                \
                                                                                \
    static void remove(const TYPENAME* pointer) {                                                \
      for (WeakPointerManagerItem* p = static_cast<WeakPointerManagerItem*>(list_.safe_front()); \
           p;                                                                                \
           p = static_cast<WeakPointerManagerItem*>(p->getnext())) {                             \
        if (p->pointer == pointer) {                                                             \
          list_.erase_and_delete(p);                                                             \
          break;                                                                                \
        }                                                                                \
      }                                                                                \
    }                                                                                \
                                                                                \
    static bool expired(const TYPENAME* pointer, int id) {                                       \
      for (WeakPointerManagerItem* p = static_cast<WeakPointerManagerItem*>(list_.safe_front()); \
           p;                                                                                \
           p = static_cast<WeakPointerManagerItem*>(p->getnext())) {                             \
        if (p->pointer == pointer && p->id == id) {                                              \
          return false;                                                                          \
        }                                                                                \
      }                                                                                \
      return true;                                                                               \
    }                                                                                \
                                                                                \
    static int getid(const TYPENAME* pointer) {                                                  \
      for (WeakPointerManagerItem* p = static_cast<WeakPointerManagerItem*>(list_.safe_front()); \
           p;                                                                                \
           p = static_cast<WeakPointerManagerItem*>(p->getnext())) {                             \
        if (p->pointer == pointer) {                                                             \
          return p->id;                                                                          \
        }                                                                                \
      }                                                                                \
      return -1;                                                                                \
    }                                                                                \
                                                                                \
  private:                                                                                \
    class WeakPointerManagerItem final : public List::Item {                                     \
    public:                                                                                \
      WeakPointerManagerItem(const TYPENAME* p, int c) : pointer(p), id(c) {}                    \
      ~WeakPointerManagerItem(void) {}                                                           \
                                                                                \
      const TYPENAME* pointer;                                                                   \
      int id;                                                                                \
    };                                                                                \
                                                                                \
    static List list_;                                                                           \
    static int lastid_;                                                                          \
  };                                                                                \
                                                                                \
  class WeakPointer_##TYPENAME final {                                                           \
  public:                                                                                \
    WeakPointer_##TYPENAME(TYPENAME* p) : pointer_(p),                                           \
                                          id_(WeakPointerManager_##TYPENAME::getid(p)) {}        \
    bool expired(void) const { return WeakPointerManager_##TYPENAME::expired(pointer_, id_); }   \
                                                                                \
    TYPENAME* operator->(void) const { return pointer_; }                                        \
    TYPENAME* get(void) const { return pointer_; }                                               \
                                                                                \
    bool operator==(WeakPointer_##TYPENAME other) const {                                        \
      return pointer_ == other.pointer_ && id_ == other.id_;                                     \
    }                                                                                \
                                                                                \
  private:                                                                                \
    TYPENAME* pointer_;                                                                          \
    int id_;                                                                                \
  };

#define DEFINE_WEAKPOINTER(TYPENAME)         \
  List WeakPointerManager_##TYPENAME::list_; \
  int WeakPointerManager_##TYPENAME::lastid_ = 0;

#define DEFINE_WEAKPOINTER_IN_CLASS(CLASS, TYPENAME) \
  List CLASS::WeakPointerManager_##TYPENAME::list_;  \
  int CLASS::WeakPointerManager_##TYPENAME::lastid_ = 0;
}

#endif
<|endoftext|>


<commit_before>/*
 * FilePath.cpp
 *
 * Copyright (C) 2020 by RStudio, PBC
 *
 * Unless you have received this program directly from RStudio pursuant to the terms of a commercial license agreement
 * with RStudio, then this program is licensed to you under the following terms:
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#include <tests/TestThat.hpp>

#include <shared_core/FilePath.hpp>

namespace rstudio {
namespace core {

TEST_CASE("Empty File Path tests")
{
   SECTION("Construction")
   {
      FilePath f;
      CHECK(f.getAbsolutePath().empty());
   }

   SECTION("Comparison (equal, true)")
   {
      FilePath f1, f2;

      CHECK(f1 == f2);
      CHECK(f2 == f1);
      CHECK(f1 == f1);
   }

   SECTION("Comparison (equal, false)")
   {
      FilePath f1, f2("/a/different/path");

      CHECK_FALSE(f1 == f2);
      CHECK_FALSE(f2 == f1);
   }

   SECTION("Comparison (inequal, false)")
   {
      FilePath f1, f2;

      CHECK_FALSE(f1 != f2);
      CHECK_FALSE(f2 != f1);
      CHECK_FALSE(f1 != f1);
   }

   SECTION("Comparison (inequal, true)")
   {
      FilePath f1, f2("/a/different/path");

      CHECK(f1 != f2);
      CHECK(f2 != f1);
   }

   SECTION("Comparison (lt)")
   {
      FilePath f1, f2("/a/different/path");

      CHECK(f1 < f2);
      CHECK_FALSE(f2 < f1);
   }

   SECTION("Retrieval methods")
   {
      FilePath f;
      std::vector<FilePath> children;

      CHECK_FALSE(f.exists());
      CHECK(f.getAbsolutePath().empty());
      CHECK(f.getAbsolutePathNative().empty());
#ifdef _WIN32
      CHECK(f.getAbsolutePathW().empty());
#endif
      CHECK(f.getCanonicalPath().empty());
      CHECK(f.getChildren(children)); // Returns error.
      CHECK(children.empty());
      CHECK(f.getExtension().empty());
      CHECK(f.getExtensionLowerCase().empty());
      CHECK(f.getFilename().empty());
      CHECK(f.getLastWriteTime() == 0);
      CHECK(f.getLexicallyNormalPath().empty());
      CHECK(f.getMimeContentType() == "text/plain"); // text/plain is the default.
      CHECK(f.getParent() == f); // Error on getting the parent, so self should be returned.
      CHECK(f.getRelativePath(FilePath("/a/parent/path")) == "");
      CHECK(f.getSize() == 0);
      CHECK(f.getSizeRecursive() == 0);
      CHECK(f.getStem().empty());
      CHECK_FALSE(f.hasExtension("ext"));
      CHECK_FALSE(f.hasTextMimeType()); // has text mime type sets the default mime type as "application/octet-stream"
      CHECK_FALSE(f.isDirectory());
      CHECK(f.isEmpty());
      CHECK_FALSE(f.isHidden());
      CHECK_FALSE(f.isJunction());
      CHECK_FALSE(f.isRegularFile());
      CHECK_FALSE(f.isSymlink());
      CHECK(f.isWithin(f));
      CHECK_FALSE(f.isWithin(FilePath("/some/path")));
   }
}

} // namespace core
} // namespace rstudio
<commit_msg>clean up clang tidy warning about str.empty<commit_after>/*
 * FilePath.cpp
 *
 * Copyright (C) 2020 by RStudio, PBC
 *
 * Unless you have received this program directly from RStudio pursuant to the terms of a commercial license agreement
 * with RStudio, then this program is licensed to you under the following terms:
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#include <tests/TestThat.hpp>

#include <shared_core/FilePath.hpp>

namespace rstudio {
namespace core {

TEST_CASE("Empty File Path tests")
{
   SECTION("Construction")
   {
      FilePath f;
      CHECK(f.getAbsolutePath().empty());
   }

   SECTION("Comparison (equal, true)")
   {
      FilePath f1, f2;

      CHECK(f1 == f2);
      CHECK(f2 == f1);
      CHECK(f1 == f1);
   }

   SECTION("Comparison (equal, false)")
   {
      FilePath f1, f2("/a/different/path");

      CHECK_FALSE(f1 == f2);
      CHECK_FALSE(f2 == f1);
   }

   SECTION("Comparison (inequal, false)")
   {
      FilePath f1, f2;

      CHECK_FALSE(f1 != f2);
      CHECK_FALSE(f2 != f1);
      CHECK_FALSE(f1 != f1);
   }

   SECTION("Comparison (inequal, true)")
   {
      FilePath f1, f2("/a/different/path");

      CHECK(f1 != f2);
      CHECK(f2 != f1);
   }

   SECTION("Comparison (lt)")
   {
      FilePath f1, f2("/a/different/path");

      CHECK(f1 < f2);
      CHECK_FALSE(f2 < f1);
   }

   SECTION("Retrieval methods")
   {
      FilePath f;
      std::vector<FilePath> children;

      CHECK_FALSE(f.exists());
      CHECK(f.getAbsolutePath().empty());
      CHECK(f.getAbsolutePathNative().empty());
#ifdef _WIN32
      CHECK(f.getAbsolutePathW().empty());
#endif
      CHECK(f.getCanonicalPath().empty());
      CHECK(f.getChildren(children)); // Returns error.
      CHECK(children.empty());
      CHECK(f.getExtension().empty());
      CHECK(f.getExtensionLowerCase().empty());
      CHECK(f.getFilename().empty());
      CHECK(f.getLastWriteTime() == 0);
      CHECK(f.getLexicallyNormalPath().empty());
      CHECK(f.getMimeContentType() == "text/plain"); // text/plain is the default.
      CHECK(f.getParent() == f); // Error on getting the parent, so self should be returned.
      CHECK(f.getRelativePath(FilePath("/a/parent/path")).empty());
      CHECK(f.getSize() == 0);
      CHECK(f.getSizeRecursive() == 0);
      CHECK(f.getStem().empty());
      CHECK_FALSE(f.hasExtension("ext"));
      CHECK_FALSE(f.hasTextMimeType()); // has text mime type sets the default mime type as "application/octet-stream"
      CHECK_FALSE(f.isDirectory());
      CHECK(f.isEmpty());
      CHECK_FALSE(f.isHidden());
      CHECK_FALSE(f.isJunction());
      CHECK_FALSE(f.isRegularFile());
      CHECK_FALSE(f.isSymlink());
      CHECK(f.isWithin(f));
      CHECK_FALSE(f.isWithin(FilePath("/some/path")));
   }
}

} // namespace core
} // namespace rstudio
<|endoftext|>


<commit_before>// This file is part of Poseidon.
// Copyleft 2020, LH_Mouse. All wrongs reserved.

#include "precompiled.hpp"
#include "static/main_config.hpp"
#include "static/async_logger.hpp"
#include "static/timer_driver.hpp"
#include "static/network_driver.hpp"
#include "utilities.hpp"
#include <locale.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>

using namespace poseidon;

namespace {

[[noreturn]]
int
do_print_help_and_exit(const char* self)
  {
    ::printf(
//        1         2         3         4         5         6         7     |
// 3456789012345678901234567890123456789012345678901234567890123456789012345|
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""" R"'''''''''''''''(
Usage: %s [OPTIONS] [[--] DIRECTORY]

  -d      daemonize
  -h      show help message then exit
  -V      show version information then exit
  -v      enable verbose mode

Daemonization, if requested, is performed after loading config files. Early
failues are printed to standard error.

If DIRECTORY is specified, the working directory is switched there before
doing everything else.

Visit the homepage at <%s>.
Report bugs to <%s>.
)'''''''''''''''" """"""""""""""""""""""""""""""""""""""""""""""""""""""""+1,
// 3456789012345678901234567890123456789012345678901234567890123456789012345|
//        1         2         3         4         5         6         7     |
      self,
      PACKAGE_URL,
      PACKAGE_BUGREPORT);

    ::fflush(stdout);
    ::quick_exit(0);
  }

const char*
do_tell_build_time()
  {
    static char s_time_str[64];
    if(ROCKET_EXPECT(s_time_str[0]))
      return s_time_str;

    // Convert the build time to ISO 8601 format.
    ::tm tr;
    ::std::memset(&tr, 0, sizeof(tr));
    ::strptime(__DATE__ " " __TIME__, "%b %d %Y %H:%M:%S", &tr);
    ::strftime(s_time_str, sizeof(s_time_str), "%Y-%m-%d %H:%M:%S", &tr);
    return s_time_str;
  }

[[noreturn]]
int
do_print_version_and_exit()
  {
    ::printf(
//        1         2         3         4         5         6         7     |
// 3456789012345678901234567890123456789012345678901234567890123456789012345|
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""" R"'''''''''''''''(
%s [built on %s]

Visit the homepage at <%s>.
Report bugs to <%s>.
)'''''''''''''''" """"""""""""""""""""""""""""""""""""""""""""""""""""""""+1,
// 3456789012345678901234567890123456789012345678901234567890123456789012345|
//        1         2         3         4         5         6         7     |
      PACKAGE_STRING, do_tell_build_time(),
      PACKAGE_URL,
      PACKAGE_BUGREPORT);

    ::fflush(stdout);
    ::quick_exit(0);
  }

// We want to detect Ctrl-C.
::std::atomic<bool> exit_now;

void
do_trap_exit_signal(int sig)
noexcept
  {
    // Trap Ctrl-C. Failure to set the signal handler is ignored.
    struct ::sigaction sigx = { };
    sigx.sa_handler = [](int) { exit_now = 1;  };
    ::sigaction(sig, &sigx, nullptr);
  }

// Define command-line options here.
struct Command_Line_Options
  {
    // options
    bool daemonize = false;
    bool verbose = false;

    // non-options
    cow_string cd_here;
  };

// This may also be automatic objects. It is declared here for convenience.
Command_Line_Options cmdline;

// These are process exit status codes.
enum Exit_Code : uint8_t
  {
    exit_success            = 0,
    exit_system_error       = 1,
    exit_invalid_argument   = 2,
  };

[[noreturn]]
int
do_exit(Exit_Code code, const char* fmt = nullptr, ...)
noexcept
  {
    // Output the string to standard error.
    if(fmt) {
      ::va_list ap;
      va_start(ap, fmt);
      ::vfprintf(stderr, fmt, ap);
      va_end(ap);
    }

    // Perform fast exit.
    ::fflush(nullptr);
    ::quick_exit(static_cast<int>(code));
  }

void
do_parse_command_line(int argc, char** argv)
  {
    bool help = false;
    bool version = false;

    opt<bool> daemonize;
    opt<bool> verbose;
    opt<cow_string> cd_here;

    // Check for some common options before calling `getopt()`.
    if(argc > 1) {
      if(::strcmp(argv[1], "--help") == 0)
        do_print_help_and_exit(argv[0]);

      if(::strcmp(argv[1], "--version") == 0)
        do_print_version_and_exit();
    }

    // Parse command-line options.
    int ch;
    while((ch = ::getopt(argc, argv, "+dhVv")) != -1) {
      // Identify a single option.
      switch(ch) {
        case 'd':
          daemonize = true;
          continue;

        case 'h':
          help = true;
          continue;

        case 'V':
          version = true;
          continue;

        case 'v':
          verbose = true;
          continue;
      }

      // `getopt()` will have written an error message to standard error.
      do_exit(exit_invalid_argument, "Try `%s -h` for help.\n",
                                     argv[0]);
    }

    // Check for early exit conditions.
    if(help)
      do_print_help_and_exit(argv[0]);

    if(version)
      do_print_version_and_exit();

    // If more arguments follow, they denote the working directory.
    if(argc - optind > 1)
      do_exit(exit_invalid_argument, "%s: too many arguments -- '%s'\n"
                                     "Try `%s -h` for help.\n",
                                     argv[0], argv[optind+1],
                                     argv[0]);

    if(argc - optind > 0)
      cd_here = cow_string(argv[optind]);

    // Daemonization mode is off by default.
    if(daemonize)
      cmdline.daemonize = *daemonize;

    // Verbose mode is off by default.
    if(verbose)
      cmdline.verbose = *verbose;

    // The default working directory is empty which means 'do not switch'.
    if(cd_here)
      cmdline.cd_here = ::std::move(*cd_here);
  }

}  // namespace

int
main(int argc, char** argv)
  try {
    // Select the C locale.
    // UTF-8 is required for wide-oriented standard streams.
    ::setlocale(LC_ALL, "C.UTF-8");

    // Note that this function shall not return in case of errors.
    do_parse_command_line(argc, argv);

    // Set current working directory if one is specified.
    if(cmdline.cd_here.size())
      if(::chdir(cmdline.cd_here.safe_c_str()) != 0)
        POSEIDON_THROW("could not set working directory to '$2'\n"
                       "[`chdir()` failed: $1]",
                       noadl::format_errno(errno), cmdline.cd_here);

    // Load 'main.conf' before daemonization, so any earlier failures are
    // visible to the user.
    Main_Config::reload();
    Async_Logger::reload();
    Network_Driver::reload();

    // Daemonize the process before entering modal loop.
    if(cmdline.daemonize)
      if(::daemon(1, 0) != 0)
        POSEIDON_THROW("could not daemonize process\n"
                       "[`chdir()` failed: $1]",
                       noadl::format_errno(errno));

    // Set name of the main thread. Failure to set the name is ignored.
    ::pthread_setname_np(::pthread_self(), "poseidon");

    // Disable cancellation for safety. Failure to set the cancel state is ignored.
    ::pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr);

    // Trap exit signals. Failure to set signal handlers is ignored.
    // This also makes stdio functions fail immediately.
    do_trap_exit_signal(SIGINT);
    do_trap_exit_signal(SIGTERM);
    do_trap_exit_signal(SIGHUP);

    // Ignore `SIGPIPE` for good.
    ::signal(SIGPIPE, SIG_IGN);

    // Start daemon threads.
    Async_Logger::start();
    Timer_Driver::start();
    Network_Driver::start();

    sleep(10000);
    do_exit(exit_success, "interrupt\n");
  }
  catch(exception& stdex) {
    // Print the message in `stdex`. There isn't much we can do.
    do_exit(exit_system_error, "%s\n[exception class `%s`]\n",
                               stdex.what(), typeid(stdex).name());
  }
<commit_msg>main: Add startup log<commit_after>// This file is part of Poseidon.
// Copyleft 2020, LH_Mouse. All wrongs reserved.

#include "precompiled.hpp"
#include "static/main_config.hpp"
#include "static/async_logger.hpp"
#include "static/timer_driver.hpp"
#include "static/network_driver.hpp"
#include "utilities.hpp"
#include <locale.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>

using namespace poseidon;

namespace {

[[noreturn]]
int
do_print_help_and_exit(const char* self)
  {
    ::printf(
//        1         2         3         4         5         6         7     |
// 3456789012345678901234567890123456789012345678901234567890123456789012345|
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""" R"'''''''''''''''(
Usage: %s [OPTIONS] [[--] DIRECTORY]

  -d      daemonize
  -h      show help message then exit
  -V      show version information then exit
  -v      enable verbose mode

Daemonization, if requested, is performed after loading config files. Early
failues are printed to standard error.

If DIRECTORY is specified, the working directory is switched there before
doing everything else.

Visit the homepage at <%s>.
Report bugs to <%s>.
)'''''''''''''''" """"""""""""""""""""""""""""""""""""""""""""""""""""""""+1,
// 3456789012345678901234567890123456789012345678901234567890123456789012345|
//        1         2         3         4         5         6         7     |
      self,
      PACKAGE_URL,
      PACKAGE_BUGREPORT);

    ::fflush(stdout);
    ::quick_exit(0);
  }

const char*
do_tell_build_time()
  {
    static char s_time_str[64];
    if(ROCKET_EXPECT(s_time_str[0]))
      return s_time_str;

    // Convert the build time to ISO 8601 format.
    ::tm tr;
    ::std::memset(&tr, 0, sizeof(tr));
    ::strptime(__DATE__ " " __TIME__, "%b %d %Y %H:%M:%S", &tr);
    ::strftime(s_time_str, sizeof(s_time_str), "%Y-%m-%d %H:%M:%S", &tr);
    return s_time_str;
  }

[[noreturn]]
int
do_print_version_and_exit()
  {
    ::printf(
//        1         2         3         4         5         6         7     |
// 3456789012345678901234567890123456789012345678901234567890123456789012345|
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""" R"'''''''''''''''(
%s [built on %s]

Visit the homepage at <%s>.
Report bugs to <%s>.
)'''''''''''''''" """"""""""""""""""""""""""""""""""""""""""""""""""""""""+1,
// 3456789012345678901234567890123456789012345678901234567890123456789012345|
//        1         2         3         4         5         6         7     |
      PACKAGE_STRING, do_tell_build_time(),
      PACKAGE_URL,
      PACKAGE_BUGREPORT);

    ::fflush(stdout);
    ::quick_exit(0);
  }

// We want to detect Ctrl-C.
::std::atomic<bool> exit_now;

void
do_trap_exit_signal(int sig)
noexcept
  {
    // Trap Ctrl-C. Failure to set the signal handler is ignored.
    struct ::sigaction sigx = { };
    sigx.sa_handler = [](int) { exit_now = 1;  };
    ::sigaction(sig, &sigx, nullptr);
  }

// Define command-line options here.
struct Command_Line_Options
  {
    // options
    bool daemonize = false;
    bool verbose = false;

    // non-options
    cow_string cd_here;
  };

// This may also be automatic objects. It is declared here for convenience.
Command_Line_Options cmdline;

// These are process exit status codes.
enum Exit_Code : uint8_t
  {
    exit_success            = 0,
    exit_system_error       = 1,
    exit_invalid_argument   = 2,
  };

[[noreturn]]
int
do_exit(Exit_Code code, const char* fmt = nullptr, ...)
noexcept
  {
    // Output the string to standard error.
    if(fmt) {
      ::va_list ap;
      va_start(ap, fmt);
      ::vfprintf(stderr, fmt, ap);
      va_end(ap);
    }

    // Perform fast exit.
    ::fflush(nullptr);
    ::quick_exit(static_cast<int>(code));
  }

void
do_parse_command_line(int argc, char** argv)
  {
    bool help = false;
    bool version = false;

    opt<bool> daemonize;
    opt<bool> verbose;
    opt<cow_string> cd_here;

    // Check for some common options before calling `getopt()`.
    if(argc > 1) {
      if(::strcmp(argv[1], "--help") == 0)
        do_print_help_and_exit(argv[0]);

      if(::strcmp(argv[1], "--version") == 0)
        do_print_version_and_exit();
    }

    // Parse command-line options.
    int ch;
    while((ch = ::getopt(argc, argv, "+dhVv")) != -1) {
      // Identify a single option.
      switch(ch) {
        case 'd':
          daemonize = true;
          continue;

        case 'h':
          help = true;
          continue;

        case 'V':
          version = true;
          continue;

        case 'v':
          verbose = true;
          continue;
      }

      // `getopt()` will have written an error message to standard error.
      do_exit(exit_invalid_argument, "Try `%s -h` for help.\n",
                                     argv[0]);
    }

    // Check for early exit conditions.
    if(help)
      do_print_help_and_exit(argv[0]);

    if(version)
      do_print_version_and_exit();

    // If more arguments follow, they denote the working directory.
    if(argc - optind > 1)
      do_exit(exit_invalid_argument, "%s: too many arguments -- '%s'\n"
                                     "Try `%s -h` for help.\n",
                                     argv[0], argv[optind+1],
                                     argv[0]);

    if(argc - optind > 0)
      cd_here = cow_string(argv[optind]);

    // Daemonization mode is off by default.
    if(daemonize)
      cmdline.daemonize = *daemonize;

    // Verbose mode is off by default.
    if(verbose)
      cmdline.verbose = *verbose;

    // The default working directory is empty which means 'do not switch'.
    if(cd_here)
      cmdline.cd_here = ::std::move(*cd_here);
  }

}  // namespace

int
main(int argc, char** argv)
  try {
    // Select the C locale.
    // UTF-8 is required for wide-oriented standard streams.
    ::setlocale(LC_ALL, "C.UTF-8");

    // Note that this function shall not return in case of errors.
    do_parse_command_line(argc, argv);

    // Set current working directory if one is specified.
    if(cmdline.cd_here.size())
      if(::chdir(cmdline.cd_here.safe_c_str()) != 0)
        POSEIDON_THROW("could not set working directory to '$2'\n"
                       "[`chdir()` failed: $1]",
                       noadl::format_errno(errno), cmdline.cd_here);

    // Load 'main.conf' before daemonization, so any earlier failures are
    // visible to the user.
    Main_Config::reload();
    Async_Logger::reload();
    Network_Driver::reload();

    // Daemonize the process before entering modal loop.
    if(cmdline.daemonize)
      if(::daemon(1, 0) != 0)
        POSEIDON_THROW("could not daemonize process\n"
                       "[`chdir()` failed: $1]",
                       noadl::format_errno(errno));

    // Set name of the main thread. Failure to set the name is ignored.
    ::pthread_setname_np(::pthread_self(), "poseidon");

    // Disable cancellation for safety. Failure to set the cancel state is ignored.
    ::pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr);

    // Trap exit signals. Failure to set signal handlers is ignored.
    // This also makes stdio functions fail immediately.
    do_trap_exit_signal(SIGINT);
    do_trap_exit_signal(SIGTERM);
    do_trap_exit_signal(SIGHUP);

    // Ignore `SIGPIPE` for good.
    ::signal(SIGPIPE, SIG_IGN);

    // Start daemon threads.
    Async_Logger::start();
    Timer_Driver::start();
    Network_Driver::start();

    POSEIDON_LOG_INFO(PACKAGE_STRING " started up successfully (PID $1)", ::getpid());

    sleep(10000);
    do_exit(exit_success, "interrupt\n");
  }
  catch(exception& stdex) {
    // Print the message in `stdex`. There isn't much we can do.
    do_exit(exit_system_error, "%s\n[exception class `%s`]\n",
                               stdex.what(), typeid(stdex).name());
  }
<|endoftext|>


<commit_before>#include "python_plugin.hh"
#include "inifile.hh"

#include <stdio.h>
#include <stdlib.h>

#define MAX_ERRMSG_SIZE 256

#define ERRMSG(fmt, args...)					\
    do {							\
        char msgbuf[MAX_ERRMSG_SIZE];				\
        snprintf(msgbuf, sizeof(msgbuf) -1,  fmt, ##args);	\
        error_msg = std::string(msgbuf);			\
    } while(0)

#define logPP(level, fmt, ...)						\
    do {								\
        ERRMSG(fmt, ## __VA_ARGS__);					\
	if (log_level >= level) {					\
	    fprintf(stderr, fmt, ## __VA_ARGS__);			\
	    fprintf(stderr,"\n");					\
	}								\
    } while (0)

extern const char *strstore(const char *s);

// http://hafizpariabi.blogspot.com/2008/01/using-custom-deallocator-in.html
// reason: avoid segfaults by del(interp_instance) on program exit
// make delete(interp_instance) a noop wrt Interp
// static void interpDeallocFunc(Interp *interp) {}
static void interpDeallocFunc(Interp *interp) {}

int PythonPlugin::run_string(const char *cmd, bp::object &retval, bool as_file)
{
    if (reload_on_change)
	reload();
    try {
	if (as_file)
	    retval = bp::exec_file(cmd, main_namespace, main_namespace);
	else
	    retval = bp::exec(cmd, main_namespace, main_namespace);
	status = PLUGIN_OK;
    }
    catch (bp::error_already_set) {
	if (PyErr_Occurred()) {
	    exception_msg = handle_pyerror();
	} else
	    exception_msg = "unknown exception";
	status = PLUGIN_EXCEPTION;
	bp::handle_exception();
	PyErr_Clear();
    }
    if (status == PLUGIN_EXCEPTION) {
	logPP(1, "run_string(%s): \n%s",
	      cmd, exception_msg.c_str());
    }
    return status;
}

int PythonPlugin::call(const char *module, const char *callable,
		       bp::object tupleargs, bp::object kwargs, bp::object &retval)
{
    bp::object function;

    if (callable == NULL)
	return PLUGIN_NO_CALLABLE;

    if (reload_on_change)
	reload();

    if (status < PLUGIN_OK)
	return status;

    try {
	if (module == NULL) {  // default to function in toplevel module
	    function = main_namespace[callable];
	} else {
	    bp::object submod =  main_namespace[module];
	    bp::object submod_namespace = submod.attr("__dict__");
	    function = submod_namespace[callable];
	}
	retval = function(*tupleargs, **kwargs);
	status = PLUGIN_OK;
    }
    catch (bp::error_already_set) {
	if (PyErr_Occurred()) {
	   exception_msg = handle_pyerror();
	} else
	    exception_msg = "unknown exception";
	status = PLUGIN_EXCEPTION;
	bp::handle_exception();
	PyErr_Clear();
    }
    if (status == PLUGIN_EXCEPTION) {
	logPP(1, "call(%s.%s): \n%s",
	  module, callable, exception_msg.c_str());
    }
    return status;
}

bool PythonPlugin::is_callable(const char *module,
			       const char *funcname)
{
    bool unexpected = false;
    bool result = false;
    bp::object function;

    if (reload_on_change)
	reload();
    if ((status != PLUGIN_OK) ||
	(funcname == NULL)) {
	return false;
    }
    try {
	if (module == NULL) {  // default to function in toplevel module
	   function = main_namespace[funcname];
	} else {
	    bp::object submod =  main_namespace[module];
	    bp::object submod_namespace = submod.attr("__dict__");
	    function = submod_namespace[funcname];
	}
	result = PyCallable_Check(function.ptr());
    }
    catch (bp::error_already_set) {
	// KeyError expected if not callable
	if (!PyErr_ExceptionMatches(PyExc_KeyError)) {
	    // something else, strange
	    exception_msg = handle_pyerror();
	    unexpected = true;
	}
	result = false;
	PyErr_Clear();
    }
    if (unexpected)
	logPP(1, "is_callable(%s.%s): unexpected exception:\n%s",module,funcname,exception_msg.c_str());

    if (log_level)
	logPP(4, "is_callable(%s.%s) = %s", module ? module : "",funcname,result ? "TRUE":"FALSE");
    return result;
}

int PythonPlugin::reload()
{
    struct stat st;

    if (stat(abs_path, &st)) {
	logPP(1, "reload: stat(%s) returned %s", abs_path, strerror(errno));
	status = PLUGIN_STAT_FAILED;
	return status;
    }
    if (st.st_mtime > module_mtime) {
	module_mtime = st.st_mtime;
	initialize(true);
	logPP(1, "reload(): module %s reloaded, status=%d", module_basename, status);
    } else {
	logPP(5, "reload: no-op");
	status = PLUGIN_OK;
    }
    return status;
}

// decode a Python exception into a string.
// Free function usable without working plugin instance.
std::string handle_pyerror()
{
    PyObject *exc, *val, *tb;
    bp::object formatted_list, formatted;

    PyErr_Fetch(&exc, &val, &tb);
    bp::handle<> hexc(exc), hval(bp::allow_null(val)), htb(bp::allow_null(tb));
    bp::object traceback(bp::import("traceback"));
    if (!tb) {
	bp::object format_exception_only(traceback.attr("format_exception_only"));
	formatted_list = format_exception_only(hexc, hval);
    } else {
	bp::object format_exception(traceback.attr("format_exception"));
	formatted_list = format_exception(hexc, hval, htb);
    }
    formatted = bp::str("\n").join(formatted_list);
    return bp::extract<std::string>(formatted);
}

void PythonPlugin::initialize(bool reload,  Interp *interp )
{
    std::string msg;
    if (Py_IsInitialized()) {
	try {
	    bp::object module = bp::import("__main__");
	    main_namespace = module.attr("__dict__");

	    for(unsigned i = 0; i < inittab_entries.size(); i++) {
		main_namespace[inittab_entries[i]] = bp::import(inittab_entries[i].c_str());
	    }
	    if (interp != NULL) {
	      bp::object interp_module = bp::import("interpreter");
	      bp::scope(interp_module).attr("this") = interp_ptr(interp, interpDeallocFunc);
	    }
	    bp::object result = bp::exec_file(abs_path,
					      main_namespace,
					      main_namespace);
	    status = PLUGIN_OK;
	}
	catch (bp::error_already_set) {
	    if (PyErr_Occurred()) {
		exception_msg = handle_pyerror();
	    } else
		exception_msg = "unknown exception";
	    bp::handle_exception();
	    status = PLUGIN_INIT_EXCEPTION;
	    PyErr_Clear();
	}
	if (status == PLUGIN_INIT_EXCEPTION) {
	    logPP(1, "initialize: module '%s' init failed: \n%s",
		  abs_path, exception_msg.c_str());
	}
    } else {
	status = PLUGIN_PYTHON_NOT_INITIALIZED;
    }
}

PythonPlugin::PythonPlugin(const char *iniFilename,
			   const char *section,
			   struct _inittab *inittab,
			   Interp *interp)
{
    IniFile inifile;
    const char *inistring;

    if (section == NULL) {
	logPP(1, "no section");
	status = PLUGIN_NO_SECTION;
	return;
    }
    if ((iniFilename == NULL) &&
	((iniFilename = getenv("INI_FILE_NAME")) == NULL)) {
	logPP(1, "no inifile");
	status = PLUGIN_NO_INIFILE;
	return;
    }
    if (inifile.Open(iniFilename) == false) {
          logPP(1, "Unable to open inifile:%s:\n", iniFilename);
	  status = PLUGIN_BAD_INIFILE;
	  return;
    }
    if ((inistring = inifile.Find("PLUGIN_DIR", section)) != NULL)
	plugin_dir = strstore(inistring);
    else {
         logPP(1, "no PLUGIN_DIR in inifile:%s:\n", iniFilename);
	 status =  PLUGIN_NO_PLUGIN_DIR;
	 return;
    }
    if ((inistring = inifile.Find("MODULE_BASENAME", section)) != NULL)
	module_basename = strstore(inistring);
    else {
         logPP(1, "no MODULE_BASENAME in inifile:%s:\n", iniFilename);
	 status =  PLUGIN_NO_MODULE_BASENAME;
	 return;
    }
    if ((inistring = inifile.Find("RELOAD_ON_CHANGE", section)) != NULL)
	reload_on_change = (atoi(inistring) > 0);

    if ((inistring = inifile.Find("LOG_LEVEL", section)) != NULL)
	log_level = atoi(inistring);

    inifile.Close();

    char module_path[PATH_MAX];
    strcpy(module_path, plugin_dir );
    strcat(module_path,"/");
    strcat(module_path, module_basename);
    strcat(module_path,".py");

    char real_path[PATH_MAX];
    if (realpath(module_path, real_path) == NULL) {
	logPP(1, "cant resolve path to '%s'", module_path);
	status = PLUGIN_BAD_PATH;
	return;
    }
    struct stat st;
    if (stat(real_path, &st)) {
	logPP(1, "stat(%s) returns %s", real_path, strerror(errno));
	status = PLUGIN_STAT_FAILED;
	return;
    }
    abs_path = strstore(real_path);

    module_mtime = st.st_mtime;      // record timestamp
    Py_SetProgramName((char *) abs_path);
    if ((inittab != NULL) &&
	PyImport_ExtendInittab(inittab)) {
	logPP(1, "cant extend inittab");
	status = PLUGIN_INITTAB_FAILED;
	return;
    }
    Py_Initialize();
    char pathcmd[PATH_MAX];
    sprintf(pathcmd, "import sys\nsys.path.insert(0,\"%s\")", plugin_dir);
    if (PyRun_SimpleString(pathcmd)) {
	logPP(1, "exeception running '%s'", pathcmd);
	exception_msg = "exeception running "; // + pathcmd;
	status = PLUGIN_EXCEPTION_DURING_PATH_APPEND;
	return;
    }
    logPP(3,"PythonPlugin: Python  '%s'",  Py_GetVersion());
    initialize(false, interp);
}

// the externally visible singleton instance
PythonPlugin *python_plugin;

// first caller wins
PythonPlugin *PythonPlugin::configure(const char *iniFilename,
				      const char *section,
				      struct _inittab *inittab,Interp *interp)
{
    if (python_plugin == NULL) {
	python_plugin =  new PythonPlugin(iniFilename, section, inittab, interp);
    }
    return (python_plugin->usable()) ? python_plugin : NULL;
}

<commit_msg>python_plugin: properly init log_level<commit_after>#include "python_plugin.hh"
#include "inifile.hh"

#include <stdio.h>
#include <stdlib.h>

#define MAX_ERRMSG_SIZE 256

#define ERRMSG(fmt, args...)					\
    do {							\
        char msgbuf[MAX_ERRMSG_SIZE];				\
        snprintf(msgbuf, sizeof(msgbuf) -1,  fmt, ##args);	\
        error_msg = std::string(msgbuf);			\
    } while(0)

#define logPP(level, fmt, ...)						\
    do {								\
        ERRMSG(fmt, ## __VA_ARGS__);					\
	if (log_level >= level) {					\
	    fprintf(stderr, fmt, ## __VA_ARGS__);			\
	    fprintf(stderr,"\n");					\
	}								\
    } while (0)

extern const char *strstore(const char *s);

// http://hafizpariabi.blogspot.com/2008/01/using-custom-deallocator-in.html
// reason: avoid segfaults by del(interp_instance) on program exit
// make delete(interp_instance) a noop wrt Interp
// static void interpDeallocFunc(Interp *interp) {}
static void interpDeallocFunc(Interp *interp) {}

int PythonPlugin::run_string(const char *cmd, bp::object &retval, bool as_file)
{
    if (reload_on_change)
	reload();
    try {
	if (as_file)
	    retval = bp::exec_file(cmd, main_namespace, main_namespace);
	else
	    retval = bp::exec(cmd, main_namespace, main_namespace);
	status = PLUGIN_OK;
    }
    catch (bp::error_already_set) {
	if (PyErr_Occurred()) {
	    exception_msg = handle_pyerror();
	} else
	    exception_msg = "unknown exception";
	status = PLUGIN_EXCEPTION;
	bp::handle_exception();
	PyErr_Clear();
    }
    if (status == PLUGIN_EXCEPTION) {
	logPP(1, "run_string(%s): \n%s",
	      cmd, exception_msg.c_str());
    }
    return status;
}

int PythonPlugin::call(const char *module, const char *callable,
		       bp::object tupleargs, bp::object kwargs, bp::object &retval)
{
    bp::object function;

    if (callable == NULL)
	return PLUGIN_NO_CALLABLE;

    if (reload_on_change)
	reload();

    if (status < PLUGIN_OK)
	return status;

    try {
	if (module == NULL) {  // default to function in toplevel module
	    function = main_namespace[callable];
	} else {
	    bp::object submod =  main_namespace[module];
	    bp::object submod_namespace = submod.attr("__dict__");
	    function = submod_namespace[callable];
	}
	retval = function(*tupleargs, **kwargs);
	status = PLUGIN_OK;
    }
    catch (bp::error_already_set) {
	if (PyErr_Occurred()) {
	   exception_msg = handle_pyerror();
	} else
	    exception_msg = "unknown exception";
	status = PLUGIN_EXCEPTION;
	bp::handle_exception();
	PyErr_Clear();
    }
    if (status == PLUGIN_EXCEPTION) {
	logPP(1, "call(%s.%s): \n%s",
	  module, callable, exception_msg.c_str());
    }
    return status;
}

bool PythonPlugin::is_callable(const char *module,
			       const char *funcname)
{
    bool unexpected = false;
    bool result = false;
    bp::object function;

    if (reload_on_change)
	reload();
    if ((status != PLUGIN_OK) ||
	(funcname == NULL)) {
	return false;
    }
    try {
	if (module == NULL) {  // default to function in toplevel module
	   function = main_namespace[funcname];
	} else {
	    bp::object submod =  main_namespace[module];
	    bp::object submod_namespace = submod.attr("__dict__");
	    function = submod_namespace[funcname];
	}
	result = PyCallable_Check(function.ptr());
    }
    catch (bp::error_already_set) {
	// KeyError expected if not callable
	if (!PyErr_ExceptionMatches(PyExc_KeyError)) {
	    // something else, strange
	    exception_msg = handle_pyerror();
	    unexpected = true;
	}
	result = false;
	PyErr_Clear();
    }
    if (unexpected)
	logPP(1, "is_callable(%s.%s): unexpected exception:\n%s",module,funcname,exception_msg.c_str());

    if (log_level)
	logPP(4, "is_callable(%s.%s) = %s", module ? module : "",funcname,result ? "TRUE":"FALSE");
    return result;
}

int PythonPlugin::reload()
{
    struct stat st;

    if (stat(abs_path, &st)) {
	logPP(1, "reload: stat(%s) returned %s", abs_path, strerror(errno));
	status = PLUGIN_STAT_FAILED;
	return status;
    }
    if (st.st_mtime > module_mtime) {
	module_mtime = st.st_mtime;
	initialize(true);
	logPP(1, "reload(): module %s reloaded, status=%d", module_basename, status);
    } else {
	logPP(5, "reload: no-op");
	status = PLUGIN_OK;
    }
    return status;
}

// decode a Python exception into a string.
// Free function usable without working plugin instance.
std::string handle_pyerror()
{
    PyObject *exc, *val, *tb;
    bp::object formatted_list, formatted;

    PyErr_Fetch(&exc, &val, &tb);
    bp::handle<> hexc(exc), hval(bp::allow_null(val)), htb(bp::allow_null(tb));
    bp::object traceback(bp::import("traceback"));
    if (!tb) {
	bp::object format_exception_only(traceback.attr("format_exception_only"));
	formatted_list = format_exception_only(hexc, hval);
    } else {
	bp::object format_exception(traceback.attr("format_exception"));
	formatted_list = format_exception(hexc, hval, htb);
    }
    formatted = bp::str("\n").join(formatted_list);
    return bp::extract<std::string>(formatted);
}

void PythonPlugin::initialize(bool reload,  Interp *interp )
{
    std::string msg;
    if (Py_IsInitialized()) {
	try {
	    bp::object module = bp::import("__main__");
	    main_namespace = module.attr("__dict__");

	    for(unsigned i = 0; i < inittab_entries.size(); i++) {
		main_namespace[inittab_entries[i]] = bp::import(inittab_entries[i].c_str());
	    }
	    if (interp != NULL) {
	      bp::object interp_module = bp::import("interpreter");
	      bp::scope(interp_module).attr("this") = interp_ptr(interp, interpDeallocFunc);
	    }
	    bp::object result = bp::exec_file(abs_path,
					      main_namespace,
					      main_namespace);
	    status = PLUGIN_OK;
	}
	catch (bp::error_already_set) {
	    if (PyErr_Occurred()) {
		exception_msg = handle_pyerror();
	    } else
		exception_msg = "unknown exception";
	    bp::handle_exception();
	    status = PLUGIN_INIT_EXCEPTION;
	    PyErr_Clear();
	}
	if (status == PLUGIN_INIT_EXCEPTION) {
	    logPP(1, "initialize: module '%s' init failed: \n%s",
		  abs_path, exception_msg.c_str());
	}
    } else {
	status = PLUGIN_PYTHON_NOT_INITIALIZED;
    }
}

PythonPlugin::PythonPlugin(const char *iniFilename,
			   const char *section,
			   struct _inittab *inittab,
			   Interp *interp) :
    log_level(0)
{
    IniFile inifile;
    const char *inistring;

    if (section == NULL) {
	logPP(1, "no section");
	status = PLUGIN_NO_SECTION;
	return;
    }
    if ((iniFilename == NULL) &&
	((iniFilename = getenv("INI_FILE_NAME")) == NULL)) {
	logPP(1, "no inifile");
	status = PLUGIN_NO_INIFILE;
	return;
    }
    if (inifile.Open(iniFilename) == false) {
          logPP(1, "Unable to open inifile:%s:\n", iniFilename);
	  status = PLUGIN_BAD_INIFILE;
	  return;
    }
    if ((inistring = inifile.Find("PLUGIN_DIR", section)) != NULL)
	plugin_dir = strstore(inistring);
    else {
         logPP(3, "no PLUGIN_DIR in inifile:%s:\n", iniFilename);
	 status =  PLUGIN_NO_PLUGIN_DIR;
	 return;
    }
    if ((inistring = inifile.Find("MODULE_BASENAME", section)) != NULL)
	module_basename = strstore(inistring);
    else {
         logPP(1, "no MODULE_BASENAME in inifile:%s:\n", iniFilename);
	 status =  PLUGIN_NO_MODULE_BASENAME;
	 return;
    }
    if ((inistring = inifile.Find("RELOAD_ON_CHANGE", section)) != NULL)
	reload_on_change = (atoi(inistring) > 0);

    if ((inistring = inifile.Find("LOG_LEVEL", section)) != NULL)
	log_level = atoi(inistring);

    inifile.Close();

    char module_path[PATH_MAX];
    strcpy(module_path, plugin_dir );
    strcat(module_path,"/");
    strcat(module_path, module_basename);
    strcat(module_path,".py");

    char real_path[PATH_MAX];
    if (realpath(module_path, real_path) == NULL) {
	logPP(1, "cant resolve path to '%s'", module_path);
	status = PLUGIN_BAD_PATH;
	return;
    }
    struct stat st;
    if (stat(real_path, &st)) {
	logPP(1, "stat(%s) returns %s", real_path, strerror(errno));
	status = PLUGIN_STAT_FAILED;
	return;
    }
    abs_path = strstore(real_path);

    module_mtime = st.st_mtime;      // record timestamp
    Py_SetProgramName((char *) abs_path);
    if ((inittab != NULL) &&
	PyImport_ExtendInittab(inittab)) {
	logPP(1, "cant extend inittab");
	status = PLUGIN_INITTAB_FAILED;
	return;
    }
    Py_Initialize();
    char pathcmd[PATH_MAX];
    sprintf(pathcmd, "import sys\nsys.path.insert(0,\"%s\")", plugin_dir);
    if (PyRun_SimpleString(pathcmd)) {
	logPP(1, "exeception running '%s'", pathcmd);
	exception_msg = "exeception running "; // + pathcmd;
	status = PLUGIN_EXCEPTION_DURING_PATH_APPEND;
	return;
    }
    logPP(3,"PythonPlugin: Python  '%s'",  Py_GetVersion());
    initialize(false, interp);
}

// the externally visible singleton instance
PythonPlugin *python_plugin;

// first caller wins
PythonPlugin *PythonPlugin::configure(const char *iniFilename,
				      const char *section,
				      struct _inittab *inittab,Interp *interp)
{
    if (python_plugin == NULL) {
	python_plugin =  new PythonPlugin(iniFilename, section, inittab, interp);
    }
    return (python_plugin->usable()) ? python_plugin : NULL;
}

<|endoftext|>


<commit_before>/** \copyright
 * Copyright (c) 2015, Balazs Racz
 * 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.
 *
 * 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 HOLDER 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 Stm32Gpio.hxx
 *
 * Helper declarations for using GPIO pins (both for GPIO and other hardware)
 * on STM32 microcontrollers.
 *
 * @author Balazs Racz
 * @date 24 Aug 2015
 */

#ifndef _FREERTOS_DRIVERS_ST_STM32GPIO_HXX_
#define _FREERTOS_DRIVERS_ST_STM32GPIO_HXX_

#include "os/Gpio.hxx"
#include "GpioWrapper.hxx"

#if defined(STM32F072xB) || defined(STM32F091xC)
#include "stm32f0xx_hal_gpio.h"
#elif defined(STM32F103xB)
#include "stm32f1xx_hal_gpio.h"
#elif defined(STM32F303xC)
#include "stm32f3xx_hal_gpio.h"
#else
#error Dont know what STM32 chip you have.
#endif

/// Static GPIO implementation for the STM32 microcontrollers. Do not use
/// directly: use @ref GPIO_PIN macro.
/// @param PORT is the port base address pointer (e.g. GPIOC)
/// @param PIN is the GPIO_PIN_# value for the pin number.
/// @param PIN_NUM is the number of the pin in the port. Zero-based.
template <uint32_t GPIOx, uint16_t PIN, uint8_t PIN_NUM> struct Stm32GpioDefs
{
    /// @return the PIO structure of the give gpio port.
    static GPIO_TypeDef *port()
    {
        return (GPIO_TypeDef *)GPIOx;
    }

    /// @return the pin number within the port.
    static uint16_t pin()
    {
        return PIN;
    }

    /// Sets the output pin to a given level.
    static void set(bool value)
    {
        if (value)
        {
#if defined(STM32F303xC)
            port()->BSRRL = pin();
#else
            port()->BSRR = pin();
#endif
        }
        else
        {
#if defined(STM32F303xC)
            port()->BSRRH = pin();
#else
            port()->BSRR = pin() << 16;
#endif
        }
    }

    /// Sets the output pin to a given level.
    static bool get()
    {
        return port()->IDR & pin();
    }

    /// @return a os-indepentent Gpio abstraction instance for use in
    /// libraries.
    static constexpr const Gpio *instance()
    {
        return GpioWrapper<Stm32GpioDefs<GPIOx, PIN, PIN_NUM>>::instance();
    }

    /// @return whether this pin is configured as an output.
    static bool is_output()
    {
        uint8_t* mode = (uint8_t*)port();
        uint8_t m = mode[PIN_NUM >> 1];
        if (PIN_NUM & 1) { m >>= 4; }
        return (m & 3) != 0;
    }

};

template <class Defs, bool SAFE_VALUE> struct GpioOutputPin : public Defs
{
    using Defs::port;
    using Defs::pin;
    using Defs::set;
    /// Initializes the hardware pin.
    static void hw_init()
    {
        GPIO_InitTypeDef gpio_init = {0};
        gpio_init.Pin = pin();
        gpio_init.Mode = GPIO_MODE_OUTPUT_PP;
        gpio_init.Pull = GPIO_NOPULL;
        gpio_init.Speed = GPIO_SPEED_FREQ_LOW;
        HAL_GPIO_Init(port(), &gpio_init);
    }
    /// Sets the output pin to a safe value.
    static void hw_set_to_safe()
    {
        hw_init();
        set(SAFE_VALUE);
    }
};

/// Defines a GPIO output pin, initialized to be an output pin with low level.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioOutputSafeLow : public GpioOutputPin<Defs, false>
{
};

/// Defines a GPIO output pin, initialized to be an output pin with high level.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioOutputSafeHigh : public GpioOutputPin<Defs, true>
{
};

/// Defines a GPIO output pin for driving an LED. The MCU must be in spec for
/// the necessary output current.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs> struct LedPin : public GpioOutputPin<Defs, false>
{
};

template <class Defs, uint32_t PULL_MODE> struct GpioInputPin : public Defs
{
    using Defs::port;
    using Defs::pin;
    using Defs::set;
    /// Initializes the hardware pin.
    static void hw_init()
    {
        GPIO_InitTypeDef gpio_init = {0};
        gpio_init.Pin = pin();
        gpio_init.Mode = GPIO_MODE_INPUT;
        gpio_init.Pull = PULL_MODE;
        gpio_init.Speed = GPIO_SPEED_FREQ_LOW;
        HAL_GPIO_Init(port(), &gpio_init);
    }
    /// Sets the hardware pin to a safe state.
    static void hw_set_to_safe()
    {
        hw_init();
    }
    /// @return true if the pin is set to drive an output.
    static bool is_output()
    {
        return false;
    }
};

/// GPIO Input pin with weak pull up.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioInputPU : public GpioInputPin<Defs, GPIO_PULLUP>
{
};

/// GPIO Input pin with weak pull down.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioInputPD : public GpioInputPin<Defs, GPIO_PULLDOWN>
{
};

/// GPIO Input pin in standard configuration (no pull).
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioInputNP : public GpioInputPin<Defs, GPIO_NOPULL>
{
};

/// Helper macro for defining GPIO pins.
///
/// @param NAME is the basename of the declaration. For NAME==FOO the macro
/// declares FOO_Pin as a structure on which the read-write functions will be
/// available.
///
/// @param BaseClass is the initialization structure, such as @ref LedPin, or
/// @ref GpioOutputSafeHigh or @ref GpioOutputSafeLow.
///
/// @param PORTNAME is a letter defining which port this is (like A, B,
/// C). E.g. for PC8 this is C.
///
/// @param NUM is the pin number, such as 8 for PC8.
///
/// Example:
///  GPIO_PIN(FOO, LedPin, 0, 3);
///  ...
///  FOO_Pin::set(true);
#define GPIO_PIN(NAME, BaseClass, PORTNAME, NUM)                               \
    typedef BaseClass<Stm32GpioDefs<(uint32_t)(GPIO ## PORTNAME ## _BASE), GPIO_PIN_ ## NUM, NUM>> NAME##_Pin

#endif // _FREERTOS_DRIVERS_ST_STM32GPIO_HXX_
<commit_msg>Fixes bug in STM32 GPIO driver that SafeHIgh and SafeLOw for outputs were not taken into account when booting.<commit_after>/** \copyright
 * Copyright (c) 2015, Balazs Racz
 * 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.
 *
 * 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 HOLDER 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 Stm32Gpio.hxx
 *
 * Helper declarations for using GPIO pins (both for GPIO and other hardware)
 * on STM32 microcontrollers.
 *
 * @author Balazs Racz
 * @date 24 Aug 2015
 */

#ifndef _FREERTOS_DRIVERS_ST_STM32GPIO_HXX_
#define _FREERTOS_DRIVERS_ST_STM32GPIO_HXX_

#include "os/Gpio.hxx"
#include "GpioWrapper.hxx"

#if defined(STM32F072xB) || defined(STM32F091xC)
#include "stm32f0xx_hal_gpio.h"
#elif defined(STM32F103xB)
#include "stm32f1xx_hal_gpio.h"
#elif defined(STM32F303xC)
#include "stm32f3xx_hal_gpio.h"
#else
#error Dont know what STM32 chip you have.
#endif

/// Static GPIO implementation for the STM32 microcontrollers. Do not use
/// directly: use @ref GPIO_PIN macro.
/// @param PORT is the port base address pointer (e.g. GPIOC)
/// @param PIN is the GPIO_PIN_# value for the pin number.
/// @param PIN_NUM is the number of the pin in the port. Zero-based.
template <uint32_t GPIOx, uint16_t PIN, uint8_t PIN_NUM> struct Stm32GpioDefs
{
    /// @return the PIO structure of the give gpio port.
    static GPIO_TypeDef *port()
    {
        return (GPIO_TypeDef *)GPIOx;
    }

    /// @return the pin number within the port.
    static uint16_t pin()
    {
        return PIN;
    }

    /// Sets the output pin to a given level.
    static void set(bool value)
    {
        if (value)
        {
#if defined(STM32F303xC)
            port()->BSRRL = pin();
#else
            port()->BSRR = pin();
#endif
        }
        else
        {
#if defined(STM32F303xC)
            port()->BSRRH = pin();
#else
            port()->BSRR = pin() << 16;
#endif
        }
    }

    /// Sets the output pin to a given level.
    static bool get()
    {
        return port()->IDR & pin();
    }

    /// @return a os-indepentent Gpio abstraction instance for use in
    /// libraries.
    static constexpr const Gpio *instance()
    {
        return GpioWrapper<Stm32GpioDefs<GPIOx, PIN, PIN_NUM>>::instance();
    }

    /// @return whether this pin is configured as an output.
    static bool is_output()
    {
        uint8_t* mode = (uint8_t*)port();
        uint8_t m = mode[PIN_NUM >> 1];
        if (PIN_NUM & 1) { m >>= 4; }
        return (m & 3) != 0;
    }

};

template <class Defs, bool SAFE_VALUE> struct GpioOutputPin : public Defs
{
    using Defs::port;
    using Defs::pin;
    using Defs::set;
    /// Initializes the hardware pin.
    static void hw_init()
    {
        GPIO_InitTypeDef gpio_init = {0};
        gpio_init.Pin = pin();
        gpio_init.Mode = GPIO_MODE_OUTPUT_PP;
        gpio_init.Pull = GPIO_NOPULL;
        gpio_init.Speed = GPIO_SPEED_FREQ_LOW;
        HAL_GPIO_Init(port(), &gpio_init);
        set(SAFE_VALUE);
    }
    /// Sets the output pin to a safe value.
    static void hw_set_to_safe()
    {
        hw_init();
        set(SAFE_VALUE);
    }
};

/// Defines a GPIO output pin, initialized to be an output pin with low level.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioOutputSafeLow : public GpioOutputPin<Defs, false>
{
};

/// Defines a GPIO output pin, initialized to be an output pin with high level.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioOutputSafeHigh : public GpioOutputPin<Defs, true>
{
};

/// Defines a GPIO output pin for driving an LED. The MCU must be in spec for
/// the necessary output current.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs> struct LedPin : public GpioOutputPin<Defs, false>
{
};

template <class Defs, uint32_t PULL_MODE> struct GpioInputPin : public Defs
{
    using Defs::port;
    using Defs::pin;
    using Defs::set;
    /// Initializes the hardware pin.
    static void hw_init()
    {
        GPIO_InitTypeDef gpio_init = {0};
        gpio_init.Pin = pin();
        gpio_init.Mode = GPIO_MODE_INPUT;
        gpio_init.Pull = PULL_MODE;
        gpio_init.Speed = GPIO_SPEED_FREQ_LOW;
        HAL_GPIO_Init(port(), &gpio_init);
    }
    /// Sets the hardware pin to a safe state.
    static void hw_set_to_safe()
    {
        hw_init();
    }
    /// @return true if the pin is set to drive an output.
    static bool is_output()
    {
        return false;
    }
};

/// GPIO Input pin with weak pull up.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioInputPU : public GpioInputPin<Defs, GPIO_PULLUP>
{
};

/// GPIO Input pin with weak pull down.
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioInputPD : public GpioInputPin<Defs, GPIO_PULLDOWN>
{
};

/// GPIO Input pin in standard configuration (no pull).
///
/// Do not use this class directly. Use @ref GPIO_PIN instead.
template <class Defs>
struct GpioInputNP : public GpioInputPin<Defs, GPIO_NOPULL>
{
};

/// Helper macro for defining GPIO pins.
///
/// @param NAME is the basename of the declaration. For NAME==FOO the macro
/// declares FOO_Pin as a structure on which the read-write functions will be
/// available.
///
/// @param BaseClass is the initialization structure, such as @ref LedPin, or
/// @ref GpioOutputSafeHigh or @ref GpioOutputSafeLow.
///
/// @param PORTNAME is a letter defining which port this is (like A, B,
/// C). E.g. for PC8 this is C.
///
/// @param NUM is the pin number, such as 8 for PC8.
///
/// Example:
///  GPIO_PIN(FOO, LedPin, 0, 3);
///  ...
///  FOO_Pin::set(true);
#define GPIO_PIN(NAME, BaseClass, PORTNAME, NUM)                               \
    typedef BaseClass<Stm32GpioDefs<(uint32_t)(GPIO ## PORTNAME ## _BASE), GPIO_PIN_ ## NUM, NUM>> NAME##_Pin

#endif // _FREERTOS_DRIVERS_ST_STM32GPIO_HXX_
<|endoftext|>