<commit_before>/*
 * Converts media wiki markup into plaintext
 */

#include <iostream>
#include <sstream>
#include <fstream>
#include <string.h>
#include <pcre.h>
#include <math.h>
#include <dirent.h>

using namespace std;

char* substr(char* dest, const char* src, int start, int len, int n)
{
  if(start >= n)
    throw string("Start index outside of string.");

  int actual_length = min(len, n-start);
  strncpy(dest, &src[start], actual_length);
  dest[actual_length] = '\0';
  return dest;
}

typedef struct _State
{
  int N; // input length
  int pos; // current position in input
  const char* markup; // the markup input we're converting
  char* out;
  int M; // maximum length of output
  int pos_out;
  string groups[10]; // will store regexp matches
} State;

class Textifier
{
private:
  State state;

  bool starts_with(string& str);
  bool starts_with(const char* str);
  const char* get_remaining();
  char* get_current_out();
  void skip_match();
  void append_group_and_skip(int group);

  void do_link();
  void do_format();
  void do_tag();
  void do_meta();
  void do_nowiki();
  void do_heading();
  void do_nested(string name, char open, char close);

  bool get_link_boundaries(int& start, int& end, int& next);

  string get_snippet();
  string get_err(string name);
  string* match(string name, pcre* regexp);

  pcre* make_pcre(const char* expr, int options);
  pcre* re_nowiki;
  pcre* re_format;
  pcre* re_heading;

public:
  Textifier();
  ~Textifier();
  char* textify(const char* markup, const int markup_len,
                char* out, const int out_len);

  void find_location(long& line, long& col);
};

Textifier::Textifier()
{
  // Compile all the regexes we'll need
  re_nowiki  = make_pcre("^<nowiki>(.*?)</nowiki>", PCRE_MULTILINE | PCRE_DOTALL);
  re_format  = make_pcre("^('+)(.*?)\\1", 0);
  re_heading = make_pcre("^(=+)\\s*(.+?)\\s*\\1", 0);
}

Textifier::~Textifier()
{
}

pcre* Textifier::make_pcre(const char* expr, int options)
{
  const char* error;
  int erroffset;
  pcre *re = pcre_compile(expr, options, &error, &erroffset, NULL);

  if(re == NULL) {
    ostringstream os;
    os << "PCRE compilation failed at offset " << erroffset << ": "
       << error << endl;
    throw string(os.str());
  }
  return re;
}

bool Textifier::get_link_boundaries(int& start, int& end, int& next)
{
  int i = state.pos;   // current search position
  int level = 0; // nesting level
  do {
    char ch = state.markup[i];
    switch(ch) {
    case '[':
      if(level++ == 0)
        start = i+1;
      break;

    case ']':
      if(--level == 0)
        end = i;
      break;

    case '|':
      if(level == 1) { // does the pipe belong to current link or a nested one?
        start = i+1;
        end = start;
      }
      break;

    default:
      end++;
      break;
    }

    i++;
  } while(level > 0 &&
          i < state.N &&
          state.markup[i] != '\n');

  next = i;
  return level == 0; // if 0, then brackets match and this is a correct link
}

void Textifier::find_location(long& line, long& column)
{
  line = 1;
  column = 1;
  for(int i = 0; i <= state.pos && i < state.N; i++) {
    if(state.markup[i] == '\n')
      line++;
    else if(line == 1)
      column++;
  }
}

bool Textifier::starts_with(string& str)
{
  return starts_with(str.c_str());
}

bool Textifier::starts_with(const char* str)
{
  int i = state.pos;
  int j = 0;
  while(str[j] != '\0' &&
        i < state.N) {
    if(state.markup[i] != str[j])
      return false;

    i++;
    j++;
  }
  return true;
}

string Textifier::get_snippet()
{
  char snippet[30];
  strncpy(snippet, get_remaining(), 30);
  snippet[min(29, state.N-state.pos)] = '\0';
  return string(snippet);
}

string Textifier::get_err(string name)
{
  ostringstream os;
  os << "Expected " << name << " at '" << get_snippet() << "'";
  return os.str();
}

string* Textifier::match(string name, pcre* regexp)
{
  const int ovector_size = 3*sizeof(state.groups)/sizeof(string);
  int ovector[ovector_size];
  int rc = pcre_exec(regexp, NULL, get_remaining(), state.N-state.pos, 0, 0, ovector, ovector_size);

  if(rc == PCRE_ERROR_NOMATCH || rc == 0)
    return NULL;
  else if(rc < 0)
    throw get_err(name);

  // from pcredemo.c
  for(int i = 0; i < rc; i++) {
    const char *substring_start = get_remaining() + ovector[2*i];
    int substring_length = ovector[2*i+1] - ovector[2*i];
    char substr[substring_length+1];
    strncpy(substr, substring_start, substring_length);
    substr[substring_length]='\0';
    state.groups[i].assign(substr);
  }
  return state.groups;
}

const char* Textifier::get_remaining()
{
  return &state.markup[state.pos];
}

char* Textifier::get_current_out()
{
  return &state.out[state.pos_out];
}

void Textifier::skip_match()
{
  state.pos += state.groups[0].length();
}

void Textifier::append_group_and_skip(int group)
{
  string* val = &state.groups[group];
  strncpy(get_current_out(), val->c_str(), val->length());
  state.pos += state.groups[0].length();
  state.pos_out += val->length();
}

void Textifier::do_link()
{
  int start, end, next;
  if(get_link_boundaries(start, end, next)) {
    char contents[end-start+1];
    substr(contents, state.markup, start, end-start, state.N);
    if(strchr(contents, ':') != NULL) {
      // this is a link to the page in a different language:
      // ignore it
      state.pos = next;
    }
    else {
      State state_copy = state;
      textify(contents, end-start, &state.out[state.pos_out], state.M-state.pos_out);
      state_copy.pos_out += state.pos_out;
      state_copy.pos = next;
      state = state_copy;
    }
  } else {
    // Apparently mediawiki allows unmatched open brackets...
    // If that's what we got, it's not a link.
    state.out[state.pos_out++] = state.markup[state.pos++];
    return;
  }
}

void Textifier::do_heading()
{
  if(!match(string("heading"), re_heading))
  {
    // Not really a heading. Just copy to output.
    state.out[state.pos_out++] = state.markup[state.pos++];
    return;
  }
  append_group_and_skip(2);
}

void Textifier::do_tag()
{
  do_nested(string("tag"), '<', '>');
}

void Textifier::do_meta()
{
  do_nested(string("meta"), '{', '}');
}

void Textifier::do_nowiki()
{
  if(!match(string("nowiki"), re_nowiki))
    throw get_err("nowiki");

  skip_match();
}

void Textifier::do_format()
{
  if(!match(string("format"), re_format))
    throw get_err("format");

  string* contents = &state.groups[2];
  State state_copy = state; // Save state. A call to textify() will reset it.

  // this call will write textified result directly to state.out
  textify(contents->c_str(), contents->length(),
          &state.out[state.pos_out], state.M-state.pos_out);

  // output has possibly advanced since we saved the state
  state_copy.pos_out += state.pos_out;

  // restore state
  state = state_copy;
  skip_match();
}

void Textifier::do_nested(string name, char open, char close)
{
  if(state.markup[state.pos] != open)
    throw get_err(name);

  int level = 0;
  do {
    if(state.markup[state.pos] == open)       level++;
    else if(state.markup[state.pos] == close) level--;
  } while(state.pos++ < state.N && level > 0);
}

/**
 * Converts state.markup to plain text. */
char* Textifier::textify(const char* markup, const int markup_len,
                         char* out, const int out_len)
{
  this->state.N = markup_len;
  this->state.pos = 0;
  this->state.markup = markup;
  this->state.out = out;
  this->state.M = out_len;
  this->state.pos_out = 0;

  while(state.pos < state.N && state.pos_out < state.M) {
    if(starts_with("<nowiki>"))
       do_nowiki();
    else if(starts_with("["))
      do_link();
    else if(starts_with("<"))
      do_tag();
    else if(starts_with("{{") || starts_with("{|"))
      do_meta();
    else if(starts_with("="))
      do_heading();
    else if(starts_with("''"))
      do_format();
    else {
      if(state.pos_out == 0 ||
         state.out[state.pos_out-1] != state.markup[state.pos] ||
         state.markup[state.pos] != '\n')
        out[state.pos_out++] = state.markup[state.pos++];
      else
        state.pos++;
    }
  }

  out[state.pos_out] = '\0';

  return out;
}

int main(int argc, char** argv)
{
  if(argc != 2) {
    cerr << "Usage: " << argv[0] << " input-file" << endl;
    return 1;
  }

  char* path = argv[1];
  ifstream file(path, ios::in|ios::ate);
  if(!file) {
    cerr << "The file '" << path << "' does not exist" << endl;
    return 1;
  }
  long size = file.tellg();
  char* markup = new char[size+1];

  file.seekg(0, ios::beg);
  file.read(markup, size);
  markup[size] = '\0';
  file.close();

  Textifier tf;
  const int markup_len = strlen(markup);
  char* plaintext = new char[markup_len+1];
  try {
    cout << tf.textify(markup, markup_len, plaintext, markup_len) << endl;
  }
  catch(string err) {
    long line;
    long column;
    tf.find_location(line, column);
    cerr << "ERROR (" << path << ":" << line << ":" << column << ")  " << err << endl;
    return 1;
  }
  delete plaintext;
  delete markup;
  return 0;
}
<commit_msg>fix small bugs, most notably in error reporting<commit_after>/*
 * Converts media wiki markup into plaintext
 */

#include <iostream>
#include <sstream>
#include <fstream>
#include <string.h>
#include <pcre.h>
#include <math.h>
#include <dirent.h>

using namespace std;

char* substr(char* dest, const char* src, int start, int len, int n)
{
  if(start >= n)
    throw string("Start index outside of string.");

  int actual_length = min(len, n-start);
  strncpy(dest, &src[start], actual_length);
  dest[actual_length] = '\0';
  return dest;
}

typedef struct _State
{
  int         N;          // input length
  int         pos;        // current position within input
  const char* markup;     // the markup input we're converting
  char*       out;        // output string
  int         M;          // maximum length of output without the terminating \0
  int         pos_out;    // position within output string
  string      groups[10]; // will store regexp matches
} State;

class Textifier
{
private:
  State state;

  bool starts_with(string& str);
  bool starts_with(const char* str);
  const char* get_remaining();
  char* get_current_out();
  void skip_match();
  void append_group_and_skip(int group);

  void do_link();
  void do_format();
  void do_tag();
  void do_meta();
  void do_nowiki();
  void do_heading();
  void ignore_nested(string name, char open, char close);

  bool get_link_boundaries(int& start, int& end, int& next);

  string get_err(string name);
  string* match(string name, pcre* regexp);

  pcre* make_pcre(const char* expr, int options);
  pcre* re_nowiki;
  pcre* re_format;
  pcre* re_heading;

public:
  Textifier();
  ~Textifier();
  char* textify(const char* markup, const int markup_len,
                char* out, const int out_len);

  void find_location(long& line, long& col);
  string get_snippet();
};

Textifier::Textifier()
{
  // Compile all the regexes we'll need
  re_nowiki  = make_pcre("^<nowiki>(.*?)</nowiki>", PCRE_MULTILINE | PCRE_DOTALL);
  re_format  = make_pcre("^(''+)(.*?)(\\1|\n)", 0);
  re_heading = make_pcre("^(=+)\\s*(.+?)\\s*\\1", 0);
}

Textifier::~Textifier()
{
}

pcre* Textifier::make_pcre(const char* expr, int options)
{
  const char* error;
  int erroffset;
  pcre *re = pcre_compile(expr, options, &error, &erroffset, NULL);

  if(re == NULL) {
    ostringstream os;
    os << "PCRE compilation failed at offset " << erroffset << ": "
       << error << endl;
    throw string(os.str());
  }
  return re;
}

bool Textifier::get_link_boundaries(int& start, int& end, int& next)
{
  int i = state.pos;   // current search position
  int level = 0; // nesting level
  do {
    char ch = state.markup[i];
    switch(ch) {
    case '[':
      if(level++ == 0)
        start = i+1;
      break;

    case ']':
      if(--level == 0)
        end = i;
      break;

    case '|':
      if(level == 1) { // does the pipe belong to current link or a nested one?
        start = i+1;
        end = start;
      }
      break;

    default:
      end++;
      break;
    }

    i++;
  } while(level > 0 &&
          i < state.N &&
          state.markup[i] != '\n');

  next = i;
  return level == 0; // if 0, then brackets match and this is a correct link
}

void Textifier::find_location(long& line, long& column)
{
  line = 1;
  column = 0;
  for(int i = 0; i <= state.pos && i < state.N; i++) {
    if(state.markup[i] == '\n') {
      line++;
      column = 0;
    }
    else
      column++;
  }
}

bool Textifier::starts_with(string& str)
{
  return starts_with(str.c_str());
}

