<commit_before>#include <fstream>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>

#include "mugen_font.h"

#include "mugen_item.h"
#include "mugen_item_content.h"
#include "mugen_section.h"
#include "mugen_reader.h"
#include "mugen_util.h"
#include "globals.h"
#include "util/funcs.h"

// If you use this, please delete the item after you use it, this isn't java ok
static MugenItemContent *getOpts( const std::string &opt ){
    std::string contentHolder = "";
    MugenItemContent *temp = new MugenItemContent();
    const char * ignored = " \r\n";
    Global::debug(1) << "Parsing string to ItemContent: " << opt << endl;
    for( unsigned int i = 0; i < opt.size(); ++i ){
	if( opt[i] == ';' )break;
	if( opt[i] == ' ' ){
	    if( !contentHolder.empty() ) *temp << contentHolder;
	    Global::debug(1) << "Got content: " << contentHolder << endl;
	    contentHolder = "";
	}
	//Start grabbing our item
	else if (! strchr(ignored, opt[i])){
		contentHolder += opt[i];
	}
    }
    if( !contentHolder.empty() ){
	*temp << contentHolder;
	Global::debug(1) << "Got content: " << contentHolder << endl;
    }
    return temp;
}

MugenFont::MugenFont( const string & file ):
type(Fixed),
width(0),
height(0),
spacingx(0),
spacingy(0),
colors(0),
offsetx(0),
offsety(0),
bmp(0),
pcx(0),
pcxsize(0),
currentBank(0){
    Global::debug(1) << "[mugen font] Opening file '" << file << "'" << endl;
    ifile.open( std::string(Util::getDataPath() + "mugen/font/" + file).c_str() );
    if (!ifile){
        perror("cant open file");
    }
    myfile = file;

    load();
}

MugenFont::MugenFont( const char * file ):
type(Fixed),
width(0),
height(0),
spacingx(0),
spacingy(0),
colors(0),
offsetx(0),
offsety(0),
bmp(0),
pcx(0),
pcxsize(0),
currentBank(0){
    Global::debug(1) << "[mugen font] Opening file '" << file << "'" << endl;
    ifile.open( std::string(Util::getDataPath() + "mugen/font/" + file).c_str() );
    if (!ifile){
        perror("cant open file");
    }
    myfile = string( file );

    load();
}

MugenFont::MugenFont( const MugenFont &copy ){
    this->type = copy.type;
    this->width = copy.width;
    this->height = copy.height;
    this->spacingx = copy.spacingx;
    this->spacingy = copy.spacingy;
    this->colors = copy.colors;
    this->offsetx = copy.offsetx;
    this->offsety = copy.offsety;
    this->bmp = copy.bmp;
}

MugenFont::~MugenFont(){
    if(bmp){
	delete bmp;
    }
}

MugenFont & MugenFont::operator=( const MugenFont &copy ){
    this->type = copy.type;
    this->width = copy.width;
    this->height = copy.height;
    this->spacingx = copy.spacingx;
    this->spacingy = copy.spacingy;
    this->colors = copy.colors;
    this->offsetx = copy.offsetx;
    this->offsety = copy.offsety;
    this->bmp = copy.bmp;

    return *this;
}

// Implement Font stuff
void MugenFont::setSize( const int x, const int y ){
    // We don't change sizes
    if  ( (x < 0 || y < 0) && type!=Fixed ){
	return;
    }
}
const int MugenFont::getSizeX() const{
    return width;
}
const int MugenFont::getSizeY() const{
    return height;
}

const int MugenFont::textLength( const char * text ) const{
    std::string str(text);
    int size =0;
    for (unsigned int i = 0; i < str.size(); ++i){
	std::map<char, FontLocation>::const_iterator loc = positions.find(str[i]);
	if (loc!=positions.end()){
	   size+=loc->second.width + spacingx;
	} else{
	    // Couldn't find a position for this character assume regular width and skip to the next character
	    size+=width + spacingx;
	}
    }
    return size;
}

const int MugenFont::getHeight( const string & str ) const{
    // What? I guess this is for freetype?
    return getHeight();
}

const int MugenFont::getHeight() const{
    return height;
}

void MugenFont::printf( int x, int y, int color, const Bitmap & work, const string & str, int marker, ... ) const{
    // Va list
    char buf[512];
    va_list ap;

    va_start(ap, marker);
    vsnprintf(buf, sizeof(buf), str.c_str(), ap);
    va_end(ap);

    const std::string newstr(buf);

    int workoffsetx = 0;
    for (unsigned int i = 0; i < newstr.size(); ++i){
	std::map<char, FontLocation>::const_iterator loc = positions.find(newstr[i]);
	if (loc!=positions.end()){
	    Bitmap character = Bitmap::temporaryBitmap( loc->second.width + spacingx, height + spacingy);
	    bmp->Blit( loc->second.startx, 0, loc->second.width + spacingx, height + spacingy,0,0, character );
	    character.draw( x + workoffsetx, y, work);
	    workoffsetx+=loc->second.width + spacingx;
	} else{
	    // Couldn't find a position for this character draw nothing, assume width, and skip to the next character
	    workoffsetx+=width + spacingx;
	}
    }
}

void MugenFont::changeBank(int bank){
    if (bank < 0 || bank > (colors -1))return;
    currentBank = bank;
    unsigned char pal[768];
    unsigned char newpal[768];
    memcpy( &pal, pcx+(pcxsize)-768, 768);
    memcpy( &newpal, pcx+(pcxsize)-768, 768);
    unsigned int start = currentBank * colors;
    for( int  i = 0; i < colors; ++i, ++start){
	newpal[768 - i] = pal[768-start];
	newpal[768 - i -1] = pal[768-start -1];
	newpal[768 - i -2] = pal[768-start -2];
    }
    unsigned char *tmppcx = new unsigned char[pcxsize];
    memcpy(tmppcx, pcx, pcxsize);
    memcpy(tmppcx + (pcxsize - 768), &newpal, 768);
    if (bmp){
	delete bmp;
    }
    bmp = new Bitmap(Bitmap::memoryPCX((unsigned char*) tmppcx, pcxsize));
}

void MugenFont::load(){

    /* 16 skips the header stuff */
    int location = 16;
    // Lets go ahead and skip the crap -> (Elecbyte signature and version) start at the 16th byte
    ifile.seekg(location,ios::beg);
    unsigned long pcxlocation;
    unsigned long txtlocation;
    unsigned long txtsize;

    ifile.read( (char *)&pcxlocation, sizeof(unsigned long) );
    ifile.read( (char *)&pcxsize, sizeof(unsigned long) );
    ifile.read( (char *)&txtlocation, sizeof(unsigned long) );
    ifile.read( (char *)&txtsize, sizeof(unsigned long) );
    Global::debug(1) << "PCX Location: " << pcxlocation << " | PCX Size: " << pcxsize << endl;
    Global::debug(1) << "TXT Location: " << txtlocation << " | TXT Actual location: " << pcxlocation + pcxsize << " | TXT Size: " << txtsize << endl;

    // Get the pcx load our bitmap
    ifile.seekg(pcxlocation,ios::beg);
    pcx = new unsigned char[pcxsize];
    ifile.read((char *)pcx, pcxsize);

    bmp = new Bitmap(Bitmap::memoryPCX((unsigned char*) pcx, pcxsize));

    // Get the text
    ifile.seekg(pcxlocation+pcxsize, ios::beg);
    std::vector<std::string> ourText;
    while( !ifile.eof() ){
	std::string line;
	getline( ifile, line );
	ourText.push_back(line);
    }

    std::vector< MugenSection * > collection = MugenUtil::configReader( ourText );

    for( unsigned int i = 0; i < collection.size(); ++i ){
	const std::string &head = collection[i]->getHeader();
	if( head == "Def" ){
	    while( collection[i]->hasItems() ){
		MugenItemContent *content = collection[i]->getNext();
		const MugenItem *item = content->getNext();
		std::string itemhead = item->query();
		MugenUtil::removeSpaces(itemhead);
		// This is so we don't have any problems with crap like Name, NaMe, naMe or whatever
		MugenUtil::fixCase( itemhead );
		if ( itemhead.find("size")!=std::string::npos ){
		    *content->getNext() >> width;
		    *content->getNext() >> height;
		} else if ( itemhead.find("spacing")!=std::string::npos ){
		    *content->getNext() >> spacingx;
		    *content->getNext() >> spacingy;
		} else if ( itemhead.find("colors")!=std::string::npos ){
		    *content->getNext() >> colors;
		} else if ( itemhead.find("offset")!=std::string::npos ){
		    *content->getNext() >> offsetx;
		    *content->getNext() >> offsety;
		} else if ( itemhead.find("type")!=std::string::npos ){
		    std::string temp;
		    *content->getNext() >> temp;
		    MugenUtil::removeSpaces(temp);
		    MugenUtil::fixCase(temp);
		    if (temp == "variable")type = Variable;
		    else if (temp == "fixed")type = Fixed;
		    Global::debug(1) << "Type: " << temp << endl;
		} //else throw MugenException( "Unhandled option in Info Section: " + itemhead );
	    }
	    Global::debug(1) << "Size X: " << width << ", Size Y: " << height << ", Spacing X: " << spacingx << ", Spacing Y: " << spacingy << ", Colors: " << colors << ", Offset X: " << offsetx << ", Offset Y: " << offsety << endl;
	}
	if( head == "Map" ){
	    bool beginParse = false;
	    int locationx = 0;
	    for (std::vector<std::string>::iterator l = ourText.begin(); l != ourText.end(); ++l){
		std::string line = *l;
		if (!beginParse){
		    if (line.find("[Map]")==std::string::npos){
			continue;
		    } else{
			beginParse = true;
			continue;
		    }
		}
		MugenItemContent *opt = getOpts(line);
		std::string character;
		int startx = locationx * width;
		int chrwidth = width;
		*opt->getNext() >> character;
		if( character != "empty" ) {
		    if (character == "0x5b") character = "[";
		    else if (character == "0x3b") character = ";";
		    if (type != Fixed){
			// get other two
			*opt->getNext() >> startx;
			*opt->getNext() >> chrwidth;
		    }
		    FontLocation loc;
		    loc.startx = startx;
		    loc.width = chrwidth;
		    char code = character[0];
		    Global::debug(1) << "Storing Character: " << code << " | startx: " << loc.startx << " | width: " << loc.width << endl;
		    positions[code] = loc;
		}
		delete opt;
		++locationx;
	    }
	}
    }

    // Time to get rid of collection
    for( std::vector< MugenSection * >::iterator i = collection.begin() ; i != collection.end() ; ++i ){
        if(*i)delete (*i);
    }

    ifile.close();

}