bool Textifier::starts_with(const char* str)
{
  int i = state.pos;
  int j = 0;
  while(str[j] != '\0' &&
        i < state.N) {
    if(state.markup[i] != str[j])
      return false;

    i++;
    j++;
  }
  return j == strlen(str);
}

string Textifier::get_snippet()
{
  char snippet[30];
  strncpy(snippet, get_remaining(), 30);

  const int snippet_len = min(29, state.N-state.pos);
  snippet[snippet_len] = '\0';

  if(snippet_len < state.N - state.pos)
    strncpy(&snippet[snippet_len-3], "...", 3);

  return string(snippet);
}

string Textifier::get_err(string name)
{
  ostringstream os;
  os << "Expected markup type '" << name << "'";
  return os.str();
}

string* Textifier::match(string name, pcre* regexp)
{
  const int ovector_size = 3*sizeof(state.groups)/sizeof(string);
  int ovector[ovector_size];
  int rc = pcre_exec(regexp, NULL, get_remaining(), state.N-state.pos, 0, 0, ovector, ovector_size);

  if(rc == PCRE_ERROR_NOMATCH || rc == 0)
    return NULL;
  else if(rc < 0)
    throw get_err(name);

  // from pcredemo.c
  for(int i = 0; i < rc; i++) {
    const char *substring_start = get_remaining() + ovector[2*i];
    int substring_length = ovector[2*i+1] - ovector[2*i];
    char substr[substring_length+1];
    strncpy(substr, substring_start, substring_length);
    substr[substring_length]='\0';
    state.groups[i].assign(substr);
  }
  return state.groups;
}

const char* Textifier::get_remaining()
{
  return &state.markup[state.pos];
}

char* Textifier::get_current_out()
{
  return &state.out[state.pos_out];
}

void Textifier::skip_match()
{
  state.pos += state.groups[0].length();
}

void Textifier::append_group_and_skip(int group)
{
  string* val = &state.groups[group];
  strncpy(get_current_out(), val->c_str(), val->length());
  state.pos += state.groups[0].length();
  state.pos_out += val->length();
}

void Textifier::do_link()
{
  int start, end, next;
  if(get_link_boundaries(start, end, next)) {
    char contents[end-start+1];
    substr(contents, state.markup, start, end-start, state.N);
    if(strchr(contents, ':') != NULL) {
      // this is a link to the page in a different language ignore it
      state.pos = next;
    }
    else {
      State state_copy = state;
      try {
	textify(contents, end-start, &state.out[state.pos_out], state.M-state.pos_out);
      }
      catch(string error) {
	state_copy.pos = start + state.pos; // move the pointer to where recursive call failed
	state = state_copy;
	throw error;
      }
      state_copy.pos_out += state.pos_out;
      state_copy.pos = next;
      state = state_copy;
    }
  } else {
    // Apparently mediawiki allows unmatched open brackets...
    // If that's what we got, it's not a link.
    state.out[state.pos_out++] = state.markup[state.pos++];
    return;
  }
}

void Textifier::do_heading()
{
  if(!match(string("heading"), re_heading))
  {
    // Not really a heading. Just copy to output.
    state.out[state.pos_out++] = state.markup[state.pos++];
    return;
  }
  append_group_and_skip(2);
}

void Textifier::do_tag()
{
  ignore_nested(string("tag"), '<', '>');
}

void Textifier::do_meta()
{
  ignore_nested(string("meta"), '{', '}');
}

void Textifier::do_nowiki()
{
  if(!match(string("nowiki"), re_nowiki))
    throw get_err("nowiki");

  skip_match();
}

void Textifier::do_format()
{
  if(!match(string("format"), re_format))
    throw get_err("format");

  string* contents = &state.groups[2];
  State state_copy = state; // Save state. A call to textify() will reset it.

  // this call will write textified result directly to state.out
  try {
    textify(contents->c_str(), contents->length(),
	    &state.out[state.pos_out], state.M-state.pos_out);
  } catch(string error) {
    state_copy.pos += state.groups[1].size() + state.pos; // move the pointer to where recursive call failed
    state = state_copy;
    throw error;
  }

  // output has possibly advanced since we saved the state
  state_copy.pos_out += state.pos_out;

  // restore state
  state = state_copy;
  skip_match();

  // Is this a format that matches until the end of the line? If so, "unconsume"
  // the newline
  if(strcmp(state.groups[3].c_str(), "\n") == 0)
    state.pos--;
}

void Textifier::ignore_nested(string name, char open, char close)
{
  if(state.markup[state.pos] != open)
    throw get_err(name);

  int level = 0;
  do {
    if(state.markup[state.pos] == open)       level++;
    else if(state.markup[state.pos] == close) level--;
  } while(state.pos++ < state.N && level > 0);
}

/**
 * Converts state.markup to plain text. */
char* Textifier::textify(const char* markup, const int markup_len,
                         char* out, const int out_len)
{
  this->state.N = markup_len;
  this->state.pos = 0;
  this->state.markup = markup;
  this->state.out = out;
  this->state.M = out_len;
  this->state.pos_out = 0;

  while(state.pos < state.N && state.pos_out < state.M) {
    if(starts_with("<nowiki>"))
       do_nowiki();
    else if(starts_with("["))
      do_link();
    else if(starts_with("<"))
      do_tag();
    else if(starts_with("{{") || starts_with("{|"))
      do_meta();
    else if(starts_with("="))
      do_heading();
    else if(starts_with("''"))
      do_format();
    else {
      if(state.pos_out == 0 ||
         state.out[state.pos_out-1] != state.markup[state.pos] ||
         state.markup[state.pos] != '\n')
        out[state.pos_out++] = state.markup[state.pos++];
      else
        state.pos++;
    }
  }

  out[state.pos_out] = '\0';

  return out;
}

int main(int argc, char** argv)
{
  if(argc != 2) {
    cerr << "Usage: " << argv[0] << " input-file" << endl;
    return 1;
  }

  char* path = argv[1];
  ifstream file(path, ios::in|ios::ate);
  if(!file) {
    cerr << "The file '" << path << "' does not exist" << endl;
    return 1;
  }
  long size = file.tellg();
  char* markup = new char[size+1];

  file.seekg(0, ios::beg);
  file.read(markup, size);
  markup[size] = '\0';
  file.close();

  Textifier tf;
  const int markup_len = strlen(markup);
  char* plaintext = new char[markup_len+1];
  try {
    cout << tf.textify(markup, markup_len, plaintext, markup_len) << endl;
  }
  catch(string err) {
    long line;
    long column;
    tf.find_location(line, column);
    cerr << "ERROR (" << path << ":" << line << ":" << column << ")  " << err
	 << " at: " << tf.get_snippet() << endl;
    return 1;
  }
  delete plaintext;
  delete markup;
  return 0;
}
<|endoftext|>


<commit_before>// This macro displays the hits belonging to a track for selected detectors
// Input: in the tracks contains the interesting tracks
//        ntracks is the number of interesing tracks
//        The default values correspond to "Show everything"
// Note: For the moment it works only with HIJING events, the PYTHIA is
//       still not supported
//#include <ClassTable.h>

void display2 (const char *filename="galice.root",Int_t nevent=0, Int_t * tracks=0, Int_t ntracks=0) {
// Dynamically link some shared libs
   if (gClassTable->GetID("AliRun") < 0) {
      gROOT->LoadMacro("loadlibs.C");
      loadlibs();
   } else {
	  delete gAlice->GetRunLoader();
      delete gAlice;
      gAlice = 0;
   }
    //gROOT->LoadMacro("AliDisplay2.C");
   gSystem->Load("libAliL3Src");
	gSystem->Load("libDISPLAY");
// Connect the Root Galice file containing Geometry, Kine and Hits

   AliRunLoader *rl = 0x0;
   TFile *file = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
   if(file){
     cout<<"galice.root is already open \n";
   }
   rl = AliRunLoader::Open(filename,"DISPLAYED EVENT");

   if (rl == 0x0)
    {
      cerr<<"Error <display.C()>: can not get Run Loader. Exiting"<<endl;
      return;
    }

// Get AliRun object from file or create it if not on file
   rl->LoadgAlice();

   gAlice = rl->GetAliRun();
   if (!gAlice) {
    cerr<<"AliTPCHits2Digits.C : AliRun object not found on file\n";
    return;
  }

// Create Event Display object
   AliDisplay2 *edisplay = new AliDisplay2(gClient->GetRoot(), 900, 700);
//   if (ntracks>0) edisplay->SetTracksToDisplay(tracks, ntracks);

// Display the requested event
//   gAlice->GetEvent(nevent);
  rl->GetEvent(nevent);
   rl->LoadKinematics();
   rl->LoadHeader();
   rl->LoadHits();
   //	edisplay->FindModules();
   edisplay->ShowNextEvent(0);
}

<commit_msg>some cleanups so that it works out of the box.<commit_after>// This macro displays the hits belonging to a track for selected detectors
// Input: in the tracks contains the interesting tracks
//        ntracks is the number of interesing tracks
//        The default values correspond to "Show everything"
// Note: For the moment it works only with HIJING events, the PYTHIA is
//       still not supported
//#include <ClassTable.h>

void display2(const char *filename="galice.root", Int_t nevent=0,
              Int_t *tracks=0, Int_t ntracks=0)
{
   // Dynamically link some shared libs
   if (gClassTable->GetID("AliRun") < 0) {
      gROOT->LoadMacro("loadlibs.C");
      loadlibs();
   } else {
      delete gAlice->GetRunLoader();
      delete gAlice;
      gAlice = 0;
   }
   //gSystem->Load("libAliL3Src");
   gSystem->Load("libDISPLAY");

   // Connect the ROOT Galice file containing Geometry, Kine and Hits
   AliRunLoader *rl = 0;
   TFile *file = (TFile*)gROOT->GetListOfFiles()->FindObject(filename);
   if(file) {
      Info("display2.C", "galice.root is already open");
   }
   rl = AliRunLoader::Open(filename, "DISPLAYED EVENT");

   if (rl == 0) {
      Error("display2.C", "can not get Run Loader, exiting...");
      return;
   }

   // Get AliRun object from file or create it if not on file
   rl->LoadgAlice();

   gAlice = rl->GetAliRun();
   if (!gAlice) {
      Error("display2.C", "AliRun object not found on file, exiting...");
      return;
  }

   // Create Event Display object
   AliDisplay2 *edisplay = new AliDisplay2(gClient->GetRoot(), 900, 700);
   // if (ntracks > 0) edisplay->SetTracksToDisplay(tracks, ntracks);

   // Display the requested event
   rl->GetEvent(nevent);
   rl->LoadKinematics();
   rl->LoadHeader();
   rl->LoadHits();

   //edisplay->FindModules();
   edisplay->ShowNextEvent(0);
}

<|endoftext|>


<commit_before><commit_msg>Remember to tag and encode the signature.<commit_after><|endoftext|>


<commit_before>// This file is the part of the Indexer++ project.
// Copyright (C) 2016 Anna Krykora <krykoraanna@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be found in the LICENSE file.

#include "IndexManagersContainer.h"

#include <mutex>

#include "AsyncLog.h"
#include "FileInfo.h"
#include "HelperCommon.h"
#include "Log.h"
#include "OneThreadLog.h"

#include "Index.h"
#include "LetterCaseMatching.h"
#include "StatusObserver.h"
#include "TextComparison.h"

using namespace std;

IndexManagersContainer::IndexManagersContainer() {

    NEW_MUTEX

    GET_LOGGER
}

IndexManagersContainer::~IndexManagersContainer() {
    DELETE_MUTEX
}

IndexManagersContainer& IndexManagersContainer::Instance() {
    static IndexManagersContainer instance;
    return instance;
}

void IndexManagersContainer::AddDrive(char drive_letter) {

    auto drive_letter_w = wstring(1, drive_letter);

    for (const auto& mgr : index_managers_) {

        if (mgr->DriveLetter() == drive_letter) {

            logger_->Debug(METHOD_METADATA + L"Enabling index manager for drive: " + drive_letter_w);
            mgr->EnableIndex();

            OnVolumeStatusChanged(drive_letter);
            return;
        }
    }

    logger_->Debug(METHOD_METADATA + L"Adding new drive: " + drive_letter_w);

    auto new_index_mgr = make_unique<IndexManager>(drive_letter, this);

    logger_->Debug(METHOD_METADATA + L"Starting IndexManager for drive: " + drive_letter_w);
    new_index_mgr->RunAsync();

    PLOCK
    index_managers_.push_back(move(new_index_mgr));
    PUNLOCK

    OnVolumeStatusChanged(drive_letter);
}

void IndexManagersContainer::RemoveDrive(char drive_letter) {

    for (const auto& mgr : index_managers_) {

        if (mgr->DriveLetter() == drive_letter) {
            mgr->DisableIndex();
            break;
        }
    }
}

uint IndexManagersContainer::GetIndexRootID(char index_drive_letter) const {

    for (const auto& mgr : index_managers_) {

        if (mgr->DriveLetter() == index_drive_letter) return mgr->IndexRootID();
    }

    return -1;
}

// Called form IndexManager and from UI threads.
void IndexManagersContainer::OnIndexChanged(pNotifyIndexChangedEventArgs p_args) {

    for (auto& observer : index_change_observers_) {
        observer->OnIndexChanged(p_args);
    }
}

#ifdef SINGLE_THREAD
void IndexManagersContainer::CheckUpdates() {
    for (const auto& mgr : index_managers_) {
        mgr->CheckUpdates();
    }
}
#endif

// Called form IndexManager and from UI threads.
void IndexManagersContainer::OnVolumeStatusChanged(char drive_letter) {

    logger_->Debug(METHOD_METADATA + L"Loading finished for drive " + wstring(1, drive_letter));

    auto status_text = GetStatus();

    for (auto& observer : status_observers_)
        observer->StatusChanged(status_text);

    for (auto& observer : index_change_observers_)
        observer->OnVolumeStatusChanged(drive_letter);
}

void IndexManagersContainer::RegisterIndexChangeObserver(IndexChangeObserver* observer) {
    index_change_observers_.push_back(observer);
}

void IndexManagersContainer::UnregisterIndexChangeObserver(IndexChangeObserver* observer) {
    index_change_observers_.remove(observer);
}

// Called form IndexManager and from UI threads.
string IndexManagersContainer::GetStatus() const {

    string res("   ");

    PLOCK_GUARD

    for (const auto& mgr : index_managers_) {

        if (mgr->DisableIndexRequested()) continue;

        res += mgr->DriveLetter();
        res += mgr->ReadingMFTFinished() ? ": finished" : ": reading MFT";

        res += string(";  ");
    }

    logger_->Debug(METHOD_METADATA + HelperCommon::StringToWstring(res));

    return res;
}

// Called from SE thread.
vector<const IndexManager*> IndexManagersContainer::GetAllIndexManagers() const {

    vector<const IndexManager*> res;

    for (const auto& mgr : index_managers_) {
        res.push_back(mgr.get());
    }

    return res;
}

// Called from SE thread.
const IndexManager* IndexManagersContainer::GetIndexManager(char drive_letter) const {

    for (auto& mgr : index_managers_) {
        if (mgr->DriveLetter() == drive_letter) return mgr.get();
    }

    return nullptr;
}

const FileInfo* IndexManagersContainer::GetFileInfoByPath(const u16string& path) const {

    u16string delim(reinterpret_cast<const char16_t*>(L"/\\"));
    auto path_components = HelperCommon::Split(path, delim);
    const FileInfo* root = nullptr;

    auto table = GetLowerMatchTable();

    auto managers = GetAllIndexManagers();

    for (const auto* mgr : managers) {
        if (!mgr->ReadingMFTFinished() || mgr->DisableIndexRequested()) continue;

        if (table[mgr->DriveLetterW()[0]] == table[path_components[0][0]]) {
            root = mgr->GetIndex()->Root();
            break;
        }
    }

    if (root == nullptr)  // Probably disk is not loaded.
        return nullptr;

    for (int i = 0;;) {

        if (compare(root->GetName(), path_components[i].c_str(), table) == 0) {
            ++i;

            if (i == path_components.size())
				return root;

            root = root->FirstChild;
            continue;
        }

        root = root->NextSibling;

        if (!root)  // Reached the end of the search.
            return nullptr;
    }
}

void IndexManagersContainer::RegisterStatusChangeObserver(StatusObserver* observer) {
    status_observers_.push_back(observer);
}

void IndexManagersContainer::UnregisterStatusChangeObserver(StatusObserver* observer) {
    status_observers_.remove(observer);
}
<commit_msg>Added missing locks on index managers collection access in IndexManagersContainer.<commit_after>// This file is the part of the Indexer++ project.
// Copyright (C) 2016 Anna Krykora <krykoraanna@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be found in the LICENSE file.

#include "IndexManagersContainer.h"

#include <mutex>

#include "AsyncLog.h"
#include "FileInfo.h"
#include "HelperCommon.h"
#include "Log.h"
#include "OneThreadLog.h"

#include "Index.h"
#include "LetterCaseMatching.h"
#include "StatusObserver.h"
#include "TextComparison.h"

using namespace std;

IndexManagersContainer::IndexManagersContainer() {

    NEW_MUTEX

    GET_LOGGER
}

IndexManagersContainer::~IndexManagersContainer() {
    DELETE_MUTEX
}

IndexManagersContainer& IndexManagersContainer::Instance() {
    static IndexManagersContainer instance;
    return instance;
}

void IndexManagersContainer::AddDrive(char drive_letter) {

    auto drive_letter_w = wstring(1, drive_letter);

    for (const auto& mgr : index_managers_) {

        if (mgr->DriveLetter() == drive_letter) {

            logger_->Debug(METHOD_METADATA + L"Enabling index manager for drive: " + drive_letter_w);
            mgr->EnableIndex();

            OnVolumeStatusChanged(drive_letter);
            return;
        }
    }

    logger_->Debug(METHOD_METADATA + L"Adding new drive: " + drive_letter_w);

    auto new_index_mgr = make_unique<IndexManager>(drive_letter, this);

    logger_->Debug(METHOD_METADATA + L"Starting IndexManager for drive: " + drive_letter_w);
    new_index_mgr->RunAsync();

    PLOCK
    index_managers_.push_back(move(new_index_mgr));
    PUNLOCK

    OnVolumeStatusChanged(drive_letter);
}

void IndexManagersContainer::RemoveDrive(char drive_letter) {

    for (const auto& mgr : index_managers_) {

        if (mgr->DriveLetter() == drive_letter) {
            mgr->DisableIndex();
            break;
        }
    }
}

// Called from SE thread.
uint IndexManagersContainer::GetIndexRootID(char index_drive_letter) const {
    PLOCK_GUARD
    for (const auto& mgr : index_managers_) {

        if (mgr->DriveLetter() == index_drive_letter) return mgr->IndexRootID();
    }

    return -1;
}

// Called form IndexManager and from UI threads.
void IndexManagersContainer::OnIndexChanged(pNotifyIndexChangedEventArgs p_args) {

    for (auto& observer : index_change_observers_) {
        observer->OnIndexChanged(p_args);
    }
}

#ifdef SINGLE_THREAD
void IndexManagersContainer::CheckUpdates() {
    for (const auto& mgr : index_managers_) {
        mgr->CheckUpdates();
    }
}
#endif

// Called form IndexManager and from UI threads.
void IndexManagersContainer::OnVolumeStatusChanged(char drive_letter) {

    logger_->Debug(METHOD_METADATA + L"Loading finished for drive " + wstring(1, drive_letter));

    auto status_text = GetStatus();

    for (auto& observer : status_observers_)
        observer->StatusChanged(status_text);

    for (auto& observer : index_change_observers_)
        observer->OnVolumeStatusChanged(drive_letter);
}

void IndexManagersContainer::RegisterIndexChangeObserver(IndexChangeObserver* observer) {
    index_change_observers_.push_back(observer);
}

void IndexManagersContainer::UnregisterIndexChangeObserver(IndexChangeObserver* observer) {
    index_change_observers_.remove(observer);
}

// Called form IndexManager and from UI threads.
string IndexManagersContainer::GetStatus() const {

    string res("   ");

    PLOCK_GUARD

    for (const auto& mgr : index_managers_) {

        if (mgr->DisableIndexRequested()) continue;

        res += mgr->DriveLetter();
        res += mgr->ReadingMFTFinished() ? ": finished" : ": reading MFT";

        res += string(";  ");
    }

    logger_->Debug(METHOD_METADATA + HelperCommon::StringToWstring(res));

    return res;
}

// Called from UI and SE thread.
vector<const IndexManager*> IndexManagersContainer::GetAllIndexManagers() const {

    vector<const IndexManager*> res;

    PLOCK_GUARD
    for (const auto& mgr : index_managers_) {
        res.push_back(mgr.get());
    }

    return res;
}

// Called from SE thread.
const IndexManager* IndexManagersContainer::GetIndexManager(char drive_letter) const {
    PLOCK_GUARD
    for (auto& mgr : index_managers_) {
        if (mgr->DriveLetter() == drive_letter) return mgr.get();
    }

    return nullptr;
}

// Called from UI and SE threads.
const FileInfo* IndexManagersContainer::GetFileInfoByPath(const u16string& path) const {

    u16string delim(reinterpret_cast<const char16_t*>(L"/\\"));
    auto path_components = HelperCommon::Split(path, delim);
    const FileInfo* root = nullptr;

    auto table = GetLowerMatchTable();

    auto managers = GetAllIndexManagers();

    for (const auto* mgr : managers) {
        if (!mgr->ReadingMFTFinished() || mgr->DisableIndexRequested()) continue;

        if (table[mgr->DriveLetterW()[0]] == table[path_components[0][0]]) {
            root = mgr->GetIndex()->Root();
            break;
        }
    }

    if (root == nullptr)  // Probably disk is not loaded.
        return nullptr;

    for (int i = 0;;) {

        if (compare(root->GetName(), path_components[i].c_str(), table) == 0) {
            ++i;

            if (i == path_components.size())
				return root;

            root = root->FirstChild;
            continue;
        }

        root = root->NextSibling;

        if (!root)  // Reached the end of the search.
            return nullptr;
    }
}

void IndexManagersContainer::RegisterStatusChangeObserver(StatusObserver* observer) {
    status_observers_.push_back(observer);
}

void IndexManagersContainer::UnregisterStatusChangeObserver(StatusObserver* observer) {
    status_observers_.remove(observer);
}<|endoftext|>


<commit_before>// Copyright 2019 The TCMalloc Authors
//
// 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
//
//     https://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.

#include "tcmalloc/static_vars.h"

#include <stddef.h>

#include <atomic>
#include <new>

#include "absl/base/attributes.h"
#include "absl/base/const_init.h"
#include "absl/base/internal/spinlock.h"
#include "absl/base/macros.h"
#include "tcmalloc/cpu_cache.h"
#include "tcmalloc/deallocation_profiler.h"
#include "tcmalloc/internal/logging.h"
#include "tcmalloc/internal/mincore.h"
#include "tcmalloc/internal/numa.h"
#include "tcmalloc/malloc_extension.h"
#include "tcmalloc/pagemap.h"
#include "tcmalloc/sampler.h"
#include "tcmalloc/sizemap.h"
#include "tcmalloc/thread_cache.h"