<commit_msg>Deleted allocated memory after use. Output bank information debug level 2<commit_after>#include <fstream>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>

#include "mugen_font.h"

#include "mugen_item.h"
#include "mugen_item_content.h"
#include "mugen_section.h"
#include "mugen_reader.h"
#include "mugen_util.h"
#include "globals.h"
#include "util/funcs.h"

// If you use this, please delete the item after you use it, this isn't java ok
static MugenItemContent *getOpts( const std::string &opt ){
    std::string contentHolder = "";
    MugenItemContent *temp = new MugenItemContent();
    const char * ignored = " \r\n";
    Global::debug(1) << "Parsing string to ItemContent: " << opt << endl;
    for( unsigned int i = 0; i < opt.size(); ++i ){
	if( opt[i] == ';' )break;
	if( opt[i] == ' ' ){
	    if( !contentHolder.empty() ) *temp << contentHolder;
	    Global::debug(1) << "Got content: " << contentHolder << endl;
	    contentHolder = "";
	}
	//Start grabbing our item
	else if (! strchr(ignored, opt[i])){
		contentHolder += opt[i];
	}
    }
    if( !contentHolder.empty() ){
	*temp << contentHolder;
	Global::debug(1) << "Got content: " << contentHolder << endl;
    }
    return temp;
}

MugenFont::MugenFont( const string & file ):
type(Fixed),
width(0),
height(0),
spacingx(0),
spacingy(0),
colors(0),
offsetx(0),
offsety(0),
bmp(0),
pcx(0),
pcxsize(0),
currentBank(0){
    Global::debug(1) << "[mugen font] Opening file '" << file << "'" << endl;
    ifile.open( std::string(Util::getDataPath() + "mugen/font/" + file).c_str() );
    if (!ifile){
        perror("cant open file");
    }
    myfile = file;

    load();
}

MugenFont::MugenFont( const char * file ):
type(Fixed),
width(0),
height(0),
spacingx(0),
spacingy(0),
colors(0),
offsetx(0),
offsety(0),
bmp(0),
pcx(0),
pcxsize(0),
currentBank(0){
    Global::debug(1) << "[mugen font] Opening file '" << file << "'" << endl;
    ifile.open( std::string(Util::getDataPath() + "mugen/font/" + file).c_str() );
    if (!ifile){
        perror("cant open file");
    }
    myfile = string( file );

    load();
}

MugenFont::MugenFont( const MugenFont &copy ){
    this->type = copy.type;
    this->width = copy.width;
    this->height = copy.height;
    this->spacingx = copy.spacingx;
    this->spacingy = copy.spacingy;
    this->colors = copy.colors;
    this->offsetx = copy.offsetx;
    this->offsety = copy.offsety;
    this->bmp = copy.bmp;
}

MugenFont::~MugenFont(){
    if(bmp){
	delete bmp;
    }
}

MugenFont & MugenFont::operator=( const MugenFont &copy ){
    this->type = copy.type;
    this->width = copy.width;
    this->height = copy.height;
    this->spacingx = copy.spacingx;
    this->spacingy = copy.spacingy;
    this->colors = copy.colors;
    this->offsetx = copy.offsetx;
    this->offsety = copy.offsety;
    this->bmp = copy.bmp;

    return *this;
}

// Implement Font stuff
void MugenFont::setSize( const int x, const int y ){
    // We don't change sizes
    if  ( (x < 0 || y < 0) && type!=Fixed ){
	return;
    }
}
const int MugenFont::getSizeX() const{
    return width;
}
const int MugenFont::getSizeY() const{
    return height;
}

const int MugenFont::textLength( const char * text ) const{
    std::string str(text);
    int size =0;
    for (unsigned int i = 0; i < str.size(); ++i){
	std::map<char, FontLocation>::const_iterator loc = positions.find(str[i]);
	if (loc!=positions.end()){
	   size+=loc->second.width + spacingx;
	} else{
	    // Couldn't find a position for this character assume regular width and skip to the next character
	    size+=width + spacingx;
	}
    }
    return size;
}

const int MugenFont::getHeight( const string & str ) const{
    // What? I guess this is for freetype?
    return getHeight();
}

const int MugenFont::getHeight() const{
    return height;
}

void MugenFont::printf( int x, int y, int color, const Bitmap & work, const string & str, int marker, ... ) const{
    // Va list
    char buf[512];
    va_list ap;

    va_start(ap, marker);
    vsnprintf(buf, sizeof(buf), str.c_str(), ap);
    va_end(ap);

    const std::string newstr(buf);

    int workoffsetx = 0;
    for (unsigned int i = 0; i < newstr.size(); ++i){
	std::map<char, FontLocation>::const_iterator loc = positions.find(newstr[i]);
	if (loc!=positions.end()){
	    Bitmap character = Bitmap::temporaryBitmap( loc->second.width + spacingx, height + spacingy);
	    bmp->Blit( loc->second.startx, 0, loc->second.width + spacingx, height + spacingy,0,0, character );
	    character.draw( x + workoffsetx, y, work);
	    workoffsetx+=loc->second.width + spacingx;
	} else{
	    // Couldn't find a position for this character draw nothing, assume width, and skip to the next character
	    workoffsetx+=width + spacingx;
	}
    }
}

void MugenFont::changeBank(int bank){
    if (bank < 0 || bank > (colors -1))return;
    currentBank = bank;
    unsigned char pal[768];
    unsigned char newpal[768];
    memcpy( pal, pcx+(pcxsize)-768, 768);
    memcpy( newpal, pcx+(pcxsize)-768, 768);
    unsigned int start = currentBank * colors;
    Global::debug(1) << "Current bank: " << start << endl;
    for( int  i = 0; i < colors; ++i, ++start){
	newpal[768 - i] = pal[768-start];
	newpal[768 - i -1] = pal[768-start -1];
	newpal[768 - i -2] = pal[768-start -2];
    }
    unsigned char *tmppcx = new unsigned char[pcxsize];
    memcpy(tmppcx, pcx, pcxsize);
    memcpy(tmppcx + (pcxsize - 768), newpal, 768);
    if (bmp){
	delete bmp;
    }
    bmp = new Bitmap(Bitmap::memoryPCX((unsigned char*) tmppcx, pcxsize));
    delete [] tmppcx;
}

void MugenFont::load(){

    /* 16 skips the header stuff */
    int location = 16;
    // Lets go ahead and skip the crap -> (Elecbyte signature and version) start at the 16th byte
    ifile.seekg(location,ios::beg);
    unsigned long pcxlocation;
    unsigned long txtlocation;
    unsigned long txtsize;

    ifile.read( (char *)&pcxlocation, sizeof(unsigned long) );
    ifile.read( (char *)&pcxsize, sizeof(unsigned long) );
    ifile.read( (char *)&txtlocation, sizeof(unsigned long) );
    ifile.read( (char *)&txtsize, sizeof(unsigned long) );
    Global::debug(1) << "PCX Location: " << pcxlocation << " | PCX Size: " << pcxsize << endl;
    Global::debug(1) << "TXT Location: " << txtlocation << " | TXT Actual location: " << pcxlocation + pcxsize << " | TXT Size: " << txtsize << endl;

    // Get the pcx load our bitmap
    ifile.seekg(pcxlocation,ios::beg);
    pcx = new unsigned char[pcxsize];
    ifile.read((char *)pcx, pcxsize);

    bmp = new Bitmap(Bitmap::memoryPCX((unsigned char*) pcx, pcxsize));

    // Get the text
    ifile.seekg(pcxlocation+pcxsize, ios::beg);
    std::vector<std::string> ourText;
    while( !ifile.eof() ){
	std::string line;
	getline( ifile, line );
	ourText.push_back(line);
    }

    std::vector< MugenSection * > collection = MugenUtil::configReader( ourText );

    for( unsigned int i = 0; i < collection.size(); ++i ){
	const std::string &head = collection[i]->getHeader();
	if( head == "Def" ){
	    while( collection[i]->hasItems() ){
		MugenItemContent *content = collection[i]->getNext();
		const MugenItem *item = content->getNext();
		std::string itemhead = item->query();
		MugenUtil::removeSpaces(itemhead);
		// This is so we don't have any problems with crap like Name, NaMe, naMe or whatever
		MugenUtil::fixCase( itemhead );
		if ( itemhead.find("size")!=std::string::npos ){
		    *content->getNext() >> width;
		    *content->getNext() >> height;
		} else if ( itemhead.find("spacing")!=std::string::npos ){
		    *content->getNext() >> spacingx;
		    *content->getNext() >> spacingy;
		} else if ( itemhead.find("colors")!=std::string::npos ){
		    *content->getNext() >> colors;
		} else if ( itemhead.find("offset")!=std::string::npos ){
		    *content->getNext() >> offsetx;
		    *content->getNext() >> offsety;
		} else if ( itemhead.find("type")!=std::string::npos ){
		    std::string temp;
		    *content->getNext() >> temp;
		    MugenUtil::removeSpaces(temp);
		    MugenUtil::fixCase(temp);
		    if (temp == "variable")type = Variable;
		    else if (temp == "fixed")type = Fixed;
		    Global::debug(1) << "Type: " << temp << endl;
		} //else throw MugenException( "Unhandled option in Info Section: " + itemhead );
	    }
	    Global::debug(1) << "Size X: " << width << ", Size Y: " << height << ", Spacing X: " << spacingx << ", Spacing Y: " << spacingy << ", Colors: " << colors << ", Offset X: " << offsetx << ", Offset Y: " << offsety << endl;
	}
	if( head == "Map" ){
	    bool beginParse = false;
	    int locationx = 0;
	    for (std::vector<std::string>::iterator l = ourText.begin(); l != ourText.end(); ++l){
		std::string line = *l;
		if (!beginParse){
		    if (line.find("[Map]")==std::string::npos){
			continue;
		    } else{
			beginParse = true;
			continue;
		    }
		}
		MugenItemContent *opt = getOpts(line);
		std::string character;
		int startx = locationx * width;
		int chrwidth = width;
		*opt->getNext() >> character;
		if( character != "empty" ) {
		    if (character == "0x5b") character = "[";
		    else if (character == "0x3b") character = ";";
		    if (type != Fixed){
			// get other two
			*opt->getNext() >> startx;
			*opt->getNext() >> chrwidth;
		    }
		    FontLocation loc;
		    loc.startx = startx;
		    loc.width = chrwidth;
		    char code = character[0];
		    Global::debug(1) << "Storing Character: " << code << " | startx: " << loc.startx << " | width: " << loc.width << endl;
		    positions[code] = loc;
		}
		delete opt;
		++locationx;
	    }
	}
    }

    // Time to get rid of collection
    for( std::vector< MugenSection * >::iterator i = collection.begin() ; i != collection.end() ; ++i ){
        if(*i)delete (*i);
    }

    ifile.close();

}