GOOGLE_MALLOC_SECTION_BEGIN
namespace tcmalloc {
namespace tcmalloc_internal {

// Cacheline-align our SizeMap and CpuCache.  They both have very hot arrays as
// their first member variables, and aligning them reduces the number of cache
// lines these arrays use.
//
// IF YOU ADD TO THIS LIST, ADD TO STATIC_VAR_SIZE TOO!
// LINT.IfChange(static_vars)
ABSL_CONST_INIT absl::base_internal::SpinLock pageheap_lock(
    absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY);
ABSL_CONST_INIT Arena Static::arena_;
ABSL_CONST_INIT SizeMap ABSL_CACHELINE_ALIGNED Static::sizemap_;
TCMALLOC_ATTRIBUTE_NO_DESTROY ABSL_CONST_INIT TransferCacheManager
    Static::transfer_cache_;
ABSL_CONST_INIT ShardedTransferCacheManager
    Static::sharded_transfer_cache_(nullptr, nullptr);
ABSL_CONST_INIT CpuCache ABSL_CACHELINE_ALIGNED Static::cpu_cache_;
ABSL_CONST_INIT SampledAllocationAllocator Static::sampledallocation_allocator_;
ABSL_CONST_INIT PageHeapAllocator<Span> Static::span_allocator_;
ABSL_CONST_INIT PageHeapAllocator<ThreadCache> Static::threadcache_allocator_;
ABSL_CONST_INIT ExplicitlyConstructed<SampledAllocationRecorder>
    Static::sampled_allocation_recorder_;
ABSL_CONST_INIT tcmalloc_internal::StatsCounter Static::sampled_objects_size_;
ABSL_CONST_INIT tcmalloc_internal::StatsCounter
    Static::sampled_internal_fragmentation_;
ABSL_CONST_INIT AllocationSampleList Static::allocation_samples;
ABSL_CONST_INIT deallocationz::DeallocationProfilerList
    Static::deallocation_samples;
ABSL_CONST_INIT std::atomic<AllocHandle> Static::sampled_alloc_handle_generator{
    0};
ABSL_CONST_INIT PeakHeapTracker Static::peak_heap_tracker_;
ABSL_CONST_INIT PageHeapAllocator<StackTraceTable::Bucket>
    Static::bucket_allocator_;
ABSL_CONST_INIT std::atomic<bool> Static::inited_{false};
ABSL_CONST_INIT std::atomic<bool> Static::cpu_cache_active_{false};
ABSL_CONST_INIT Static::PageAllocatorStorage Static::page_allocator_;
ABSL_CONST_INIT PageMap Static::pagemap_;
ABSL_CONST_INIT GuardedPageAllocator Static::guardedpage_allocator_;
ABSL_CONST_INIT NumaTopology<kNumaPartitions, kNumBaseClasses>
    Static::numa_topology_;
// LINT.ThenChange(:static_vars_size)

ABSL_CONST_INIT Static tc_globals;

size_t Static::metadata_bytes() {
  // This is ugly and doesn't nicely account for e.g. alignment losses
  // -- I'd like to put all the above in a struct and take that
  // struct's size.  But we can't due to linking issues.
  //
  // TODO(b/242550501):  Progress on constant initialization guarantees allow
  // state to be consolidated directly into an instance, rather than as a
  // collection of static variables.  Simplify this.
  // LINT.IfChange(static_vars_size)
  const size_t static_var_size =
      sizeof(pageheap_lock) + sizeof(arena_) + sizeof(sizemap_) +
      sizeof(sharded_transfer_cache_) + sizeof(transfer_cache_) +
      sizeof(cpu_cache_) + sizeof(sampledallocation_allocator_) +
      sizeof(span_allocator_) + +sizeof(threadcache_allocator_) +
      sizeof(sampled_allocation_recorder_) + sizeof(bucket_allocator_) +
      sizeof(inited_) + sizeof(cpu_cache_active_) + sizeof(page_allocator_) +
      sizeof(pagemap_) + sizeof(sampled_objects_size_) +
      sizeof(sampled_internal_fragmentation_) +
      sizeof(allocation_samples) +
      sizeof(deallocation_samples) +
      sizeof(sampled_alloc_handle_generator) + sizeof(peak_heap_tracker_) +
      sizeof(guardedpage_allocator_) + sizeof(numa_topology_);
  // LINT.ThenChange(:static_vars)

  const size_t allocated = arena().stats().bytes_allocated +
                           AddressRegionFactory::InternalBytesAllocated();
  return allocated + static_var_size;
}

size_t Static::pagemap_residence() {
  // Determine residence of the root node of the pagemap.
  size_t total = MInCore::residence(&pagemap_, sizeof(pagemap_));
  return total;
}

int ABSL_ATTRIBUTE_WEAK default_want_legacy_size_classes();

ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE void Static::SlowInitIfNecessary() {
  absl::base_internal::SpinLockHolder h(&pageheap_lock);

  // double-checked locking
  if (!inited_.load(std::memory_order_acquire)) {
    absl::Span<const SizeClassInfo> size_classes;

    if (IsExperimentActive(Experiment::TEST_ONLY_TCMALLOC_POW2_SIZECLASS)) {
      size_classes = kExperimentalPow2SizeClasses;
    } else if (default_want_legacy_size_classes != nullptr &&
               default_want_legacy_size_classes() > 0) {
      // TODO(b/196216678): remove this opt out after 2022-11-01.
      size_classes = kLegacySizeClasses;
    } else {
      size_classes = kSizeClasses;
    }

    CHECK_CONDITION(sizemap_.Init(size_classes));
    numa_topology_.Init();
    sampledallocation_allocator_.Init(&arena_);
    sampled_allocation_recorder_.Construct(&sampledallocation_allocator_);
    sampled_allocation_recorder().Init();
    peak_heap_tracker_.Init(&arena_);
    span_allocator_.Init(&arena_);
    span_allocator_.New();  // Reduce cache conflicts
    span_allocator_.New();  // Reduce cache conflicts
    bucket_allocator_.Init(&arena_);
    // Do a bit of sanitizing: make sure central_cache is aligned properly
    CHECK_CONDITION((sizeof(transfer_cache_) % ABSL_CACHELINE_SIZE) == 0);
    transfer_cache_.Init();
    if (IsExperimentActive(
            Experiment::TEST_ONLY_TCMALLOC_SHARDED_TRANSFER_CACHE) ||
        IsExperimentActive(
            Experiment::TEST_ONLY_TCMALLOC_GENERIC_SHARDED_TRANSFER_CACHE)) {
      // The constructor of the sharded transfer cache leaves it in a disabled
      // state.
      sharded_transfer_cache_.Init();
    }
    new (page_allocator_.memory) PageAllocator;
    threadcache_allocator_.Init(&arena_);
    pagemap_.MapRootWithSmallPages();
    guardedpage_allocator_.Init(/*max_alloced_pages=*/64, /*total_pages=*/128);
    inited_.store(true, std::memory_order_release);
  }
}

}  // namespace tcmalloc_internal
}  // namespace tcmalloc
GOOGLE_MALLOC_SECTION_END
<commit_msg>Update a TODO.<commit_after>// Copyright 2019 The TCMalloc Authors
//
// 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
//
//     https://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.

#include "tcmalloc/static_vars.h"

#include <stddef.h>

#include <atomic>
#include <new>

#include "absl/base/attributes.h"
#include "absl/base/const_init.h"
#include "absl/base/internal/spinlock.h"
#include "absl/base/macros.h"
#include "tcmalloc/cpu_cache.h"
#include "tcmalloc/deallocation_profiler.h"
#include "tcmalloc/internal/logging.h"
#include "tcmalloc/internal/mincore.h"
#include "tcmalloc/internal/numa.h"
#include "tcmalloc/malloc_extension.h"
#include "tcmalloc/pagemap.h"
#include "tcmalloc/sampler.h"
#include "tcmalloc/sizemap.h"
#include "tcmalloc/thread_cache.h"

GOOGLE_MALLOC_SECTION_BEGIN
namespace tcmalloc {
namespace tcmalloc_internal {

// Cacheline-align our SizeMap and CpuCache.  They both have very hot arrays as
// their first member variables, and aligning them reduces the number of cache
// lines these arrays use.
//
// IF YOU ADD TO THIS LIST, ADD TO STATIC_VAR_SIZE TOO!
// LINT.IfChange(static_vars)
ABSL_CONST_INIT absl::base_internal::SpinLock pageheap_lock(
    absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY);
ABSL_CONST_INIT Arena Static::arena_;
ABSL_CONST_INIT SizeMap ABSL_CACHELINE_ALIGNED Static::sizemap_;
TCMALLOC_ATTRIBUTE_NO_DESTROY ABSL_CONST_INIT TransferCacheManager
    Static::transfer_cache_;
ABSL_CONST_INIT ShardedTransferCacheManager
    Static::sharded_transfer_cache_(nullptr, nullptr);
ABSL_CONST_INIT CpuCache ABSL_CACHELINE_ALIGNED Static::cpu_cache_;
ABSL_CONST_INIT SampledAllocationAllocator Static::sampledallocation_allocator_;
ABSL_CONST_INIT PageHeapAllocator<Span> Static::span_allocator_;
ABSL_CONST_INIT PageHeapAllocator<ThreadCache> Static::threadcache_allocator_;
ABSL_CONST_INIT ExplicitlyConstructed<SampledAllocationRecorder>
    Static::sampled_allocation_recorder_;
ABSL_CONST_INIT tcmalloc_internal::StatsCounter Static::sampled_objects_size_;
ABSL_CONST_INIT tcmalloc_internal::StatsCounter
    Static::sampled_internal_fragmentation_;
ABSL_CONST_INIT AllocationSampleList Static::allocation_samples;
ABSL_CONST_INIT deallocationz::DeallocationProfilerList
    Static::deallocation_samples;
ABSL_CONST_INIT std::atomic<AllocHandle> Static::sampled_alloc_handle_generator{
    0};
ABSL_CONST_INIT PeakHeapTracker Static::peak_heap_tracker_;
ABSL_CONST_INIT PageHeapAllocator<StackTraceTable::Bucket>
    Static::bucket_allocator_;
ABSL_CONST_INIT std::atomic<bool> Static::inited_{false};
ABSL_CONST_INIT std::atomic<bool> Static::cpu_cache_active_{false};
ABSL_CONST_INIT Static::PageAllocatorStorage Static::page_allocator_;
ABSL_CONST_INIT PageMap Static::pagemap_;
ABSL_CONST_INIT GuardedPageAllocator Static::guardedpage_allocator_;
ABSL_CONST_INIT NumaTopology<kNumaPartitions, kNumBaseClasses>
    Static::numa_topology_;
// LINT.ThenChange(:static_vars_size)

ABSL_CONST_INIT Static tc_globals;

size_t Static::metadata_bytes() {
  // This is ugly and doesn't nicely account for e.g. alignment losses
  // -- I'd like to put all the above in a struct and take that
  // struct's size.  But we can't due to linking issues.
  //
  // TODO(b/242550501):  Progress on constant initialization guarantees allow
  // state to be consolidated directly into an instance, rather than as a
  // collection of static variables.  Simplify this.
  // LINT.IfChange(static_vars_size)
  const size_t static_var_size =
      sizeof(pageheap_lock) + sizeof(arena_) + sizeof(sizemap_) +
      sizeof(sharded_transfer_cache_) + sizeof(transfer_cache_) +
      sizeof(cpu_cache_) + sizeof(sampledallocation_allocator_) +
      sizeof(span_allocator_) + +sizeof(threadcache_allocator_) +
      sizeof(sampled_allocation_recorder_) + sizeof(bucket_allocator_) +
      sizeof(inited_) + sizeof(cpu_cache_active_) + sizeof(page_allocator_) +
      sizeof(pagemap_) + sizeof(sampled_objects_size_) +
      sizeof(sampled_internal_fragmentation_) +
      sizeof(allocation_samples) +
      sizeof(deallocation_samples) +
      sizeof(sampled_alloc_handle_generator) + sizeof(peak_heap_tracker_) +
      sizeof(guardedpage_allocator_) + sizeof(numa_topology_);
  // LINT.ThenChange(:static_vars)

  const size_t allocated = arena().stats().bytes_allocated +
                           AddressRegionFactory::InternalBytesAllocated();
  return allocated + static_var_size;
}

size_t Static::pagemap_residence() {
  // Determine residence of the root node of the pagemap.
  size_t total = MInCore::residence(&pagemap_, sizeof(pagemap_));
  return total;
}

int ABSL_ATTRIBUTE_WEAK default_want_legacy_size_classes();

ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE void Static::SlowInitIfNecessary() {
  absl::base_internal::SpinLockHolder h(&pageheap_lock);

  // double-checked locking
  if (!inited_.load(std::memory_order_acquire)) {
    absl::Span<const SizeClassInfo> size_classes;

    if (IsExperimentActive(Experiment::TEST_ONLY_TCMALLOC_POW2_SIZECLASS)) {
      size_classes = kExperimentalPow2SizeClasses;
    } else if (default_want_legacy_size_classes != nullptr &&
               default_want_legacy_size_classes() > 0) {
      // TODO(b/242710633): remove this opt out.
      size_classes = kLegacySizeClasses;
    } else {
      size_classes = kSizeClasses;
    }

    CHECK_CONDITION(sizemap_.Init(size_classes));
    numa_topology_.Init();
    sampledallocation_allocator_.Init(&arena_);
    sampled_allocation_recorder_.Construct(&sampledallocation_allocator_);
    sampled_allocation_recorder().Init();
    peak_heap_tracker_.Init(&arena_);
    span_allocator_.Init(&arena_);
    span_allocator_.New();  // Reduce cache conflicts
    span_allocator_.New();  // Reduce cache conflicts
    bucket_allocator_.Init(&arena_);
    // Do a bit of sanitizing: make sure central_cache is aligned properly
    CHECK_CONDITION((sizeof(transfer_cache_) % ABSL_CACHELINE_SIZE) == 0);
    transfer_cache_.Init();
    if (IsExperimentActive(
            Experiment::TEST_ONLY_TCMALLOC_SHARDED_TRANSFER_CACHE) ||
        IsExperimentActive(
            Experiment::TEST_ONLY_TCMALLOC_GENERIC_SHARDED_TRANSFER_CACHE)) {
      // The constructor of the sharded transfer cache leaves it in a disabled
      // state.
      sharded_transfer_cache_.Init();
    }
    new (page_allocator_.memory) PageAllocator;
    threadcache_allocator_.Init(&arena_);
    pagemap_.MapRootWithSmallPages();
    guardedpage_allocator_.Init(/*max_alloced_pages=*/64, /*total_pages=*/128);
    inited_.store(true, std::memory_order_release);
  }
}

}  // namespace tcmalloc_internal
}  // namespace tcmalloc
GOOGLE_MALLOC_SECTION_END
<|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS eforms4 (1.22.22); FILE MERGED 2004/12/06 09:30:35 mbu 1.22.22.1: OXFormsDescriptor handling added<commit_after><|endoftext|>


<commit_before><commit_msg>Fix shutdown during onAccept (#3267)<commit_after><|endoftext|>


<commit_before>///
/// @file   Li.cpp
/// @brief  Test the offset logarithmic integral function.
///         Li(x) = li(x) - li(2)
///
/// Copyright (C) 2019 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount-internal.hpp>
#include <imath.hpp>

#include <stdint.h>
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <vector>

using namespace std;
using namespace primecount;

vector<int64_t> Li_table =
{
                     5, // Li(10^1)
                    29, // Li(10^2)
                   176, // Li(10^3)
                  1245, // Li(10^4)
                  9628, // Li(10^5)
                 78626, // Li(10^6)
                664917, // Li(10^7)
               5762208, // Li(10^8)
              50849233, // Li(10^9)
             455055613, // Li(10^10)
          4118066399ll, // Li(10^11)
         37607950279ll, // Li(10^12)
        346065645809ll, // Li(10^13)
       3204942065690ll, // Li(10^14)
      29844571475286ll  // Li(10^15)
};

void check(bool OK)
{
  cout << "   " << (OK ? "OK" : "ERROR") << "\n";
  if (!OK)
    exit(1);
}

int main()
{
  for (size_t i = 0; i < Li_table.size(); i++)
  {
    int p = (int) i + 1;
    int64_t x = ipow(10ll, p);
    cout << "Li(" << x << ") = " << Li(x);
    check(Li(x) == Li_table[i]);
  }

  for (size_t i = 0; i < Li_table.size(); i++)
  {
    int p = (int) i + 1;
    int64_t x = ipow(10ll, p);
    cout << "Li_inverse(" << Li_table[i] << ") = " << Li_inverse(Li_table[i]);
    check(Li_inverse(Li_table[i]) <= x &&
          Li_inverse(Li_table[i] + 1) > x);
  }

  // Sanity checks for small values of Li(x)
  for (int64_t x = 0; x < 1000000; x++)
  {
    int64_t lix = Li(x);
    double logx = log(max((double) x, 2.0));

    if (lix < 0 ||
        (x >= 11 && lix < x / logx) ||
        (x >= 2  && lix > x * logx))
    {
      cout << "Li(" << x << ") = " << lix << "   ERROR" << endl;
      exit(1);
    }
  }

  // Sanity checks for small values of Li_inverse(x)
  for (int64_t x = 2; x < 100000; x++)
  {
    int64_t res = Li_inverse(x);
    double logx = log((double) x);

    if (res < 0 ||
        res < x ||
        (x >= 4 && res > x * logx * logx))
    {
      cout << "Li_inverse(" << x << ") = " << res << "   ERROR" << endl;
      exit(1);
    }
  }

  cout << endl;
  cout << "All tests passed successfully!" << endl;

  return 0;
}
<commit_msg>Speed up slow test<commit_after>///
/// @file   Li.cpp
/// @brief  Test the offset logarithmic integral function.
///         Li(x) = li(x) - li(2)
///
/// Copyright (C) 2021 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount-internal.hpp>
#include <imath.hpp>

#include <stdint.h>
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <vector>

using namespace std;
using namespace primecount;

vector<int64_t> Li_table =
{
                     5, // Li(10^1)
                    29, // Li(10^2)
                   176, // Li(10^3)
                  1245, // Li(10^4)
                  9628, // Li(10^5)
                 78626, // Li(10^6)
                664917, // Li(10^7)
               5762208, // Li(10^8)
              50849233, // Li(10^9)
             455055613, // Li(10^10)
          4118066399ll, // Li(10^11)
         37607950279ll, // Li(10^12)
        346065645809ll, // Li(10^13)
       3204942065690ll, // Li(10^14)
      29844571475286ll  // Li(10^15)
};

void check(bool OK)
{
  cout << "   " << (OK ? "OK" : "ERROR") << "\n";
  if (!OK)
    exit(1);
}

int main()
{
  for (size_t i = 0; i < Li_table.size(); i++)
  {
    int p = (int) i + 1;
    int64_t x = ipow(10ll, p);
    cout << "Li(" << x << ") = " << Li(x);
    check(Li(x) == Li_table[i]);
  }

  for (size_t i = 0; i < Li_table.size(); i++)
  {
    int p = (int) i + 1;
    int64_t x = ipow(10ll, p);
    cout << "Li_inverse(" << Li_table[i] << ") = " << Li_inverse(Li_table[i]);
    check(Li_inverse(Li_table[i]) <= x &&
          Li_inverse(Li_table[i] + 1) > x);
  }

  // Sanity checks for small values of Li(x)
  for (int64_t x = 0; x < 300000; x++)
  {
    int64_t lix = Li(x);
    double logx = log(max((double) x, 2.0));

    if (lix < 0 ||
        (x >= 11 && lix < x / logx) ||
        (x >= 2  && lix > x * logx))
    {
      cout << "Li(" << x << ") = " << lix << "   ERROR" << endl;
      exit(1);
    }
  }

  // Sanity checks for small values of Li_inverse(x)
  for (int64_t x = 2; x < 30000; x++)
  {
    int64_t res = Li_inverse(x);
    double logx = log((double) x);

    if (res < 0 ||
        res < x ||
        (x >= 4 && res > x * logx * logx))
    {
      cout << "Li_inverse(" << x << ") = " << res << "   ERROR" << endl;
      exit(1);
    }
  }

  cout << endl;
  cout << "All tests passed successfully!" << endl;

  return 0;
}
<|endoftext|>


<commit_before>// ------------------------------------------------------------------
// pion-platform: a C++ framework for building lightweight HTTP interfaces
// ------------------------------------------------------------------
// Copyright (C) 2007 Atomic Labs, Inc.  (http://www.atomiclabs.com)
//
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file COPYING or copy at http://www.boost.org/LICENSE_1_0.txt
//

#ifndef _MSC_VER
	#include <fcntl.h>
	#include <unistd.h>
	#include <sys/stat.h>
#endif

#ifdef _MSC_VER
	#include <windows.h>
	#include <direct.h>
#endif

// mlockall support on LINUX
#ifndef _MSC_VER
	#include <sys/mman.h>
	#include <string.h>
#endif

#include <pion/PionConfig.hpp>

#ifdef PION_HAVE_SSL
	#include <openssl/ssl.h>
//#ifdef _MSC_VER
//	#include <openssl/applink.c>
//#endif
#endif

#ifndef SYSCONFDIR
	#define SYSCONFDIR "/usr/local/etc"
#endif

#include <iostream>
#include <boost/filesystem/operations.hpp>
#include "PlatformConfig.hpp"
#include "../../net/utils/ShutdownManager.hpp"

using namespace std;
using namespace pion;
using namespace pion::net;
using namespace pion::platform;
using namespace pion::server;

// some forward declarations of functions used
void daemonize_server(void);
void argument_error(void);
int run(bool run_as_daemon, bool lock_memory, const std::string& platform_config_file);

int parse_args(int argc, char *argv[], bool& run_as_daemon, bool& lock_memory, std::string& platform_config_file)
{
	// get platform config file
	run_as_daemon = false;
	lock_memory = false;

#ifdef _MSC_VER
	platform_config_file = "config\\platform.xml";
#else
	platform_config_file = "/etc/pion/platform.xml";
	if (! boost::filesystem::exists(platform_config_file) )
		platform_config_file = std::string(SYSCONFDIR) + "/pion/platform.xml";
#endif

	for (int argnum=1; argnum < argc; ++argnum) {
		if (argv[argnum][0] == '-') {
			if (argv[argnum][1] == 'D') {
				run_as_daemon = true;
			} else if (argv[argnum][1] == 'M') {
				lock_memory = true;
			} else if (argv[argnum][1] == 'c' && argv[argnum][2] == '\0' && argnum+1 < argc) {
				platform_config_file = boost::filesystem::system_complete(argv[++argnum]).normalize().file_string();
			} else if (strncmp(argv[argnum], "--version", 9) == 0) {
				std::cout << "pion version " << PION_VERSION << std::endl;
				return 1;
			} else {
				argument_error();
				return 1;
			}
		} else {
			argument_error();
			return 1;
		}
	}

	return 0;
}

/// Windows Service stuff
#ifdef _MSC_VER
#define SVCNAME TEXT("Pion")

/// store command line parameters to pass between main() and SvcMain
bool					g_lock_memory = false;
std::string				g_platform_config_file;

/// Windows Service status and handle
SERVICE_STATUS          gSvcStatus;
SERVICE_STATUS_HANDLE   gSvcStatusHandle;

/// reports serive status to the Service Control Manager (uses gSvcStatusHandle)
void report_service_status( DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint );

/// serivce control handler - we only support Stop request
void WINAPI service_control_handler( DWORD dwCtrl )
{
	// Handle the requested control code.
	switch(dwCtrl) {
	case SERVICE_CONTROL_STOP:
	case SERVICE_CONTROL_SHUTDOWN:
		report_service_status(SERVICE_STOP_PENDING, NO_ERROR, 0);
		// Signal the Pion to shutdown.
		main_shutdown_manager.shutdown();
		return;

	case SERVICE_CONTROL_INTERROGATE:
		// Fall through to send current status.
		break;

	default:
		break;
	}

   report_service_status(gSvcStatus.dwCurrentState, NO_ERROR, 0);
}

void report_service_status( DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint )
{
    static DWORD dwCheckPoint = 1;

    // Fill in the SERVICE_STATUS structure.
    gSvcStatus.dwCurrentState = dwCurrentState;
    gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
    gSvcStatus.dwWaitHint = dwWaitHint;

    if (dwCurrentState == SERVICE_START_PENDING)
        gSvcStatus.dwControlsAccepted = 0;
    else
		gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;

    if ( (dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED) )
        gSvcStatus.dwCheckPoint = 0;
    else
		gSvcStatus.dwCheckPoint = dwCheckPoint++;

    // Report the status of the service to the SCM.
    SetServiceStatus( gSvcStatusHandle, &gSvcStatus );
}

void service_report_event(LPTSTR szFunction)
{
	//TODO
}

void WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv )
{
    // Register the handler function for the service
    gSvcStatusHandle = RegisterServiceCtrlHandler( SVCNAME, service_control_handler );

    if( !gSvcStatusHandle ){
		PION_ASSERT( gSvcStatusHandle );
        service_report_event(TEXT("RegisterServiceCtrlHandler"));
        return;
    }

    // These SERVICE_STATUS members remain as set here
    gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    gSvcStatus.dwServiceSpecificExitCode = 0;

    // Report initial status to the SCM
    report_service_status( SERVICE_START_PENDING, NO_ERROR, 3000 );

	bool run_as_daemon = false;
	bool lock_memory = false;

#ifdef _MSC_VER
	std::string platform_config_file("config\\platform.xml");
#else
	std::string platform_config_file("/etc/pion/platform.xml");
#endif

	run( true, g_lock_memory, g_platform_config_file );

	report_service_status( SERVICE_STOPPED, NO_ERROR, 0 );
}
#endif

/// main control function
int main (int argc, char *argv[])
{
	bool run_as_daemon = false;
	bool lock_memory = false;

#ifdef _MSC_VER
	std::string platform_config_file("config\\platform.xml");
#else
	std::string platform_config_file("/etc/pion/platform.xml");
#endif

	if(parse_args(argc, argv, run_as_daemon, lock_memory, platform_config_file) != 0)
		return 1;

#ifdef _MSC_VER
	if(run_as_daemon) {
		// running as Windows Service
		// initialize the global variables to be used by SrvMain
		g_platform_config_file = platform_config_file;
		g_lock_memory = lock_memory;

		SERVICE_TABLE_ENTRY DispatchTable[] =
		{
			{ SVCNAME, (LPSERVICE_MAIN_FUNCTION) SvcMain },
			{ NULL, NULL }
		};
		// this call returns when the service has stopped.
		// the process should simply terminate when the call returns.
		if (!StartServiceCtrlDispatcher( DispatchTable )) {
			service_report_event(("StartServiceCtrlDispatcher"));
		}
		return 0;
	}
#endif
	return run(run_as_daemon, lock_memory, platform_config_file);
}