<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "apic_timer.hpp"
#include "apic.hpp"
#include "pit.hpp"
#include <kernel/irq_manager.hpp>
#include <kernel/timers.hpp>
#include <smp>
#include <cstdio>
#include <info>

#define TIMER_ONESHOT     0x0
#define TIMER_PERIODIC    0x20000
#define TIMER_DEADLINE    0x40000

// vol 3a  10-10
#define DIVIDE_BY_16     0x3

#define CALIBRATION_MS   125

using namespace std::chrono;

namespace x86
{
  // calculated once on BSP
  static uint32_t ticks_per_micro = 0;

  struct alignas(SMP_ALIGN) timer_data
  {
    bool intr_enabled = false;

  };
  static std::array<timer_data, SMP_MAX_CORES> timerdata;

  #define GET_TIMER() PER_CPU(timerdata)

  void APIC_Timer::init()
  {
    // initialize timer system
    Timers::init(
        oneshot, // timer start function
        stop);   // timer stop function

    // initialize local APIC timer
    APIC::get().timer_init();
  }
  void APIC_Timer::calibrate()
  {
    init();

    if (ticks_per_micro != 0) {
      // make sure timers are delay-initalized
      const auto irq = LAPIC_IRQ_TIMER;
      IRQ_manager::get().subscribe(irq, start_timers);
      // soft-trigger IRQ immediately
      IRQ_manager::get().register_irq(irq);
      return;
    }

    // start timer (unmask)
    INFO("APIC", "Measuring APIC timer...");

    auto& lapic = APIC::get();
    // See: Vol3a 10.5.4.1 TSC-Deadline Mode
    // 0xFFFFFFFF --> ~68 seconds
    // 0xFFFFFF   --> ~46 milliseconds
    lapic.timer_begin(0xFFFFFFFF);
    // measure function call and tick read overhead
    uint32_t overhead;
    [&overhead] {
        overhead = APIC::get().timer_diff();
    }();
    // restart counter
    lapic.timer_begin(0xFFFFFFFF);

    /// use PIT to measure <time> in one-shot ///
    PIT::instance().on_timeout_ms(milliseconds(CALIBRATION_MS),
    [overhead] {
      uint32_t diff = APIC::get().timer_diff() - overhead;
      assert(ticks_per_micro == 0);
      // measure difference
      ticks_per_micro = diff / CALIBRATION_MS / 1000;
      // stop APIC timer
      APIC::get().timer_interrupt(false);

      //printf("* APIC timer: ticks %ums: %u\t 1mi: %u\n",
      //       CALIBRATION_MS, diff, ticks_per_micro);
      start_timers();

      // with SMP, signal everyone else too (IRQ 1)
      if (SMP::cpu_count() > 1) {
        APIC::get().bcast_ipi(0x21);
      }
    });
  }

  void APIC_Timer::start_timers() noexcept
  {
    assert(ready());
    // set interrupt handler
    IRQ_manager::get().subscribe(LAPIC_IRQ_TIMER, Timers::timers_handler);
    // start all timers
    Timers::ready();
  }

  bool APIC_Timer::ready() noexcept
  {
    return ticks_per_micro != 0;
  }

  void APIC_Timer::oneshot(std::chrono::microseconds micros) noexcept
  {
    // prevent overflow
    uint64_t ticks = micros.count() * ticks_per_micro;
    if (ticks > 0xFFFFFFFF) ticks = 0xFFFFFFFF;

    // set initial counter
    auto& lapic = APIC::get();
    lapic.timer_begin(ticks);
    // re-enable interrupts if disabled
    if (GET_TIMER().intr_enabled == false) {
      GET_TIMER().intr_enabled = true;
      lapic.timer_interrupt(true);
    }
  }
  void APIC_Timer::stop() noexcept
  {
    GET_TIMER().intr_enabled = false;
    APIC::get().timer_interrupt(false);
  }

  // used by soft-reset
  uint32_t apic_timer_get_ticks() noexcept
  {
    return ticks_per_micro;
  }
  void     apic_timer_set_ticks(uint32_t tpm) noexcept
  {
    ticks_per_micro = tpm;
  }
}
<commit_msg>x86: Delay-start timers to prevent OS::block loop<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "apic_timer.hpp"
#include "apic.hpp"
#include "pit.hpp"
#include <kernel/irq_manager.hpp>
#include <kernel/timers.hpp>
#include <smp>
#include <cstdio>
#include <info>

#define TIMER_ONESHOT     0x0
#define TIMER_PERIODIC    0x20000
#define TIMER_DEADLINE    0x40000

// vol 3a  10-10
#define DIVIDE_BY_16     0x3

#define CALIBRATION_MS   125

using namespace std::chrono;

namespace x86
{
  // calculated once on BSP
  static uint32_t ticks_per_micro = 0;

  struct alignas(SMP_ALIGN) timer_data
  {
    bool intr_enabled = false;

  };
  static std::array<timer_data, SMP_MAX_CORES> timerdata;

  #define GET_TIMER() PER_CPU(timerdata)

  void APIC_Timer::init()
  {
    // initialize timer system
    Timers::init(
        oneshot, // timer start function
        stop);   // timer stop function

    // initialize local APIC timer
    APIC::get().timer_init();
  }
  void APIC_Timer::calibrate()
  {
    init();

    if (ticks_per_micro != 0) {
      // make sure timers are delay-initalized
      const auto irq = LAPIC_IRQ_TIMER;
      IRQ_manager::get().subscribe(irq, start_timers);
      // soft-trigger IRQ immediately
      IRQ_manager::get().register_irq(irq);
      return;
    }

    // start timer (unmask)
    INFO("APIC", "Measuring APIC timer...");

    auto& lapic = APIC::get();
    // See: Vol3a 10.5.4.1 TSC-Deadline Mode
    // 0xFFFFFFFF --> ~68 seconds
    // 0xFFFFFF   --> ~46 milliseconds
    lapic.timer_begin(0xFFFFFFFF);
    // measure function call and tick read overhead
    uint32_t overhead;
    [&overhead] {
        overhead = APIC::get().timer_diff();
    }();
    // restart counter
    lapic.timer_begin(0xFFFFFFFF);

    /// use PIT to measure <time> in one-shot ///
    PIT::instance().on_timeout_ms(milliseconds(CALIBRATION_MS),
    [overhead] {
      uint32_t diff = APIC::get().timer_diff() - overhead;
      assert(ticks_per_micro == 0);
      // measure difference
      ticks_per_micro = diff / CALIBRATION_MS / 1000;
      // stop APIC timer
      APIC::get().timer_interrupt(false);

      //printf("* APIC timer: ticks %ums: %u\t 1mi: %u\n",
      //       CALIBRATION_MS, diff, ticks_per_micro);
      start_timers();

      // with SMP, signal everyone else too (IRQ 1)
      if (SMP::cpu_count() > 1) {
        APIC::get().bcast_ipi(0x21);
      }
    });
  }

  void APIC_Timer::start_timers() noexcept
  {
    assert(ready());
    // set interrupt handler
    IRQ_manager::get().subscribe(LAPIC_IRQ_TIMER, Timers::timers_handler);
    // delay-start all timers
    auto irq = IRQ_manager::get().get_free_irq();
    IRQ_manager::get().subscribe(irq, Timers::ready);
    IRQ_manager::get().register_irq(irq);
  }

  bool APIC_Timer::ready() noexcept
  {
    return ticks_per_micro != 0;
  }

  void APIC_Timer::oneshot(std::chrono::microseconds micros) noexcept
  {
    // prevent overflow
    uint64_t ticks = micros.count() * ticks_per_micro;
    if (ticks > 0xFFFFFFFF) ticks = 0xFFFFFFFF;

    // set initial counter
    auto& lapic = APIC::get();
    lapic.timer_begin(ticks);
    // re-enable interrupts if disabled
    if (GET_TIMER().intr_enabled == false) {
      GET_TIMER().intr_enabled = true;
      lapic.timer_interrupt(true);
    }
  }
  void APIC_Timer::stop() noexcept
  {
    GET_TIMER().intr_enabled = false;
    APIC::get().timer_interrupt(false);
  }

  // used by soft-reset
  uint32_t apic_timer_get_ticks() noexcept
  {
    return ticks_per_micro;
  }
  void     apic_timer_set_ticks(uint32_t tpm) noexcept
  {
    ticks_per_micro = tpm;
  }
}
<|endoftext|>


<commit_before>#include "pixelboost/file/fileHelpers.h"

#include "pixelboost/graphics/device/device.h"
#include "pixelboost/graphics/device/indexBuffer.h"
#include "pixelboost/graphics/device/texture.h"
#include "pixelboost/graphics/device/vertexBuffer.h"
#include "pixelboost/graphics/helper/screenHelpers.h"
#include "pixelboost/graphics/render/font/fontRenderer.h"

using namespace pixelboost;

FontRenderer::FontRenderer(int maxCharacters)
    : _MaxCharacters(maxCharacters)
{
    _IndexBuffer = GraphicsDevice::Instance()->CreateIndexBuffer(kBufferFormatStatic, _MaxCharacters*6);
    _VertexBuffer = GraphicsDevice::Instance()->CreateVertexBuffer(kBufferFormatStatic, kVertexFormat_P_XYZ_UV, _MaxCharacters*4);

    _IndexBuffer->Lock();

    unsigned short* indices = _IndexBuffer->GetData();
    for (int i=0; i<_MaxCharacters; i++)
    {
        indices[0] = (i*4);
        indices[1] = (i*4)+1;
        indices[2] = (i*4)+2;
        indices[3] = (i*4);
        indices[4] = (i*4)+2;
        indices[5] = (i*4)+3;
        indices += 6;
    }

    _IndexBuffer->Unlock();
}