int run (bool run_as_daemon, bool lock_memory, const std::string& platform_config_file)
{
	// initialize log system (use simple configuration)
	PionLogger pion_log(PION_GET_LOGGER("pion"));

	// This level might be overridden if there is a LogConfig file specified in the platform
	// configuration (and if using a logging library that supports logging configuration.)
	PION_LOG_SETLEVEL_INFO(pion_log);
	PION_LOG_CONFIG_BASIC;

	// get logger for main() process
	PionLogger pion_main_log(PION_GET_LOGGER("pion.main"));

	/// become a daemon if the -D option is given
	if (run_as_daemon)
		daemonize_server();

	// setup signal handler
#ifdef _MSC_VER
	SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
#else
	signal(SIGPIPE, SIG_IGN);
	signal(SIGCHLD, SIG_IGN);
	signal(SIGTSTP, SIG_IGN);
	signal(SIGTTOU, SIG_IGN);
	signal(SIGTTIN, SIG_IGN);
	signal(SIGHUP, SIG_IGN);
	signal(SIGINT, handle_signal);
	signal(SIGTERM, handle_signal);
#endif

#ifdef PION_HAVE_SSL
	// initialize the OpenSSL library
	CRYPTO_malloc_init();
	SSL_library_init();
#endif

#ifndef _MSC_VER
	if (lock_memory)
		if (mlockall(MCL_CURRENT | MCL_FUTURE))
			PION_LOG_FATAL(pion_main_log, "Failed to lock memory: " << strerror(errno));
#endif

	// PlatformConfig destructor can throw exceptions, make sure we handle them
	try	{
		PlatformConfig platform_cfg;
		try {
			// load the platform configuration
			platform_cfg.setConfigFile(platform_config_file);
			platform_cfg.openConfigFile();

			PION_LOG_INFO(pion_main_log, "Pion has started successfully (v" << PION_VERSION << ')');
#ifdef _MSC_VER
			if(run_as_daemon)
				report_service_status( SERVICE_RUNNING, NO_ERROR, 0 );
#endif
			// wait for shutdown
			main_shutdown_manager.wait();
		} catch (std::exception& e) {
			PION_LOG_FATAL(pion_main_log, e.what());
		}

		PION_LOG_INFO(pion_main_log, "Pion is shutting down");
	} catch (std::exception& e) {
		PION_LOG_FATAL(pion_main_log, e.what());
	}
	return 0;
}

#ifdef _MSC_VER
/// run server as Windows service
void daemonize_server(void)
{
    gSvcStatusHandle = RegisterServiceCtrlHandler( SVCNAME, service_control_handler );
    if( !gSvcStatusHandle )
    {
        service_report_event(TEXT("RegisterServiceCtrlHandler"));
        return;
    }

    // These SERVICE_STATUS members remain as set here
    gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    gSvcStatus.dwServiceSpecificExitCode = 0;

    // Report initial status to the SCM
    report_service_status( SERVICE_START_PENDING, NO_ERROR, 20000 );

	// Windows tends to start the service in C:\windows\system32 folder
	// We need to change it to Pion's installation dir for Pion to work
	char exe_path[MAX_PATH];
	exe_path[0]=0;
	if( GetModuleFileName(NULL, exe_path, sizeof(exe_path)/sizeof(exe_path[0])) ) {
		char exe_dir[MAX_PATH], drive[MAX_PATH], filename[MAX_PATH];
		exe_dir[0]=0; drive[0] = 0; filename[0]=0;
		_splitpath( exe_path, drive, exe_dir, filename, NULL);
		SetCurrentDirectory( exe_dir );
	}
}
#else
/// run server as a daemon (Unix)
void daemonize_server(void)
{
	// adopted from "Unix Daemon Server Programming"
	// http://www.enderunix.org/docs/eng/daemon.php

	// return early if already running as a daemon
	if(getppid()==1) return;

	// for out the process
	int i = fork();
	if (i<0) exit(1);	// error forking
	if (i>0) exit(0);	// exit if parent

	// child (daemon process) continues here after the fork...

	// obtain a new process group
	setsid();

	// close all descriptors
	for (i=getdtablesize();i>=0;--i) close(i);

	// bind stdio to /dev/null
	i=open("/dev/null",O_RDWR); dup(i); dup(i);

	// restrict file creation mode to 0750
	umask(027);
}
#endif

/// displays an error message if the arguments are invalid
void argument_error(void)
{
	std::cerr << "usage:   pion [-c PLATFORM_XML_FILE] [-D] [-M]" << std::endl;
}
<commit_msg>Add static link declarations to pion main.cpp<commit_after>// ------------------------------------------------------------------
// pion-platform: a C++ framework for building lightweight HTTP interfaces
// ------------------------------------------------------------------
// Copyright (C) 2007 Atomic Labs, Inc.  (http://www.atomiclabs.com)
//
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file COPYING or copy at http://www.boost.org/LICENSE_1_0.txt
//

#ifndef _MSC_VER
	#include <fcntl.h>
	#include <unistd.h>
	#include <sys/stat.h>
#endif

#ifdef _MSC_VER
	#include <windows.h>
	#include <direct.h>
#endif

// mlockall support on LINUX
#ifndef _MSC_VER
	#include <sys/mman.h>
	#include <string.h>
#endif

#include <pion/PionConfig.hpp>

#ifdef PION_HAVE_SSL
	#include <openssl/ssl.h>
//#ifdef _MSC_VER
//	#include <openssl/applink.c>
//#endif
#endif

#ifndef SYSCONFDIR
	#define SYSCONFDIR "/usr/local/etc"
#endif

#include <iostream>
#include <boost/filesystem/operations.hpp>
#include "PlatformConfig.hpp"
#include "../../net/utils/ShutdownManager.hpp"

#ifdef PION_STATIC_LINKING
	#include <pion/PionPlugin.hpp>
	PION_DECLARE_PLUGIN(FileService)
	PION_DECLARE_PLUGIN(HTTPProtocol)
	PION_DECLARE_PLUGIN(SnifferReactor)
#endif

using namespace std;
using namespace pion;
using namespace pion::net;
using namespace pion::platform;
using namespace pion::server;

// some forward declarations of functions used
void daemonize_server(void);
void argument_error(void);
int run(bool run_as_daemon, bool lock_memory, const std::string& platform_config_file);

int parse_args(int argc, char *argv[], bool& run_as_daemon, bool& lock_memory, std::string& platform_config_file)
{
	// get platform config file
	run_as_daemon = false;
	lock_memory = false;

#ifdef _MSC_VER
	platform_config_file = "config\\platform.xml";
#else
	platform_config_file = "/etc/pion/platform.xml";
	if (! boost::filesystem::exists(platform_config_file) )
		platform_config_file = std::string(SYSCONFDIR) + "/pion/platform.xml";
#endif

	for (int argnum=1; argnum < argc; ++argnum) {
		if (argv[argnum][0] == '-') {
			if (argv[argnum][1] == 'D') {
				run_as_daemon = true;
			} else if (argv[argnum][1] == 'M') {
				lock_memory = true;
			} else if (argv[argnum][1] == 'c' && argv[argnum][2] == '\0' && argnum+1 < argc) {
				platform_config_file = boost::filesystem::system_complete(argv[++argnum]).normalize().file_string();
			} else if (strncmp(argv[argnum], "--version", 9) == 0) {
				std::cout << "pion version " << PION_VERSION << std::endl;
				return 1;
			} else {
				argument_error();
				return 1;
			}
		} else {
			argument_error();
			return 1;
		}
	}

	return 0;
}

/// Windows Service stuff
#ifdef _MSC_VER
#define SVCNAME TEXT("Pion")

/// store command line parameters to pass between main() and SvcMain
bool					g_lock_memory = false;
std::string				g_platform_config_file;

/// Windows Service status and handle
SERVICE_STATUS          gSvcStatus;
SERVICE_STATUS_HANDLE   gSvcStatusHandle;

/// reports serive status to the Service Control Manager (uses gSvcStatusHandle)
void report_service_status( DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint );

/// serivce control handler - we only support Stop request
void WINAPI service_control_handler( DWORD dwCtrl )
{
	// Handle the requested control code.
	switch(dwCtrl) {
	case SERVICE_CONTROL_STOP:
	case SERVICE_CONTROL_SHUTDOWN:
		report_service_status(SERVICE_STOP_PENDING, NO_ERROR, 0);
		// Signal the Pion to shutdown.
		main_shutdown_manager.shutdown();
		return;

	case SERVICE_CONTROL_INTERROGATE:
		// Fall through to send current status.
		break;

	default:
		break;
	}

   report_service_status(gSvcStatus.dwCurrentState, NO_ERROR, 0);
}

void report_service_status( DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint )
{
    static DWORD dwCheckPoint = 1;

    // Fill in the SERVICE_STATUS structure.
    gSvcStatus.dwCurrentState = dwCurrentState;
    gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
    gSvcStatus.dwWaitHint = dwWaitHint;

    if (dwCurrentState == SERVICE_START_PENDING)
        gSvcStatus.dwControlsAccepted = 0;
    else
		gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;

    if ( (dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED) )
        gSvcStatus.dwCheckPoint = 0;
    else
		gSvcStatus.dwCheckPoint = dwCheckPoint++;

    // Report the status of the service to the SCM.
    SetServiceStatus( gSvcStatusHandle, &gSvcStatus );
}

void service_report_event(LPTSTR szFunction)
{
	//TODO
}

void WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv )
{
    // Register the handler function for the service
    gSvcStatusHandle = RegisterServiceCtrlHandler( SVCNAME, service_control_handler );

    if( !gSvcStatusHandle ){
		PION_ASSERT( gSvcStatusHandle );
        service_report_event(TEXT("RegisterServiceCtrlHandler"));
        return;
    }

    // These SERVICE_STATUS members remain as set here
    gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    gSvcStatus.dwServiceSpecificExitCode = 0;

    // Report initial status to the SCM
    report_service_status( SERVICE_START_PENDING, NO_ERROR, 3000 );

	bool run_as_daemon = false;
	bool lock_memory = false;

#ifdef _MSC_VER
	std::string platform_config_file("config\\platform.xml");
#else
	std::string platform_config_file("/etc/pion/platform.xml");
#endif

	run( true, g_lock_memory, g_platform_config_file );

	report_service_status( SERVICE_STOPPED, NO_ERROR, 0 );
}
#endif

/// main control function
int main (int argc, char *argv[])
{
	bool run_as_daemon = false;
	bool lock_memory = false;

#ifdef _MSC_VER
	std::string platform_config_file("config\\platform.xml");
#else
	std::string platform_config_file("/etc/pion/platform.xml");
#endif

	if(parse_args(argc, argv, run_as_daemon, lock_memory, platform_config_file) != 0)
		return 1;

#ifdef _MSC_VER
	if(run_as_daemon) {
		// running as Windows Service
		// initialize the global variables to be used by SrvMain
		g_platform_config_file = platform_config_file;
		g_lock_memory = lock_memory;

		SERVICE_TABLE_ENTRY DispatchTable[] =
		{
			{ SVCNAME, (LPSERVICE_MAIN_FUNCTION) SvcMain },
			{ NULL, NULL }
		};
		// this call returns when the service has stopped.
		// the process should simply terminate when the call returns.
		if (!StartServiceCtrlDispatcher( DispatchTable )) {
			service_report_event(("StartServiceCtrlDispatcher"));
		}
		return 0;
	}
#endif
	return run(run_as_daemon, lock_memory, platform_config_file);
}

int run (bool run_as_daemon, bool lock_memory, const std::string& platform_config_file)
{
	// initialize log system (use simple configuration)
	PionLogger pion_log(PION_GET_LOGGER("pion"));

	// This level might be overridden if there is a LogConfig file specified in the platform
	// configuration (and if using a logging library that supports logging configuration.)
	PION_LOG_SETLEVEL_INFO(pion_log);
	PION_LOG_CONFIG_BASIC;

	// get logger for main() process
	PionLogger pion_main_log(PION_GET_LOGGER("pion.main"));

	/// become a daemon if the -D option is given
	if (run_as_daemon)
		daemonize_server();

	// setup signal handler
#ifdef _MSC_VER
	SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
#else
	signal(SIGPIPE, SIG_IGN);
	signal(SIGCHLD, SIG_IGN);
	signal(SIGTSTP, SIG_IGN);
	signal(SIGTTOU, SIG_IGN);
	signal(SIGTTIN, SIG_IGN);
	signal(SIGHUP, SIG_IGN);
	signal(SIGINT, handle_signal);
	signal(SIGTERM, handle_signal);
#endif

#ifdef PION_HAVE_SSL
	// initialize the OpenSSL library
	CRYPTO_malloc_init();
	SSL_library_init();
#endif

#ifndef _MSC_VER
	if (lock_memory)
		if (mlockall(MCL_CURRENT | MCL_FUTURE))
			PION_LOG_FATAL(pion_main_log, "Failed to lock memory: " << strerror(errno));
#endif

	// PlatformConfig destructor can throw exceptions, make sure we handle them
	try	{
		PlatformConfig platform_cfg;
		try {
			// load the platform configuration
			platform_cfg.setConfigFile(platform_config_file);
			platform_cfg.openConfigFile();

			PION_LOG_INFO(pion_main_log, "Pion has started successfully (v" << PION_VERSION << ')');
#ifdef _MSC_VER
			if(run_as_daemon)
				report_service_status( SERVICE_RUNNING, NO_ERROR, 0 );
#endif
			// wait for shutdown
			main_shutdown_manager.wait();
		} catch (std::exception& e) {
			PION_LOG_FATAL(pion_main_log, e.what());
		}

		PION_LOG_INFO(pion_main_log, "Pion is shutting down");
	} catch (std::exception& e) {
		PION_LOG_FATAL(pion_main_log, e.what());
	}
	return 0;
}