FontRenderer::~FontRenderer()
{
    GraphicsDevice::Instance()->DestroyIndexBuffer(_IndexBuffer);
    GraphicsDevice::Instance()->DestroyVertexBuffer(_VertexBuffer);

    for (FontMap::iterator it = _Fonts.begin(); it != _Fonts.end(); ++it)
    {
        delete it->second;
    }
}

void FontRenderer::AddCharacter(Vertex_PXYZ_UV* buffer, const Font::Character& character, float offset, float baseline)
{
    float xOffset = character.xOffset;
    float yOffset = -character.yOffset + baseline;

    buffer[0].position[0] = offset + xOffset;
    buffer[0].position[1] = yOffset - character.height;
    buffer[0].uv[0] = character.uvx;
    buffer[0].uv[1] = character.uvy + character.uvv;
    buffer[1].position[0] = offset + xOffset;
    buffer[1].position[1] = yOffset;
    buffer[1].uv[0] = character.uvx;
    buffer[1].uv[1] = character.uvy;
    buffer[2].position[0] = offset + character.width + xOffset;
    buffer[2].position[1] = yOffset;
    buffer[2].uv[0] = character.uvx + character.uvu;
    buffer[2].uv[1] = character.uvy;
    buffer[3].position[0] = offset + character.width + xOffset;
    buffer[3].position[1] = yOffset - character.height;
    buffer[3].uv[0] = character.uvx + character.uvu;
    buffer[3].uv[1] = character.uvy + character.uvv;
}

void FontRenderer::LoadFont(const std::string& name)
{
    Font* font = new Font();

    std::string fileRoot = FileHelpers::GetRootPath();

    std::string fntFilename = fileRoot + "/data/fonts/" + name + (ScreenHelpers::IsHighResolution() ? "-hd" : "") + ".fnt";

    std::string fontContents = FileHelpers::FileToString(fntFilename);

    std::vector<std::string> lines;
    SplitString(fontContents, '\n', lines);

    for (std::vector<std::string>::iterator line = lines.begin(); line != lines.end(); ++line)
    {
        std::vector<std::string> elements;
        SplitString(*line, ' ', elements);

        if (elements.size() < 1 )
            continue;

        std::map<std::string, std::string> data;
        for (std::vector<std::string>::iterator element = elements.begin(); element != elements.end(); ++element)
        {
            data[element->substr(0, element->find('='))] = element->substr(element->find('=')+1);
        }

        std::string elementType = elements[0];

        Vec2 texSize;

        if (elementType == "info")
        {
            int size = (int)atoi(data["size"].c_str());

            font->size = size;
        } else if (elementType == "common")
        {
            int lineHeight = (int)atoi(data["lineHeight"].c_str());
            int base = (int)atoi(data["base"].c_str());
            int scaleW = (int)atoi(data["scaleW"].c_str());
            int scaleH = (int)atoi(data["scaleH"].c_str());

            font->base = (float)base / (float)scaleH;
            font->lineHeight = (float)lineHeight / (float)scaleH;
            texSize = Vec2(scaleW, scaleH);
        } else if (elementType == "page")
        {
            std::string texFilename = fileRoot + "/data/fonts/" + data["file"].substr(1, data["file"].find('"', 1)-1);
            font->texture = GraphicsDevice::Instance()->CreateTexture();
            font->texture->Load(texFilename, true);
        } else if (elementType == "char")
        {
            Font::Character character;

            char charCode = (char)atoi(data["id"].c_str());
            int x = (int)atoi(data["x"].c_str());
            int y = (int)atoi(data["y"].c_str());
            int width = (int)atoi(data["width"].c_str());
            int height = (int)atoi(data["height"].c_str());
            int xoffset = (int)atoi(data["xoffset"].c_str());
            int yoffset = (int)atoi(data["yoffset"].c_str());
            int xadvance = (int)atoi(data["xadvance"].c_str());

            character.width = width/(float)font->size;
            character.height = height/(float)font->size;
            character.uvx = x/texSize[0];
            character.uvy = y/texSize[1];
            character.uvu = width/texSize[0];
            character.uvv = height/texSize[1];
            character.xOffset = xoffset/(float)font->size;
            character.yOffset = yoffset/(float)font->size;
            character.xAdvance = xadvance/(float)font->size;

            font->chars[charCode] = character;
        } else if (elementType == "kerning")
        {
            char charOne = (char)atoi(data["first"].c_str());
            char charTwo = (char)atoi(data["second"].c_str());
            int amount = (int)atoi(data["amount"].c_str());

            font->kerning[std::pair<char, char>(charOne, charTwo)] = amount/texSize[0];
        }
    }

    _Fonts[name] = font;
}

void FontRenderer::Update(float time)
{
    _Instances.clear();
}

void FontRenderer::Render(RenderLayer* layer)
{
    InstanceList& instances = _Instances[layer];

    if (instances.size() == 0)
        return;

    glDisable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glEnable(GL_TEXTURE_2D);

#ifndef PIXELBOOST_GRAPHICS_PREMULTIPLIED_ALPHA
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#else
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
#endif

    glDisableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    _IndexBuffer->Bind();

    for (InstanceList::iterator it = instances.begin(); it != instances.end(); ++it)
    {
        Font* font;

        FontMap::iterator fontIt = _Fonts.find(it->_Font);
        if (fontIt == _Fonts.end())
            continue;

        font = fontIt->second;

        _VertexBuffer->Lock();

        Vertex_PXYZ_UV* vertexBuffer = static_cast<Vertex_PXYZ_UV*>(_VertexBuffer->GetData());

        float offset = 0.f;
        for (int i=0; i<it->_String.length(); i++)
        {
            std::map<char, Font::Character>::iterator charIt = font->chars.find(it->_String[i]);

            if (charIt == font->chars.end())
                continue;

            AddCharacter(vertexBuffer, charIt->second, offset, font->base);

            vertexBuffer += 4;

            offset += charIt->second.xAdvance;

            if (i<it->_String.length()-1)
            {
                std::map<std::pair<char, char>, float>::iterator kerningIt = font->kerning.find(std::pair<char, char>(it->_String[i], it->_String[i+1]));

                if (kerningIt != font->kerning.end())
                    offset += kerningIt->second;
            }
        }

        _VertexBuffer->Unlock();

        _VertexBuffer->Bind();

        font->texture->Bind(0);

        glPushMatrix();

        glTranslatef(it->_Position[0], it->_Position[1], 0.f);

        glRotatef(it->_Rotation, 0, 0, 1);

        float scale = (it->_Size/(float)font->size) * ((float)font->size/(float)pixelboost::ScreenHelpers::GetDpu());

        glScalef(scale, scale, 1.f);

        switch (it->_Alignment) {
            case kFontAlignLeft:
                break;
            case kFontAlignCenter:
                glTranslatef(-offset/2.f, 0, 0);
                break;
            case kFontAlignRight:
                glTranslatef(-offset, 0, 0);
                break;
        }

        GraphicsDevice::Instance()->DrawElements(GraphicsDevice::kElementTriangles, it->_String.length()*6);

        glPopMatrix();
    }

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    GraphicsDevice::Instance()->BindIndexBuffer(0);
    GraphicsDevice::Instance()->BindVertexBuffer(0);

    glDisable(GL_BLEND);
    glDisable(GL_TEXTURE_2D);
}

bool FontRenderer::AttachToRenderer(RenderLayer* layer, const std::string& fontName, const std::string& string, Vec2 position, FontAlign alignment, float size, float rotation, Vec4 color)
{
    FontInstance instance;

    instance._Font = fontName;
    instance._String = string;
    instance._Position = position;
    instance._Alignment = alignment;
    instance._Rotation = rotation;
    instance._Size = size;
    instance._Color = color;

    _Instances[layer].push_back(instance);

    return true;
}

void FontRenderer::SplitString(const std::string& string, char seperator, std::vector<std::string>& output)
{
    std::string item;

    for (int i=0; i<string.length(); i++)
    {
        char ch=string[i];

        if (ch == seperator)
        {
            if (!item.empty())
            {
                output.push_back(item);
            }
            item = "";
        }
        else
        {
            item += ch;
        }
    }
    if (!item.empty())
    {
        output.push_back(item);
    }
}
<commit_msg>Use units for fonts rather than points<commit_after>#include "pixelboost/file/fileHelpers.h"

#include "pixelboost/graphics/device/device.h"
#include "pixelboost/graphics/device/indexBuffer.h"
#include "pixelboost/graphics/device/texture.h"
#include "pixelboost/graphics/device/vertexBuffer.h"
#include "pixelboost/graphics/helper/screenHelpers.h"
#include "pixelboost/graphics/render/font/fontRenderer.h"

using namespace pixelboost;

FontRenderer::FontRenderer(int maxCharacters)
    : _MaxCharacters(maxCharacters)
{
    _IndexBuffer = GraphicsDevice::Instance()->CreateIndexBuffer(kBufferFormatStatic, _MaxCharacters*6);
    _VertexBuffer = GraphicsDevice::Instance()->CreateVertexBuffer(kBufferFormatStatic, kVertexFormat_P_XYZ_UV, _MaxCharacters*4);

    _IndexBuffer->Lock();

    unsigned short* indices = _IndexBuffer->GetData();
    for (int i=0; i<_MaxCharacters; i++)
    {
        indices[0] = (i*4);
        indices[1] = (i*4)+1;
        indices[2] = (i*4)+2;
        indices[3] = (i*4);
        indices[4] = (i*4)+2;
        indices[5] = (i*4)+3;
        indices += 6;
    }

    _IndexBuffer->Unlock();
}

FontRenderer::~FontRenderer()
{
    GraphicsDevice::Instance()->DestroyIndexBuffer(_IndexBuffer);
    GraphicsDevice::Instance()->DestroyVertexBuffer(_VertexBuffer);

    for (FontMap::iterator it = _Fonts.begin(); it != _Fonts.end(); ++it)
    {
        delete it->second;
    }
}

void FontRenderer::AddCharacter(Vertex_PXYZ_UV* buffer, const Font::Character& character, float offset, float baseline)
{
    float xOffset = character.xOffset;
    float yOffset = -character.yOffset + baseline;

    buffer[0].position[0] = offset + xOffset;
    buffer[0].position[1] = yOffset - character.height;
    buffer[0].uv[0] = character.uvx;
    buffer[0].uv[1] = character.uvy + character.uvv;
    buffer[1].position[0] = offset + xOffset;
    buffer[1].position[1] = yOffset;
    buffer[1].uv[0] = character.uvx;
    buffer[1].uv[1] = character.uvy;
    buffer[2].position[0] = offset + character.width + xOffset;
    buffer[2].position[1] = yOffset;
    buffer[2].uv[0] = character.uvx + character.uvu;
    buffer[2].uv[1] = character.uvy;
    buffer[3].position[0] = offset + character.width + xOffset;
    buffer[3].position[1] = yOffset - character.height;
    buffer[3].uv[0] = character.uvx + character.uvu;
    buffer[3].uv[1] = character.uvy + character.uvv;
}

void FontRenderer::LoadFont(const std::string& name)
{
    Font* font = new Font();

    std::string fileRoot = FileHelpers::GetRootPath();

    std::string fntFilename = fileRoot + "/data/fonts/" + name + (ScreenHelpers::IsHighResolution() ? "-hd" : "") + ".fnt";

    std::string fontContents = FileHelpers::FileToString(fntFilename);

    std::vector<std::string> lines;
    SplitString(fontContents, '\n', lines);

    for (std::vector<std::string>::iterator line = lines.begin(); line != lines.end(); ++line)
    {
        std::vector<std::string> elements;
        SplitString(*line, ' ', elements);

        if (elements.size() < 1 )
            continue;

        std::map<std::string, std::string> data;
        for (std::vector<std::string>::iterator element = elements.begin(); element != elements.end(); ++element)
        {
            data[element->substr(0, element->find('='))] = element->substr(element->find('=')+1);
        }

        std::string elementType = elements[0];

        Vec2 texSize;

        if (elementType == "info")
        {
            int size = (int)atoi(data["size"].c_str());

            font->size = size;
        } else if (elementType == "common")
        {
            int lineHeight = (int)atoi(data["lineHeight"].c_str());
            int base = (int)atoi(data["base"].c_str());
            int scaleW = (int)atoi(data["scaleW"].c_str());
            int scaleH = (int)atoi(data["scaleH"].c_str());

            font->base = (float)base/(float)font->size;
            font->lineHeight = (float)lineHeight / (float)scaleH;
            texSize = Vec2(scaleW, scaleH);
        } else if (elementType == "page")
        {
            std::string texFilename = fileRoot + "/data/fonts/" + data["file"].substr(1, data["file"].find('"', 1)-1);
            font->texture = GraphicsDevice::Instance()->CreateTexture();
            font->texture->Load(texFilename, true);
        } else if (elementType == "char")
        {
            Font::Character character;

            char charCode = (char)atoi(data["id"].c_str());
            int x = (int)atoi(data["x"].c_str());
            int y = (int)atoi(data["y"].c_str());
            int width = (int)atoi(data["width"].c_str());
            int height = (int)atoi(data["height"].c_str());
            int xoffset = (int)atoi(data["xoffset"].c_str());
            int yoffset = (int)atoi(data["yoffset"].c_str());
            int xadvance = (int)atoi(data["xadvance"].c_str());

            character.width = width/(float)font->size;
            character.height = height/(float)font->size;
            character.uvx = x/texSize[0];
            character.uvy = y/texSize[1];
            character.uvu = width/texSize[0];
            character.uvv = height/texSize[1];
            character.xOffset = xoffset/(float)font->size;
            character.yOffset = yoffset/(float)font->size;
            character.xAdvance = xadvance/(float)font->size;

            font->chars[charCode] = character;
        } else if (elementType == "kerning")
        {
            char charOne = (char)atoi(data["first"].c_str());
            char charTwo = (char)atoi(data["second"].c_str());
            int amount = (int)atoi(data["amount"].c_str());

            font->kerning[std::pair<char, char>(charOne, charTwo)] = amount/texSize[0];
        }
    }

    _Fonts[name] = font;
}

void FontRenderer::Update(float time)
{
    _Instances.clear();
}

void FontRenderer::Render(RenderLayer* layer)
{
    InstanceList& instances = _Instances[layer];

    if (instances.size() == 0)
        return;

    glDisable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glEnable(GL_TEXTURE_2D);

#ifndef PIXELBOOST_GRAPHICS_PREMULTIPLIED_ALPHA
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#else
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
#endif

    glDisableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    _IndexBuffer->Bind();

    for (InstanceList::iterator it = instances.begin(); it != instances.end(); ++it)
    {
        Font* font;

        FontMap::iterator fontIt = _Fonts.find(it->_Font);
        if (fontIt == _Fonts.end())
            continue;

        font = fontIt->second;

        _VertexBuffer->Lock();

        Vertex_PXYZ_UV* vertexBuffer = static_cast<Vertex_PXYZ_UV*>(_VertexBuffer->GetData());

        float offset = 0.f;
        for (int i=0; i<it->_String.length(); i++)
        {
            std::map<char, Font::Character>::iterator charIt = font->chars.find(it->_String[i]);

            if (charIt == font->chars.end())
                continue;

            AddCharacter(vertexBuffer, charIt->second, offset, font->base);

            vertexBuffer += 4;

            offset += charIt->second.xAdvance;

            if (i<it->_String.length()-1)
            {
                std::map<std::pair<char, char>, float>::iterator kerningIt = font->kerning.find(std::pair<char, char>(it->_String[i], it->_String[i+1]));

                if (kerningIt != font->kerning.end())
                    offset += kerningIt->second;
            }
        }

        _VertexBuffer->Unlock();

        _VertexBuffer->Bind();

        font->texture->Bind(0);

        glPushMatrix();

        glTranslatef(it->_Position[0], it->_Position[1], 0.f);

        glRotatef(it->_Rotation, 0, 0, 1);

        glScalef(it->_Size, it->_Size, 1.f);

        switch (it->_Alignment) {
            case kFontAlignLeft:
                break;
            case kFontAlignCenter:
                glTranslatef(-offset/2.f, 0, 0);
                break;
            case kFontAlignRight:
                glTranslatef(-offset, 0, 0);
                break;
        }

        GraphicsDevice::Instance()->DrawElements(GraphicsDevice::kElementTriangles, it->_String.length()*6);

        glPopMatrix();
    }

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    GraphicsDevice::Instance()->BindIndexBuffer(0);
    GraphicsDevice::Instance()->BindVertexBuffer(0);

    glDisable(GL_BLEND);
    glDisable(GL_TEXTURE_2D);
}

bool FontRenderer::AttachToRenderer(RenderLayer* layer, const std::string& fontName, const std::string& string, Vec2 position, FontAlign alignment, float size, float rotation, Vec4 color)
{
    FontInstance instance;

    instance._Font = fontName;
    instance._String = string;
    instance._Position = position;
    instance._Alignment = alignment;
    instance._Rotation = rotation;
    instance._Size = size;
    instance._Color = color;

    _Instances[layer].push_back(instance);

    return true;
}

void FontRenderer::SplitString(const std::string& string, char seperator, std::vector<std::string>& output)
{
    std::string item;

    for (int i=0; i<string.length(); i++)
    {
        char ch=string[i];

        if (ch == seperator)
        {
            if (!item.empty())
            {
                output.push_back(item);
            }
            item = "";
        }
        else
        {
            item += ch;
        }
    }
    if (!item.empty())
    {
        output.push_back(item);
    }
}
<|endoftext|>


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

#include "content/nw/src/browser/menubar_view.h"

#include "content/nw/src/browser/menubar_controller.h"
#include "ui/base/models/menu_model.h"
#include "ui/base/window_open_disposition.h"
#include "ui/gfx/text_elider.h"
#include "ui/views/controls/button/menu_button.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/widget/widget.h"

using views::MenuRunner;

#if !defined(OS_WIN)
static const gfx::ElideBehavior kElideBehavior = gfx::FADE_TAIL;
#else
// Windows fade eliding causes text to darken; see http://crbug.com/388084
static const gfx::ElideBehavior kElideBehavior = gfx::ELIDE_TAIL;
#endif

namespace nw {

const char MenuBarView::kViewClassName[] = "BookmarkBarView";

// MenuBarButton  -------------------------------------------------------

// Buttons used on the menu bar. Copied from BookmarkFolderButton

class MenuBarButton : public views::MenuButton {
 public:
  MenuBarButton(const base::string16& title,
                views::MenuButtonListener* menu_button_listener,
                bool show_menu_marker)
      : MenuButton(title, menu_button_listener, show_menu_marker) {
    SetElideBehavior(kElideBehavior);
  }

  bool GetTooltipText(const gfx::Point& p,
                              base::string16* tooltip) const override {
    if (label()->GetPreferredSize().width() > label()->size().width())
      *tooltip = GetText();
    return !tooltip->empty();
  }

 private:

  DISALLOW_COPY_AND_ASSIGN(MenuBarButton);
};

MenuBarView::MenuBarView() {
  SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
}

MenuBarView::~MenuBarView() {
}

void MenuBarView::UpdateMenu(ui::MenuModel* model) {
  RemoveAllChildViews(true);
  InitView(model);
  Layout();
  PreferredSizeChanged();
  SchedulePaint();
}

void MenuBarView::InitView(ui::MenuModel* model) {
  model_ = model;
  for (int i = 0; i < model_->GetItemCount(); i++) {
    AddChildView(new MenuBarButton(model_->GetLabelAt(i), this, false));
  }
}

bool MenuBarView::GetMenuButtonAtLocation(const gfx::Point& loc, ui::MenuModel** model, views::MenuButton** button) {
  if (!model_)
    return false;
  if (loc.x() < 0 || loc.x() >= width() || loc.y() < 0 || loc.y() >= height())
    return false;
  for (int i = 0; i < model_->GetItemCount(); i++) {
    views::View* child = child_at(i);
    if (child->bounds().Contains(loc) &&
        (model_->GetTypeAt(i) == ui::MenuModel::TYPE_SUBMENU)) {
      *model = model_->GetSubmenuModelAt(i);
      *button = static_cast<views::MenuButton*>(child);
      return true;
    }
  }
  return false;
}

void MenuBarView::OnMenuButtonClicked(views::MenuButton* view,
                                          const gfx::Point& point,
                                          const ui::Event* event) {
  int button_index = GetIndexOf(view);
  DCHECK_NE(-1, button_index);
  ui::MenuModel::ItemType type = model_->GetTypeAt(button_index);
  if (type == ui::MenuModel::TYPE_SUBMENU) {
    MenuBarController* controller = new MenuBarController(this, model_->GetSubmenuModelAt(button_index), NULL);
    controller->RunMenuAt(view, point);
  }
}

void MenuBarView::ButtonPressed(views::Button* sender,
                                const ui::Event& event) {
}

void MenuBarView::OnNativeThemeChanged(const ui::NativeTheme* theme) {
  set_background(views::Background::CreateSolidBackground(GetNativeTheme()->
       GetSystemColor(ui::NativeTheme::kColorId_MenuBackgroundColor)));
}

} //namespace nw
<commit_msg>[linux] fixed foreground colors for menubar<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/nw/src/browser/menubar_view.h"