#ifdef _MSC_VER
/// run server as Windows service
void daemonize_server(void)
{
    gSvcStatusHandle = RegisterServiceCtrlHandler( SVCNAME, service_control_handler );
    if( !gSvcStatusHandle )
    {
        service_report_event(TEXT("RegisterServiceCtrlHandler"));
        return;
    }

    // These SERVICE_STATUS members remain as set here
    gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    gSvcStatus.dwServiceSpecificExitCode = 0;

    // Report initial status to the SCM
    report_service_status( SERVICE_START_PENDING, NO_ERROR, 20000 );

	// Windows tends to start the service in C:\windows\system32 folder
	// We need to change it to Pion's installation dir for Pion to work
	char exe_path[MAX_PATH];
	exe_path[0]=0;
	if( GetModuleFileName(NULL, exe_path, sizeof(exe_path)/sizeof(exe_path[0])) ) {
		char exe_dir[MAX_PATH], drive[MAX_PATH], filename[MAX_PATH];
		exe_dir[0]=0; drive[0] = 0; filename[0]=0;
		_splitpath( exe_path, drive, exe_dir, filename, NULL);
		SetCurrentDirectory( exe_dir );
	}
}
#else
/// run server as a daemon (Unix)
void daemonize_server(void)
{
	// adopted from "Unix Daemon Server Programming"
	// http://www.enderunix.org/docs/eng/daemon.php

	// return early if already running as a daemon
	if(getppid()==1) return;

	// for out the process
	int i = fork();
	if (i<0) exit(1);	// error forking
	if (i>0) exit(0);	// exit if parent

	// child (daemon process) continues here after the fork...

	// obtain a new process group
	setsid();

	// close all descriptors
	for (i=getdtablesize();i>=0;--i) close(i);

	// bind stdio to /dev/null
	i=open("/dev/null",O_RDWR); dup(i); dup(i);

	// restrict file creation mode to 0750
	umask(027);
}
#endif

/// displays an error message if the arguments are invalid
void argument_error(void)
{
	std::cerr << "usage:   pion [-c PLATFORM_XML_FILE] [-D] [-M]" << std::endl;
}
<|endoftext|>


<commit_before>/***********************************************************************************************************************
 * Copyright (C) 2016 Andrew Zonenberg and contributors                                                                *
 *                                                                                *
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General   *
 * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) *
 * any later version.                                                                                *
 *                                                                                *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied  *
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for     *
 * more details.                                                                                *
 *                                                                                *
 * You should have received a copy of the GNU Lesser General Public License along with this program; if not, you may   *
 * find one here:                                                                                *
 * https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt                                                              *
 * or you may search the http://www.gnu.org website for the version 2.1 license, or you may write to the Free Software *
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA                                      *
 **********************************************************************************************************************/

#include <log.h>
#include <gpdevboard.h>
#include <unistd.h>

using namespace std;

bool RunTest(hdevice hdev);

int main(int argc, char* argv[])
{
	g_log_sinks.emplace(g_log_sinks.begin(), new STDLogSink(Severity::VERBOSE));

	//expect one arg: the bitstream
	if(argc != 2)
	{
		LogNotice("Usage: [testcase] bitstream.txt\n");
		return 1;
	}

	//Set up the test
	if(!LockDevice())
	{
		LogError("Failed to lock dev board\n");
		return false;
	}
	hdevice hdev = MultiBoardTestSetup(argv[1], 25000, 3.3, SilegoPart::SLG46620V);
	if(!hdev)
	{
		LogError("Failed to open board\n");
		return 1;
	}

	//Run the actual test case
	LogNotice("\n");
	LogNotice("Running application test case\n");
	if(!RunTest(hdev))
	{
		SetStatusLED(hdev, 0);
		Reset(hdev);
		return 1;
	}

	//Turn off the LED before declaring success
	LogVerbose("\n");
	LogVerbose("Test complete, resetting board\n");
	SetStatusLED(hdev, 0);
	ResetAllSiggens(hdev);
	Reset(hdev);
	USBCleanup(hdev);
	UnlockDevice();
	return 0;
}

/**
	@brief The actual application-layer test
 */
bool RunTest(hdevice hdev)
{
	LogIndenter li;

	//Set up the I/O config we need for this test (?)
	IOConfig ioConfig;
	for(size_t i = 2; i <= 20; i++)
		ioConfig.driverConfigs[i] = TP_RESET;
	if(!SetIOConfig(hdev, ioConfig))
		return false;

	const int INPUT_PIN = 8;
	const int OUTPUT_PIN = 7;

	//Sweep input and verify output
	LogVerbose("Running PGA voltage sweep\n");
	LogVerbose("|%10s|%10s|%10s|%10s|%10s|%10s|\n", "Requested", "Actual", "Output", "Expected", "Error", "% error");
	double step = 0.05;
	for(double vtest = step; vtest < 0.51; vtest += step)
	{
		//Set up a signal generator on the input
		if(!ConfigureSiggen(hdev, INPUT_PIN, vtest))
			return false;

		//Read the input
		if(!SelectADCChannel(hdev, INPUT_PIN))
			return false;
		double vin;
		if(!ReadADC(hdev, vin))
			return false;

		//Read the output
		if(!SelectADCChannel(hdev, OUTPUT_PIN))
			return false;
		double vout;
		if(!ReadADC(hdev, vout))
			return false;

		double expected = vin * 2;
		double error = expected - vout;
		double pctError = (error * 100) / expected;

		LogVerbose("|%10.3f|%10.3f|%10.3f|%10.3f|%10.3f|%10.3f|\n", vtest, vin, vout, expected, error, pctError);

		//TODO: Decide on an appropriate tolerance
		if(pctError > 5)
		{
			LogError("Percent error is too big, test failed\n");
			return false;
		}
	}

	return true;
}
<commit_msg>tests: fixed returning false on error instead of 1<commit_after>/***********************************************************************************************************************
 * Copyright (C) 2016 Andrew Zonenberg and contributors                                                                *
 *                                                                                *
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General   *
 * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) *
 * any later version.                                                                                *
 *                                                                                *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied  *
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for     *
 * more details.                                                                                *
 *                                                                                *
 * You should have received a copy of the GNU Lesser General Public License along with this program; if not, you may   *
 * find one here:                                                                                *
 * https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt                                                              *
 * or you may search the http://www.gnu.org website for the version 2.1 license, or you may write to the Free Software *
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA                                      *
 **********************************************************************************************************************/

#include <log.h>
#include <gpdevboard.h>
#include <unistd.h>

using namespace std;

bool RunTest(hdevice hdev);

int main(int argc, char* argv[])
{
	g_log_sinks.emplace(g_log_sinks.begin(), new STDLogSink(Severity::VERBOSE));

	//expect one arg: the bitstream
	if(argc != 2)
	{
		LogNotice("Usage: [testcase] bitstream.txt\n");
		return 1;
	}

	//Set up the test
	if(!LockDevice())
	{
		LogError("Failed to lock dev board\n");
		return 1;
	}
	hdevice hdev = MultiBoardTestSetup(argv[1], 25000, 3.3, SilegoPart::SLG46620V);
	if(!hdev)
	{
		LogError("Failed to open board\n");
		return 1;
	}

	//Run the actual test case
	LogNotice("\n");
	LogNotice("Running application test case\n");
	if(!RunTest(hdev))
	{
		SetStatusLED(hdev, 0);
		Reset(hdev);
		return 1;
	}

	//Turn off the LED before declaring success
	LogVerbose("\n");
	LogVerbose("Test complete, resetting board\n");
	SetStatusLED(hdev, 0);
	ResetAllSiggens(hdev);
	Reset(hdev);
	USBCleanup(hdev);
	UnlockDevice();
	return 0;
}

/**
	@brief The actual application-layer test
 */
bool RunTest(hdevice hdev)
{
	LogIndenter li;

	//Set up the I/O config we need for this test (?)
	IOConfig ioConfig;
	for(size_t i = 2; i <= 20; i++)
		ioConfig.driverConfigs[i] = TP_RESET;
	if(!SetIOConfig(hdev, ioConfig))
		return false;

	const int INPUT_PIN = 8;
	const int OUTPUT_PIN = 7;

	//Sweep input and verify output
	LogVerbose("Running PGA voltage sweep\n");
	LogVerbose("|%10s|%10s|%10s|%10s|%10s|%10s|\n", "Requested", "Actual", "Output", "Expected", "Error", "% error");
	double step = 0.05;
	for(double vtest = step; vtest < 0.51; vtest += step)
	{
		//Set up a signal generator on the input
		if(!ConfigureSiggen(hdev, INPUT_PIN, vtest))
			return false;

		//Read the input
		if(!SelectADCChannel(hdev, INPUT_PIN))
			return false;
		double vin;
		if(!ReadADC(hdev, vin))
			return false;

		//Read the output
		if(!SelectADCChannel(hdev, OUTPUT_PIN))
			return false;
		double vout;
		if(!ReadADC(hdev, vout))
			return false;

		double expected = vin * 2;
		double error = expected - vout;
		double pctError = (error * 100) / expected;

		LogVerbose("|%10.3f|%10.3f|%10.3f|%10.3f|%10.3f|%10.3f|\n", vtest, vin, vout, expected, error, pctError);

		//TODO: Decide on an appropriate tolerance
		if(pctError > 5)
		{
			LogError("Percent error is too big, test failed\n");
			return false;
		}
	}

	return true;
}
<|endoftext|>


<commit_before>#include <lunar_parsec.hpp>

#include <iostream>
#include <limits>

#include <stdlib.h>

typedef std::numeric_limits< double > dbl;

class json_val {
public:
    json_val() { }
    virtual ~json_val() { }
};

class json_double : public json_val {
public:
    json_double(double num) : m_num(num) { }
    virtual ~json_double() { }

    double m_num;
};

class json_string : public json_val {
public:
    json_string() { }
    virtual ~json_string() { }

    std::string m_str;
};

std::string
parse_frac(lunar::parsec<char> &ps)
{
    std::string s;

    auto dot = ps.character('.')();
    if (! ps.is_success())
        return s;

    s  = ".";
    s += ps.parse_many1_char(ps.parse_digit())();

    return s;
}

std::string
parse_digit1_9(lunar::parsec<char> &ps)
{
    auto one2nine = [](char c) -> bool {
        return '1' <= c && c <= '9';
    };

    std::string s;

    auto c = ps.satisfy(one2nine)();
    if (! ps.is_success())
        return s;

    s += c;
    s += ps.parse_many_char(ps.parse_digit())();

    return s;
}

// number          = [ minus ] int [ frac ] [ exp ]
json_double
parse_number(lunar::parsec<char> &ps)
{
    std::string s;

    {
        lunar::parsec<char>::parser_try ptry(ps);
        auto sign = ps.character('-')();
        if (ps.is_success())
            s += "-";
    }

    {
        lunar::parsec<char>::parser_try ptry(ps);
        auto zero = ps.character('0')();
        if (ps.is_success()) {
            return json_double(0);
        }
    }

    s += parse_digit1_9(ps);
    if (! ps.is_success()) {
        return json_double(0);
    }

    {
        lunar::parsec<char>::parser_try ptry(ps);
        auto frac = parse_frac(ps);
        if (ps.is_success())
            s += frac;
    }

    ps.set_is_success(true);

    return json_double(strtod(s.c_str(), nullptr));
}

void
parser_json(void *arg)
{
    auto rs = (lunar::shared_stream*)arg;

    lunar::parsec<char> ps(rs);

    json_double d = parse_number(ps);
    if (ps.is_success()) {
        std::cout.precision(dbl::max_digits10);
        std::cout << "input = " << d.m_num << "\n> " << std::flush;
    } else {
        std::cout << "failed to parse\n> " << std::flush;
    }

    lunar::deref_ptr_stream(rs);
}

void
read_stdin(void *arg)
{
    struct kevent kev;
    EV_SET(&kev, STDIN_FILENO, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);

    std::cout << "> " << std::flush;
    for (;;) {
        lunar::select_green_thread(&kev, 1, nullptr, 0, false, 0);
        auto str = new std::string;
        auto rs  = new lunar::shared_stream;
        auto ws  = new lunar::shared_stream;

        lunar::make_ptr_stream(rs, ws, 32);

        std::cin >> *str;

        lunar::spawn_green_thread(parser_json, rs);

        lunar::push_ptr(ws, str);
        lunar::push_eof(ws);

        lunar::deref_ptr_stream(ws);
    }
}

int
main(int argc, char **argv)
{
    lunar::init_green_thread(0);

    lunar::spawn_green_thread(read_stdin, nullptr);
    lunar::run_green_thread();

    return 0;
}<commit_msg>update json parser in C++<commit_after>#include <lunar_parsec.hpp>

#include <iostream>
#include <limits>

#include <stdlib.h>

typedef std::numeric_limits< double > dbl;

class json_val {
public:
    json_val() { }
    virtual ~json_val() { }
};

class json_double : public json_val {
public:
    json_double(double num) : m_num(num) { }
    virtual ~json_double() { }