#include "content/nw/src/browser/menubar_controller.h"
#include "ui/base/models/menu_model.h"
#include "ui/base/window_open_disposition.h"
#include "ui/gfx/text_elider.h"
#include "ui/views/controls/button/menu_button.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/widget/widget.h"

using views::MenuRunner;

#if !defined(OS_WIN)
static const gfx::ElideBehavior kElideBehavior = gfx::FADE_TAIL;
#else
// Windows fade eliding causes text to darken; see http://crbug.com/388084
static const gfx::ElideBehavior kElideBehavior = gfx::ELIDE_TAIL;
#endif

namespace nw {

const char MenuBarView::kViewClassName[] = "BookmarkBarView";

// MenuBarButton  -------------------------------------------------------

// Buttons used on the menu bar. Copied from BookmarkFolderButton

class MenuBarButton : public views::MenuButton {
 public:
  MenuBarButton(const base::string16& title,
                views::MenuButtonListener* menu_button_listener,
                bool show_menu_marker)
      : MenuButton(title, menu_button_listener, show_menu_marker) {
    SetElideBehavior(kElideBehavior);
  }

  bool GetTooltipText(const gfx::Point& p,
                              base::string16* tooltip) const override {
    if (label()->GetPreferredSize().width() > label()->size().width())
      *tooltip = GetText();
    return !tooltip->empty();
  }

  void OnNativeThemeChanged(const ui::NativeTheme* theme) override {
    views::MenuButton::OnNativeThemeChanged(theme);
    SetEnabledTextColors(theme->GetSystemColor(ui::NativeTheme::kColorId_EnabledMenuItemForegroundColor));
  }

 private:

  DISALLOW_COPY_AND_ASSIGN(MenuBarButton);
};

MenuBarView::MenuBarView() {
  SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
}

MenuBarView::~MenuBarView() {
}

void MenuBarView::UpdateMenu(ui::MenuModel* model) {
  RemoveAllChildViews(true);
  InitView(model);
  Layout();
  PreferredSizeChanged();
  SchedulePaint();
}

void MenuBarView::InitView(ui::MenuModel* model) {
  model_ = model;
  for (int i = 0; i < model_->GetItemCount(); i++) {
    AddChildView(new MenuBarButton(model_->GetLabelAt(i), this, false));
  }
}

bool MenuBarView::GetMenuButtonAtLocation(const gfx::Point& loc, ui::MenuModel** model, views::MenuButton** button) {
  if (!model_)
    return false;
  if (loc.x() < 0 || loc.x() >= width() || loc.y() < 0 || loc.y() >= height())
    return false;
  for (int i = 0; i < model_->GetItemCount(); i++) {
    views::View* child = child_at(i);
    if (child->bounds().Contains(loc) &&
        (model_->GetTypeAt(i) == ui::MenuModel::TYPE_SUBMENU)) {
      *model = model_->GetSubmenuModelAt(i);
      *button = static_cast<views::MenuButton*>(child);
      return true;
    }
  }
  return false;
}

void MenuBarView::OnMenuButtonClicked(views::MenuButton* view,
                                          const gfx::Point& point,
                                          const ui::Event* event) {
  int button_index = GetIndexOf(view);
  DCHECK_NE(-1, button_index);
  ui::MenuModel::ItemType type = model_->GetTypeAt(button_index);
  if (type == ui::MenuModel::TYPE_SUBMENU) {
    MenuBarController* controller = new MenuBarController(this, model_->GetSubmenuModelAt(button_index), NULL);
    controller->RunMenuAt(view, point);
  }
}

void MenuBarView::ButtonPressed(views::Button* sender,
                                const ui::Event& event) {
}

void MenuBarView::OnNativeThemeChanged(const ui::NativeTheme* theme) {
  // Use menu background color for menubar
  set_background(views::Background::CreateSolidBackground(theme->
       GetSystemColor(ui::NativeTheme::kColorId_MenuBackgroundColor)));
  // Force to repaint the menubar
  SchedulePaint();
}

} //namespace nw
<|endoftext|>


<commit_before>/*---------------------------------------------------------------
 * Copyright (c) 1999,2000,2001,2002,2003
 * The Board of Trustees of the University of Illinois
 * All Rights Reserved.
 *---------------------------------------------------------------
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software (Iperf) and associated
 * documentation files (the "Software"), to deal in the Software
 * without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to permit
 * persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 *
 *
 * Redistributions of source code must retain the above
 * copyright notice, this list of conditions and
 * the following disclaimers.
 *
 *
 * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following
 * disclaimers in the documentation and/or other materials
 * provided with the distribution.
 *
 *
 * Neither the names of the University of Illinois, NCSA,
 * nor the names of its contributors may be used to endorse
 * or promote products derived from this Software without
 * specific prior written permission.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * ________________________________________________________________
 * National Laboratory for Applied Network Research
 * National Center for Supercomputing Applications
 * University of Illinois at Urbana-Champaign
 * http://www.ncsa.uiuc.edu
 * ________________________________________________________________
 * main.cpp
 * by Mark Gates <mgates@nlanr.net>
 * &  Ajay Tirumala <tirumala@ncsa.uiuc.edu>
 * -------------------------------------------------------------------
 * main does initialization and creates the various objects that will
 * actually run the iperf program, then waits in the Joinall().
 * -------------------------------------------------------------------
 * headers
 * uses
 *   <stdlib.h>
 *   <string.h>
 *
 *   <signal.h>
 * ------------------------------------------------------------------- */

#define HEADERS()

#include "headers.h"

#include "Client.hpp"
#include "Settings.hpp"
#include "Listener.hpp"
#include "Speaker.hpp"
#include "Locale.hpp"
#include "Condition.hpp"
#include "List.h"
#include "util.h"
//#include "oml_orbit_winlab_iperf.h"

#include <oml2/omlc.h>
#include <ocomm/o_log.h>
OmlMP* tcp_measure;
OmlMP* udp_measure;
OmlMP* peer_information;
static OmlMPDef tcp_receiverport[] = {
  {"ID", OML_LONG_VALUE},
  {"Begin_interval", OML_DOUBLE_VALUE},
  {"End_interval", OML_DOUBLE_VALUE},
  {"Transfer", OML_DOUBLE_VALUE},
  {"Bandwidth", OML_DOUBLE_VALUE},
  {NULL, (OmlValueT)0}
};
static OmlMPDef udp_receiverport[] = {
  {"ID", OML_LONG_VALUE},
  {"Begin_interval", OML_DOUBLE_VALUE},
  {"End_interval", OML_DOUBLE_VALUE},
  {"Transfer", OML_DOUBLE_VALUE},
  {"Bandwidth", OML_DOUBLE_VALUE},
  {"Jitter", OML_DOUBLE_VALUE},
  {"Packet_Lost", OML_LONG_VALUE},
  {"Total_Packet", OML_LONG_VALUE},
  {"PLR", OML_DOUBLE_VALUE},
  {NULL, (OmlValueT)0}
};
static OmlMPDef peer_info[] = {
  {"ID", OML_LONG_VALUE},
  {"local_address", OML_STRING_VALUE},
  {"local_port", OML_LONG_VALUE},
  {"foreign_address", OML_STRING_VALUE},
  {"foreign_port", OML_LONG_VALUE},
  {NULL, (OmlValueT)0}
};

#ifdef WIN32
    #include "service.h"
#endif

/* -------------------------------------------------------------------
 * prototypes
 * ------------------------------------------------------------------- */

void waitUntilQuit( void );

void sig_quit( int inSigno );

void cleanup( void );

/* -------------------------------------------------------------------
 * global variables
 * ------------------------------------------------------------------- */
#define GLOBAL()

Condition gQuit_cond;

/* -------------------------------------------------------------------
 * sets up signal handlers
 * parses settings from environment and command line
 * starts up server or client thread
 * waits for all threads to complete
 * ------------------------------------------------------------------- */

int main( int argc,  char *argv[] ) {

#ifdef WIN32
    SERVICE_TABLE_ENTRY dispatchTable[] =
    {
        { TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)service_main},
        { NULL, NULL}
    };
#endif

    omlc_init("iperf", &argc,  (const char**) argv, NULL);

    printf("ADD MP \n");
    tcp_measure = omlc_add_mp("TCP_received", tcp_receiverport);
    udp_measure = omlc_add_mp("UDP_received", udp_receiverport);
    peer_information = omlc_add_mp("Peer_Info", peer_info);

    Listener *theListener = NULL;
    Speaker  *theSpeaker  = NULL;

    // signal handlers quietly exit on ^C and kill
    // these are usually remapped later by the client or server
    my_signal( SIGTERM, sig_exit );
    my_signal( SIGINT,  sig_exit );

#ifndef WIN32
    signal(SIGPIPE,SIG_IGN);
#else
    WSADATA wsaData;
    int rc = WSAStartup( 0x202, &wsaData );
    FAIL_errno( rc == SOCKET_ERROR, "WSAStartup" );

    SetConsoleCtrlHandler( sig_dispatcher, true );
#endif

    // perform any cleanup when quitting Iperf
    atexit( cleanup );

    ext_Settings* ext_gSettings = new ext_Settings;
    Settings* gSettings = NULL;

    // read settings from environment variables and command-line interface
    gSettings = new Settings( ext_gSettings );
    gSettings->ParseEnvironment();
    gSettings->ParseCommandLine( argc, argv );

    // start up client or server (listener)
    if ( gSettings->GetServerMode() == kMode_Server ) {
        // start up a listener
        theListener = new Listener( ext_gSettings );
        theListener->DeleteSelfAfterRun();

        // Start the server as a daemon
        if ( gSettings->GetDaemonMode() == true ) {
#ifdef WIN32
            CmdInstallService(argc, argv);
            DELETE_PTR( theListener );
            DELETE_PTR( gSettings );

            return 0;
#else
            theListener->runAsDaemon(argv[0],LOG_DAEMON);
#endif
        }
#ifdef WIN32
          else {
            if ( gSettings->GetRemoveService() == true ) {
                // remove the service and continue to run as a normal process
                if ( CmdRemoveService() ) {
                    printf("IPerf Service is removed.\n");

                    DELETE_PTR( theListener );
                    DELETE_PTR( gSettings );

                    return 0;
                }
            } else {
                // try to start the service
                if ( CmdStartService(argc, argv) ) {
                    printf("IPerf Service already exists.\n");

                    DELETE_PTR( theListener );
                    DELETE_PTR( gSettings );

                    return 0;
                }
            }
        }
#endif
        omlc_start();
        theListener->Start();

        if ( ext_gSettings->mThreads == 0 ) {
            theListener->SetDaemon();

            // the listener keeps going; we terminate on user input only
            waitUntilQuit();
#ifdef HAVE_THREAD
            if ( Thread::NumUserThreads() > 0 ) {
                printf( wait_server_threads );
                fflush( 0 );
            }
#endif
        }
    } else if ( gSettings->GetServerMode() == kMode_Client ) {
#ifdef HAVE_THREAD
        theSpeaker = new Speaker(ext_gSettings);
        theSpeaker->OwnSettings();
        theSpeaker->DeleteSelfAfterRun();
        omlc_start();
        theSpeaker->Start();
#else
        // If we need to start up a listener do it now
        ext_Settings *temp = NULL;
        Settings::GenerateListenerSettings( ext_gSettings, &temp );
        if ( temp != NULL ) {
            theListener = new Listener( temp );
            theListener->DeleteSelfAfterRun();
        }
        Client* theClient = new Client( ext_gSettings );
        omlc_start();
        theClient->InitiateServer();
        theClient->Start();
        if ( theListener != NULL ) {
            theListener->Start();
        }
#endif
    } else {
        // neither server nor client mode was specified
        // print usage and exit

#ifdef WIN32

        // starting the service by SCM, there is no arguments will be passed in.
        // the arguments will pass into Service_Main entry.

        if ( !StartServiceCtrlDispatcher(dispatchTable) )
            printf(usage_short, argv[0], argv[0]);
#else
        printf( usage_short, argv[0], argv[0] );
#endif
    }

    // wait for other (client, server) threads to complete
    Thread::Joinall();
    DELETE_PTR( gSettings );  // modified by qfeng
    // all done!
    return 0;
} // end main

/* -------------------------------------------------------------------
 * Blocks the thread until a quit thread signal is sent
 * ------------------------------------------------------------------- */

void waitUntilQuit( void ) {
#ifdef HAVE_THREAD

    // signal handlers send quit signal on ^C and kill
    gQuit_cond.Lock();
    my_signal( SIGTERM, sig_quit );
    my_signal( SIGINT,  sig_quit );

#ifdef HAVE_USLEEP

    // this sleep is a hack to get around an apparent bug? in IRIX
    // where pthread_cancel doesn't work unless the thread
    // starts up before the gQuit_cand.Wait() call below.
    // A better solution is to just use sigwait here, but
    // then I have to emulate that for Windows...
    usleep( 10 );
#endif

    // wait for quit signal
    gQuit_cond.Wait();
    gQuit_cond.Unlock();
#endif
} // end waitUntilQuit

/* -------------------------------------------------------------------
 * Sends a quit thread signal to let the main thread quit nicely.
 * ------------------------------------------------------------------- */

void sig_quit( int inSigno ) {
#ifdef HAVE_THREAD

    // if we get a second signal after 1/10 second, exit
    // some implementations send the signal to all threads, so the 1/10 sec
    // allows us to ignore multiple receipts of the same signal
    static Timestamp* first = NULL;
    if ( first != NULL ) {
        Timestamp now;
        if ( now.subSec( *first ) > 0.1 ) {
            sig_exit( inSigno );
        }
    } else {
        first = new Timestamp();
    }

    // with threads, send a quit signal
    gQuit_cond.Signal();

#else

    // without threads, just exit quietly, same as sig_exit()
    sig_exit( inSigno );

#endif
} // end sig_quit

/* -------------------------------------------------------------------
 * Any necesary cleanup before Iperf quits. Called at program exit,
 * either by exit() or terminating main().
 * ------------------------------------------------------------------- */

void cleanup( void ) {
#ifdef WIN32
    WSACleanup();
#endif
    extern Iperf_ListEntry *clients;
    Iperf_destroy ( &clients );

} // end cleanup

#ifdef WIN32
/*--------------------------------------------------------------------
 * ServiceStart
 *
 * each time starting the service, this is the entry point of the service.
 * Start the service, certainly it is on server-mode
 *
 *
 *-------------------------------------------------------------------- */
VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv) {
    Listener *theListener = NULL;

    // report the status to the service control manager.
    //
    if ( !ReportStatusToSCMgr(
                             SERVICE_START_PENDING, // service state
                             NO_ERROR,              // exit code
                             3000) )                 // wait hint
        goto clean;

    ext_Settings* ext_gSettings = new ext_Settings;
    Settings *gSettings;

    // read settings from passing by StartService
    gSettings = new Settings( ext_gSettings );
    gSettings->ParseEnvironment();
    gSettings->ParseCommandLine( dwArgc, lpszArgv );

    // report the status to the service control manager.
    //
    if ( !ReportStatusToSCMgr(
                             SERVICE_START_PENDING, // service state
                             NO_ERROR,              // exit code
                             3000) )                 // wait hint
        goto clean;

    // if needed, redirect the output into a specified file
    if ( gSettings->GetFileOutput() ) {
        redirect(gSettings->GetOutputFileName());
    }

    // report the status to the service control manager.
    //
    if ( !ReportStatusToSCMgr(
                             SERVICE_START_PENDING, // service state
                             NO_ERROR,              // exit code
                             3000) )                 // wait hint
        goto clean;

    theListener = new Listener( ext_gSettings );

    theListener->Start();
    theListener->SetDaemon();

    // report the status to the service control manager.
    //
    if ( !ReportStatusToSCMgr(
                             SERVICE_RUNNING,       // service state
                             NO_ERROR,              // exit code
                             0) )                    // wait hint
        goto clean;

    // the listener keeps going; we terminate on user input only
    waitUntilQuit();
#ifdef HAVE_THREAD
    if ( Thread::NumUserThreads() > 0 ) {
        printf( wait_server_threads );
        fflush( 0 );
    }
#endif

    clean:
    // wait for other (client, server) threads to complete
    Thread::Joinall();
    DELETE_PTR( theListener );
    DELETE_PTR( gSettings );  // modified by qfeng
    DELETE_PTR( ext_gSettings );  // modified by qfeng
}

//
//  FUNCTION: ServiceStop
//
//  PURPOSE: Stops the service
//
//  PARAMETERS:
//    none
//
//  RETURN VALUE:
//    none
//
//  COMMENTS:
//    If a ServiceStop procedure is going to
//    take longer than 3 seconds to execute,
//    it should spawn a thread to execute the
//    stop code, and return.  Otherwise, the
//    ServiceControlManager will believe that
//    the service has stopped responding.
//
VOID ServiceStop() {
#ifdef HAVE_THREAD
    gQuit_cond.Signal();
#else
    sig_exit(1);
#endif
}

#endif

<commit_msg>new iperf version with more comprehensible names of MPs<commit_after>/*---------------------------------------------------------------
 * Copyright (c) 1999,2000,2001,2002,2003
 * The Board of Trustees of the University of Illinois
 * All Rights Reserved.
 *---------------------------------------------------------------
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software (Iperf) and associated
 * documentation files (the "Software"), to deal in the Software
 * without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to permit
 * persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 *
 *
 * Redistributions of source code must retain the above
 * copyright notice, this list of conditions and
 * the following disclaimers.
 *
 *
 * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following
 * disclaimers in the documentation and/or other materials
 * provided with the distribution.
 *
 *
 * Neither the names of the University of Illinois, NCSA,
 * nor the names of its contributors may be used to endorse
 * or promote products derived from this Software without
 * specific prior written permission.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * ________________________________________________________________
 * National Laboratory for Applied Network Research
 * National Center for Supercomputing Applications
 * University of Illinois at Urbana-Champaign
 * http://www.ncsa.uiuc.edu
 * ________________________________________________________________
 * main.cpp
 * by Mark Gates <mgates@nlanr.net>
 * &  Ajay Tirumala <tirumala@ncsa.uiuc.edu>
 * -------------------------------------------------------------------
 * main does initialization and creates the various objects that will
 * actually run the iperf program, then waits in the Joinall().
 * -------------------------------------------------------------------
 * headers
 * uses
 *   <stdlib.h>
 *   <string.h>
 *
 *   <signal.h>
 * ------------------------------------------------------------------- */

#define HEADERS()

#include "headers.h"

#include "Client.hpp"
#include "Settings.hpp"
#include "Listener.hpp"
#include "Speaker.hpp"
#include "Locale.hpp"
#include "Condition.hpp"
#include "List.h"
#include "util.h"
//#include "oml_orbit_winlab_iperf.h"

#include <oml2/omlc.h>
#include <ocomm/o_log.h>
OmlMP* tcp_measure;
OmlMP* udp_measure;
OmlMP* peer_information;
static OmlMPDef tcp_receiverport[] = {
  {"ID", OML_LONG_VALUE},
  {"Begin_interval", OML_DOUBLE_VALUE},
  {"End_interval", OML_DOUBLE_VALUE},
  {"Transfer", OML_DOUBLE_VALUE},
  {"Bandwidth", OML_DOUBLE_VALUE},
  {NULL, (OmlValueT)0}
};
static OmlMPDef udp_receiverport[] = {
  {"ID", OML_LONG_VALUE},
  {"Begin_interval", OML_DOUBLE_VALUE},
  {"End_interval", OML_DOUBLE_VALUE},
  {"Transfer", OML_DOUBLE_VALUE},
  {"Bandwidth", OML_DOUBLE_VALUE},
  {"Jitter", OML_DOUBLE_VALUE},
  {"Packet_Lost", OML_LONG_VALUE},
  {"Total_Packet", OML_LONG_VALUE},
  {"PLR", OML_DOUBLE_VALUE},
  {NULL, (OmlValueT)0}
};
static OmlMPDef peer_info[] = {
  {"ID", OML_LONG_VALUE},
  {"local_address", OML_STRING_VALUE},
  {"local_port", OML_LONG_VALUE},
  {"foreign_address", OML_STRING_VALUE},
  {"foreign_port", OML_LONG_VALUE},
  {NULL, (OmlValueT)0}
};