    double m_num;
};

class json_string : public json_val {
public:
    json_string() { }
    virtual ~json_string() { }

    std::string m_str;
};

std::string
parse_frac(lunar::parsec<char> &ps)
{
    std::string s;

    auto dot = ps.character('.')();
    if (! ps.is_success())
        return s;

    s  = ".";
    s += ps.parse_many1_char(ps.parse_digit())();

    return s;
}

std::string
parse_digit1_9(lunar::parsec<char> &ps)
{
    auto one2nine = [](char c) -> bool {
        return '1' <= c && c <= '9';
    };

    std::string s;

    auto c = ps.satisfy(one2nine)();
    if (! ps.is_success())
        return s;

    s += c;
    s += ps.parse_many_char(ps.parse_digit())();

    return s;
}

// number          = [ minus ] int [ frac ] [ exp ]
json_double
parse_number(lunar::parsec<char> &ps)
{
    std::string s;

    {
        lunar::parsec<char>::parser_try ptry(ps);
        auto sign = ps.character('-')();
        if (ps.is_success())
            s += "-";
    }

    {
        lunar::parsec<char>::parser_try ptry(ps);
        auto zero = ps.character('0')();
        if (ps.is_success()) {
            return json_double(0);
        }
    }

    s += parse_digit1_9(ps);
    if (! ps.is_success()) {
        return json_double(0);
    }

    {
        lunar::parsec<char>::parser_try ptry(ps);
        auto frac = parse_frac(ps);
        if (ps.is_success())
            s += frac;
    }

    ps.set_is_success(true);

    return json_double(strtod(s.c_str(), nullptr));
}

bool
is_unescaped(char c)
{
    if (c == '\x20' || c == '\x21' ||
        ('\x23' <= c && c <= '\x5b') ||
        ('\x5d' <= c && c <= '\x7f') ||
        ((char)-128 <= c && c <= (char)-1))
        return true;

    return false;
}

// string          = quotation-mark *char quotation-mark
json_string
parse_string(lunar::parsec<char> &ps)
{
    json_string ret;

    ps.character('"')();
    if (! ps.is_success())
        return ret;

    char c;
    {
        lunar::parsec<char>::parser_try ptry(ps);
        c = ps.satisfy(is_unescaped)();
    }
    if (ps.is_success())
        ret.m_str += c;
    else
        ps.set_is_success(true);

    ps.character('"')();
    if (! ps.is_success())
        return ret;

    return ret;
}

void
parser_json(void *arg)
{
    auto rs = (lunar::shared_stream*)arg;

    lunar::parsec<char> ps(rs);

    json_double d = parse_number(ps);
    if (ps.is_success()) {
        std::cout.precision(dbl::max_digits10);
        std::cout << "input = " << d.m_num << "\n> " << std::flush;
    } else {
        std::cout << "failed to parse\n> " << std::flush;
    }

    lunar::deref_ptr_stream(rs);
}

void
read_stdin(void *arg)
{
    struct kevent kev;
    EV_SET(&kev, STDIN_FILENO, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);

    std::cout << "> " << std::flush;
    for (;;) {
        lunar::select_green_thread(&kev, 1, nullptr, 0, false, 0);
        auto str = new std::string;
        auto rs  = new lunar::shared_stream;
        auto ws  = new lunar::shared_stream;

        lunar::make_ptr_stream(rs, ws, 32);

        std::cin >> *str;

        lunar::spawn_green_thread(parser_json, rs);

        lunar::push_ptr(ws, str);
        lunar::push_eof(ws);

        lunar::deref_ptr_stream(ws);
    }
}

int
main(int argc, char **argv)
{
    lunar::init_green_thread(0);

    lunar::spawn_green_thread(read_stdin, nullptr);
    lunar::run_green_thread();

    return 0;
}<|endoftext|>


<commit_before>// Copyright (C) 2010-2013 Joshua Boyce.
// See the file COPYING for copying permission.

#include <hadesmem/pelib/tls_dir.hpp>
#include <hadesmem/pelib/tls_dir.hpp>

#include <sstream>
#include <utility>

#include <hadesmem/detail/warning_disable_prefix.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <hadesmem/detail/warning_disable_suffix.hpp>

#include <hadesmem/config.hpp>
#include <hadesmem/error.hpp>
#include <hadesmem/module.hpp>
#include <hadesmem/module_list.hpp>
#include <hadesmem/pelib/pe_file.hpp>
#include <hadesmem/process.hpp>
#include <hadesmem/read.hpp>

void TestTlsDir()
{
// Use TLS to ensure that at least one module has a TLS dir
#if defined(HADESMEM_GCC) || defined(HADESMEM_CLANG)
  static thread_local int tls_dummy = 0;
#elif defined(HADESMEM_MSVC) || defined(HADESMEM_INTEL)
  static __declspec(thread) int tls_dummy = 0;
#else
#error "[HadesMem] Unsupported compiler."
#endif
  (void)tls_dummy;

  hadesmem::Process const process(::GetCurrentProcessId());

  hadesmem::PeFile pe_file_1(
    process, ::GetModuleHandleW(nullptr), hadesmem::PeFileType::Image, 0);

  hadesmem::TlsDir tls_dir_1(process, pe_file_1);

  hadesmem::TlsDir tls_dir_2(tls_dir_1);
  BOOST_TEST_EQ(tls_dir_1, tls_dir_2);
  tls_dir_1 = tls_dir_2;
  BOOST_TEST_EQ(tls_dir_1, tls_dir_2);
  hadesmem::TlsDir tls_dir_3(std::move(tls_dir_2));
  BOOST_TEST_EQ(tls_dir_3, tls_dir_1);
  tls_dir_2 = std::move(tls_dir_3);
  BOOST_TEST_EQ(tls_dir_1, tls_dir_2);

  bool processed_one_tls_dir = false;

  hadesmem::ModuleList modules(process);
  for (auto const& mod : modules)
  {
    // TODO: Also test FileType_Data
    hadesmem::PeFile const cur_pe_file(
      process, mod.GetHandle(), hadesmem::PeFileType::Image, 0);

    std::unique_ptr<hadesmem::TlsDir> cur_tls_dir;
    try
    {
      cur_tls_dir = std::make_unique<hadesmem::TlsDir>(process, cur_pe_file);
    }
    catch (std::exception const& /*e*/)
    {
      continue;
    }

    processed_one_tls_dir = true;

    auto const tls_dir_raw =
      hadesmem::Read<IMAGE_TLS_DIRECTORY>(process, cur_tls_dir->GetBase());

    cur_tls_dir->SetStartAddressOfRawData(
      cur_tls_dir->GetStartAddressOfRawData());
    cur_tls_dir->SetEndAddressOfRawData(cur_tls_dir->GetEndAddressOfRawData());
    cur_tls_dir->SetAddressOfIndex(cur_tls_dir->GetAddressOfIndex());
    cur_tls_dir->SetAddressOfCallBacks(cur_tls_dir->GetAddressOfCallBacks());
    cur_tls_dir->SetSizeOfZeroFill(cur_tls_dir->GetSizeOfZeroFill());
    cur_tls_dir->SetCharacteristics(cur_tls_dir->GetCharacteristics());
    std::vector<PIMAGE_TLS_CALLBACK> callbacks;
    cur_tls_dir->GetCallbacks(std::back_inserter(callbacks));
    cur_tls_dir->UpdateWrite();
    cur_tls_dir->UpdateRead();

    auto const tls_dir_raw_new =
      hadesmem::Read<IMAGE_TLS_DIRECTORY>(process, cur_tls_dir->GetBase());

    BOOST_TEST_EQ(
      std::memcmp(&tls_dir_raw, &tls_dir_raw_new, sizeof(tls_dir_raw)), 0);

    std::stringstream test_str_1;
    test_str_1.imbue(std::locale::classic());
    test_str_1 << *cur_tls_dir;
    std::stringstream test_str_2;
    test_str_2.imbue(std::locale::classic());
    test_str_2 << cur_tls_dir->GetBase();
    BOOST_TEST_EQ(test_str_1.str(), test_str_2.str());

    // TODO: Ensure that base address is different across modules (similar to
    // other tests).
  }

  BOOST_TEST(processed_one_tls_dir);
}

int main()
{
  TestTlsDir();
  return boost::report_errors();
}
<commit_msg>* [TlsDir] Fix test for Intel C++ compiler (it was optimizing away the thread local variable, meaning there were no loaded modules with a TLS dir, so now we actually use the variable in a calculation).<commit_after>// Copyright (C) 2010-2013 Joshua Boyce.
// See the file COPYING for copying permission.

#include <hadesmem/pelib/tls_dir.hpp>
#include <hadesmem/pelib/tls_dir.hpp>

#include <sstream>
#include <utility>

#include <hadesmem/detail/warning_disable_prefix.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <hadesmem/detail/warning_disable_suffix.hpp>

#include <hadesmem/config.hpp>
#include <hadesmem/error.hpp>
#include <hadesmem/module.hpp>
#include <hadesmem/module_list.hpp>
#include <hadesmem/pelib/pe_file.hpp>
#include <hadesmem/process.hpp>
#include <hadesmem/read.hpp>

void TestTlsDir()
{
// Use TLS to ensure that at least one module has a TLS dir
#if defined(HADESMEM_GCC) || defined(HADESMEM_CLANG)
  static thread_local std::int32_t = 0;
#elif defined(HADESMEM_MSVC) || defined(HADESMEM_INTEL)
  static __declspec(thread) std::int32_t tls_dummy = 0;
#else
#error "[HadesMem] Unsupported compiler."
#endif

  hadesmem::Process const process(::GetCurrentProcessId());

  hadesmem::PeFile pe_file_1(
    process, ::GetModuleHandleW(nullptr), hadesmem::PeFileType::Image, 0);

  hadesmem::TlsDir tls_dir_1(process, pe_file_1);

  hadesmem::TlsDir tls_dir_2(tls_dir_1);
  BOOST_TEST_EQ(tls_dir_1, tls_dir_2);
  tls_dir_1 = tls_dir_2;
  BOOST_TEST_EQ(tls_dir_1, tls_dir_2);
  hadesmem::TlsDir tls_dir_3(std::move(tls_dir_2));
  BOOST_TEST_EQ(tls_dir_3, tls_dir_1);
  tls_dir_2 = std::move(tls_dir_3);
  BOOST_TEST_EQ(tls_dir_1, tls_dir_2);

  hadesmem::ModuleList modules(process);
  for (auto const& mod : modules)
  {
    // TODO: Also test FileType_Data
    hadesmem::PeFile const cur_pe_file(
      process, mod.GetHandle(), hadesmem::PeFileType::Image, 0);

    std::unique_ptr<hadesmem::TlsDir> cur_tls_dir;
    try
    {
      cur_tls_dir = std::make_unique<hadesmem::TlsDir>(process, cur_pe_file);
    }
    catch (std::exception const& /*e*/)
    {
      continue;
    }

    ++tls_dummy;

    auto const tls_dir_raw =
      hadesmem::Read<IMAGE_TLS_DIRECTORY>(process, cur_tls_dir->GetBase());

    cur_tls_dir->SetStartAddressOfRawData(
      cur_tls_dir->GetStartAddressOfRawData());
    cur_tls_dir->SetEndAddressOfRawData(cur_tls_dir->GetEndAddressOfRawData());
    cur_tls_dir->SetAddressOfIndex(cur_tls_dir->GetAddressOfIndex());
    cur_tls_dir->SetAddressOfCallBacks(cur_tls_dir->GetAddressOfCallBacks());
    cur_tls_dir->SetSizeOfZeroFill(cur_tls_dir->GetSizeOfZeroFill());
    cur_tls_dir->SetCharacteristics(cur_tls_dir->GetCharacteristics());
    std::vector<PIMAGE_TLS_CALLBACK> callbacks;
    cur_tls_dir->GetCallbacks(std::back_inserter(callbacks));
    cur_tls_dir->UpdateWrite();
    cur_tls_dir->UpdateRead();

    auto const tls_dir_raw_new =
      hadesmem::Read<IMAGE_TLS_DIRECTORY>(process, cur_tls_dir->GetBase());

    BOOST_TEST_EQ(
      std::memcmp(&tls_dir_raw, &tls_dir_raw_new, sizeof(tls_dir_raw)), 0);

    std::stringstream test_str_1;
    test_str_1.imbue(std::locale::classic());
    test_str_1 << *cur_tls_dir;
    std::stringstream test_str_2;
    test_str_2.imbue(std::locale::classic());
    test_str_2 << cur_tls_dir->GetBase();
    BOOST_TEST_EQ(test_str_1.str(), test_str_2.str());

    // TODO: Ensure that base address is different across modules (similar to
    // other tests).
  }

  BOOST_TEST_NE(tls_dummy, 0);
}

int main()
{
  TestTlsDir();
  return boost::report_errors();
}
<|endoftext|>