#ifdef WIN32
    #include "service.h"
#endif

/* -------------------------------------------------------------------
 * prototypes
 * ------------------------------------------------------------------- */

void waitUntilQuit( void );

void sig_quit( int inSigno );

void cleanup( void );

/* -------------------------------------------------------------------
 * global variables
 * ------------------------------------------------------------------- */
#define GLOBAL()

Condition gQuit_cond;

/* -------------------------------------------------------------------
 * sets up signal handlers
 * parses settings from environment and command line
 * starts up server or client thread
 * waits for all threads to complete
 * ------------------------------------------------------------------- */

int main( int argc,  char *argv[] ) {

#ifdef WIN32
    SERVICE_TABLE_ENTRY dispatchTable[] =
    {
        { TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)service_main},
        { NULL, NULL}
    };
#endif

    omlc_init("iperf", &argc,  (const char**) argv, NULL);

    printf("ADD MP \n");
    peer_information = omlc_add_mp("Peer_Info", peer_info);

    Listener *theListener = NULL;
    Speaker  *theSpeaker  = NULL;

    // signal handlers quietly exit on ^C and kill
    // these are usually remapped later by the client or server
    my_signal( SIGTERM, sig_exit );
    my_signal( SIGINT,  sig_exit );

#ifndef WIN32
    signal(SIGPIPE,SIG_IGN);
#else
    WSADATA wsaData;
    int rc = WSAStartup( 0x202, &wsaData );
    FAIL_errno( rc == SOCKET_ERROR, "WSAStartup" );

    SetConsoleCtrlHandler( sig_dispatcher, true );
#endif

    // perform any cleanup when quitting Iperf
    atexit( cleanup );

    ext_Settings* ext_gSettings = new ext_Settings;
    Settings* gSettings = NULL;

    // read settings from environment variables and command-line interface
    gSettings = new Settings( ext_gSettings );
    gSettings->ParseEnvironment();
    gSettings->ParseCommandLine( argc, argv );

    // start up client or server (listener)
    if ( gSettings->GetServerMode() == kMode_Server ) {
        // start up a listener
        theListener = new Listener( ext_gSettings );
        theListener->DeleteSelfAfterRun();
        if ( gSettings->GetProtocolMode() == false){//UDP
          udp_measure = omlc_add_mp("UDP_Rich_Info", udp_receiverport);
	}
	else{
	  tcp_measure = omlc_add_mp("TCP_Info", tcp_receiverport);
        }

        // Start the server as a daemon
        if ( gSettings->GetDaemonMode() == true ) {
#ifdef WIN32
            CmdInstallService(argc, argv);
            DELETE_PTR( theListener );
            DELETE_PTR( gSettings );

            return 0;
#else
            theListener->runAsDaemon(argv[0],LOG_DAEMON);
#endif
        }
#ifdef WIN32
          else {
            if ( gSettings->GetRemoveService() == true ) {
                // remove the service and continue to run as a normal process
                if ( CmdRemoveService() ) {
                    printf("IPerf Service is removed.\n");

                    DELETE_PTR( theListener );
                    DELETE_PTR( gSettings );

                    return 0;
                }
            } else {
                // try to start the service
                if ( CmdStartService(argc, argv) ) {
                    printf("IPerf Service already exists.\n");

                    DELETE_PTR( theListener );
                    DELETE_PTR( gSettings );

                    return 0;
                }
            }
        }
#endif
        omlc_start();
        theListener->Start();

        if ( ext_gSettings->mThreads == 0 ) {
            theListener->SetDaemon();

            // the listener keeps going; we terminate on user input only
            waitUntilQuit();
#ifdef HAVE_THREAD
            if ( Thread::NumUserThreads() > 0 ) {
                printf( wait_server_threads );
                fflush( 0 );
            }
#endif
        }
    } else if ( gSettings->GetServerMode() == kMode_Client ) {
#ifdef HAVE_THREAD
        theSpeaker = new Speaker(ext_gSettings);
        theSpeaker->OwnSettings();
        theSpeaker->DeleteSelfAfterRun();
        if ( gSettings->GetProtocolMode() == false){//UDP
	  tcp_measure = omlc_add_mp("UDP_Periodic_Info", tcp_receiverport);
          udp_measure = omlc_add_mp("UDP_Rich_Info", udp_receiverport);
	}
	else{//TCP
	  tcp_measure = omlc_add_mp("TCP_Info", tcp_receiverport);
	}
        omlc_start();
        theSpeaker->Start();
#else
        // If we need to start up a listener do it now
        ext_Settings *temp = NULL;
        Settings::GenerateListenerSettings( ext_gSettings, &temp );
        if ( temp != NULL ) {
            theListener = new Listener( temp );
            theListener->DeleteSelfAfterRun();
        }
        Client* theClient = new Client( ext_gSettings );
        omlc_start();
        theClient->InitiateServer();
        theClient->Start();
        if ( theListener != NULL ) {
            theListener->Start();
        }
#endif
    } else {
        // neither server nor client mode was specified
        // print usage and exit

#ifdef WIN32

        // starting the service by SCM, there is no arguments will be passed in.
        // the arguments will pass into Service_Main entry.

        if ( !StartServiceCtrlDispatcher(dispatchTable) )
            printf(usage_short, argv[0], argv[0]);
#else
        printf( usage_short, argv[0], argv[0] );
#endif
    }

    // wait for other (client, server) threads to complete
    Thread::Joinall();
    DELETE_PTR( gSettings );  // modified by qfeng
    // all done!
    return 0;
} // end main

/* -------------------------------------------------------------------
 * Blocks the thread until a quit thread signal is sent
 * ------------------------------------------------------------------- */

void waitUntilQuit( void ) {
#ifdef HAVE_THREAD

    // signal handlers send quit signal on ^C and kill
    gQuit_cond.Lock();
    my_signal( SIGTERM, sig_quit );
    my_signal( SIGINT,  sig_quit );

#ifdef HAVE_USLEEP

    // this sleep is a hack to get around an apparent bug? in IRIX
    // where pthread_cancel doesn't work unless the thread
    // starts up before the gQuit_cand.Wait() call below.
    // A better solution is to just use sigwait here, but
    // then I have to emulate that for Windows...
    usleep( 10 );
#endif

    // wait for quit signal
    gQuit_cond.Wait();
    gQuit_cond.Unlock();
#endif
} // end waitUntilQuit

/* -------------------------------------------------------------------
 * Sends a quit thread signal to let the main thread quit nicely.
 * ------------------------------------------------------------------- */

void sig_quit( int inSigno ) {
#ifdef HAVE_THREAD

    // if we get a second signal after 1/10 second, exit
    // some implementations send the signal to all threads, so the 1/10 sec
    // allows us to ignore multiple receipts of the same signal
    static Timestamp* first = NULL;
    if ( first != NULL ) {
        Timestamp now;
        if ( now.subSec( *first ) > 0.1 ) {
            sig_exit( inSigno );
        }
    } else {
        first = new Timestamp();
    }

    // with threads, send a quit signal
    gQuit_cond.Signal();

#else

    // without threads, just exit quietly, same as sig_exit()
    sig_exit( inSigno );

#endif
} // end sig_quit

/* -------------------------------------------------------------------
 * Any necesary cleanup before Iperf quits. Called at program exit,
 * either by exit() or terminating main().
 * ------------------------------------------------------------------- */

void cleanup( void ) {
#ifdef WIN32
    WSACleanup();
#endif
    extern Iperf_ListEntry *clients;
    Iperf_destroy ( &clients );

} // end cleanup

#ifdef WIN32
/*--------------------------------------------------------------------
 * ServiceStart
 *
 * each time starting the service, this is the entry point of the service.
 * Start the service, certainly it is on server-mode
 *
 *
 *-------------------------------------------------------------------- */
VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv) {
    Listener *theListener = NULL;

    // report the status to the service control manager.
    //
    if ( !ReportStatusToSCMgr(
                             SERVICE_START_PENDING, // service state
                             NO_ERROR,              // exit code
                             3000) )                 // wait hint
        goto clean;

    ext_Settings* ext_gSettings = new ext_Settings;
    Settings *gSettings;

    // read settings from passing by StartService
    gSettings = new Settings( ext_gSettings );
    gSettings->ParseEnvironment();
    gSettings->ParseCommandLine( dwArgc, lpszArgv );

    // report the status to the service control manager.
    //
    if ( !ReportStatusToSCMgr(
                             SERVICE_START_PENDING, // service state
                             NO_ERROR,              // exit code
                             3000) )                 // wait hint
        goto clean;

    // if needed, redirect the output into a specified file
    if ( gSettings->GetFileOutput() ) {
        redirect(gSettings->GetOutputFileName());
    }

    // report the status to the service control manager.
    //
    if ( !ReportStatusToSCMgr(
                             SERVICE_START_PENDING, // service state
                             NO_ERROR,              // exit code
                             3000) )                 // wait hint
        goto clean;

    theListener = new Listener( ext_gSettings );

    theListener->Start();
    theListener->SetDaemon();

    // report the status to the service control manager.
    //
    if ( !ReportStatusToSCMgr(
                             SERVICE_RUNNING,       // service state
                             NO_ERROR,              // exit code
                             0) )                    // wait hint
        goto clean;

    // the listener keeps going; we terminate on user input only
    waitUntilQuit();
#ifdef HAVE_THREAD
    if ( Thread::NumUserThreads() > 0 ) {
        printf( wait_server_threads );
        fflush( 0 );
    }
#endif

    clean:
    // wait for other (client, server) threads to complete
    Thread::Joinall();
    DELETE_PTR( theListener );
    DELETE_PTR( gSettings );  // modified by qfeng
    DELETE_PTR( ext_gSettings );  // modified by qfeng
}

//
//  FUNCTION: ServiceStop
//
//  PURPOSE: Stops the service
//
//  PARAMETERS:
//    none
//
//  RETURN VALUE:
//    none
//
//  COMMENTS:
//    If a ServiceStop procedure is going to
//    take longer than 3 seconds to execute,
//    it should spawn a thread to execute the
//    stop code, and return.  Otherwise, the
//    ServiceControlManager will believe that
//    the service has stopped responding.
//
VOID ServiceStop() {
#ifdef HAVE_THREAD
    gQuit_cond.Signal();
#else
    sig_exit(1);
#endif
}

#endif

<|endoftext|>