Česky
Kamil Dudka

Share Library (C++)

File detail

Name:Downloadsharectl.cpp [Download]
Location: sharelib > src > sharectl
Size:8.6 KB
Last modification:2007-08-27 01:16

Source code

/**
 * @file sharectl.cpp
 * @brief Command-line utility manipulating with shared segment
 * @author Kamil Dudka, xdudka00@gmail.com
 * @date 2007-05-15
 * @ingroup sharectl
 */
 
#include "sharectl.h"
#include "SharedSegment.h"
#include "SegmentHeader.h"
 
#include <iostream>
#include <sstream>
 
using namespace Share;
 
int main (int argc, char *argv[])
{
  try {
    SharedSegmentWrapper segment;
 
    // Parse command line arguments
    ArgParser parser (argc, argv);
 
    if (parser.action() == ArgParser::HELP) {
      std::cout <<
        "sharectl SEGMENT_NAME [SWITCH] [...]\n"
        "  --create           Create new shared segment of specified size.\n"
        "  --create-and-wait  Create new shared segment of specified size and wait until key pressed.\n"
        "  --notify-attach    Increase internal reference counter.\n"
        "  --notify-detach    Decrease internal reference counter.\n"
        "  --unlink           Mark segment to be destroyed.\n"
        "  --force-destroy    Destroy segment immediately.\n"
        "  --alloc            Allocate block of specified size inside shared segment.\n"
        "  --free             Free block identified by relative pointer (number)\n";
      return 0;
    }
 
    // Create shared segment or attach to an existing one
    if (parser.isNewSegment())
      segment.create (parser.name(), parser.size());
    else
      segment.attach (parser.name());
 
    // Obtaing attached segment address
    SegmentDebuger debuger (segment.atAddr());
 
    // Handle cmd-line action switch
    switch (parser.action()) {
      case ArgParser::FORCE_DESTORY:
        segment.destroy();
        break;
 
      case ArgParser::ALLOC:
        debuger.alloc(parser.size());
        std::cout << debuger;
        break;
 
      case ArgParser::FREE:
        debuger.free(parser.size());
        std::cout << debuger;
        break;
 
      case ArgParser::CREATE_AND_WAIT: {
          std::cout << "Shared segment created.\n  Waiting. Pres any key to abort.\n";
          char tmp;
          std::cin.read (&tmp, sizeof(char));
          std::cout << debuger;
        }
        break;
 
      case ArgParser::NOTIFY_ATTACH:
      case ArgParser::NOTIFY_DETACH:
      case ArgParser::UNLINK:
        debuger.refCountAction (parser.action());
        // Print statistics after operation
 
      case ArgParser::CREATE:
      case ArgParser::NONE:
        std::cout << debuger;
        if (debuger.shouldBeDestroyed())
          segment.destroy ();
        break;
 
      default:
        throw ShareException("internal exception");
    }
  }
  catch (ShareException e) {
    std::cerr << "sharectl: " << e.message() << std::endl;
    return 1;
  }
}
 
// TODO: Comand-line arguments documentation
ArgParser::ArgParser (int, char *argv[]) throw (ShareException):
  size_(0),
  action_(NONE)
{
  ArgSwitchChecker switchChecker;
 
  // Scan all arguments in loop
  for (char **current = argv + 1; *current; current++) {
    // Obtain current argument
    const char *str = *current;
 
    // Check for --switch
    Action act = switchChecker.checkSwitch (str);
    if (act != NONE) {
      // Accept switch argument
      if (action_ != NONE)
        throw ShareException ("ArgParser: More then one switch - not implemented yet");
 
      action_ = act;
      continue;
    }
 
    if (str[0] == '-') {
      // Decline switch argument
      std::ostringstream stream;
      stream << "ArgParser: Unknown switch: " << str;
      throw ShareException (stream.str().c_str());
    }
 
    // Read size argument
    size_t size;
    std::istringstream stream (str);
    if (stream >> size) {
      if (size_)
        throw ShareException ("ArgParser: More then one numeric argument - not implemented yet");
 
      size_ = size;
      continue;
    }
 
    if (!name_.empty())
      throw ShareException ("ArgParser: More then one string argument - not implemented yet");
 
    // Read name argument
    name_ = str;
  }
 
  switch (action_) {
    case HELP:
      break;
 
    case CREATE:
    case CREATE_AND_WAIT:
    case ALLOC:
    case FREE:
      if (!size_)
        throw ShareException ("ArgParser: Size argument must be given!");
 
    default:
      if (name_.empty())
        throw ShareException ("ArgParser: Name of shared segment must be given!");
  }
}
 
bool ArgParser::isNewSegment()
{
  return
    action_ == CREATE ||
    action_ == CREATE_AND_WAIT;
}
 
const char* ArgParser::name()
{
  return name_.c_str();
}
 
size_t ArgParser::size()
{
  return size_;
}
 
ArgParser::Action ArgParser::action()
{
  return action_;
}
 
ArgSwitchChecker::ArgSwitchChecker()
{
  // Build map
  map_ ["--help"] = ArgParser::HELP;
  map_ ["--usage"] = ArgParser::HELP;
  map_ ["--create"] = ArgParser::CREATE;
  map_ ["--create-and-wait"] = ArgParser::CREATE_AND_WAIT;
  map_ ["--notify-attach"] = ArgParser::NOTIFY_ATTACH;
  map_ ["--notify-detach"] = ArgParser::NOTIFY_DETACH;
  map_ ["--unlink"] = ArgParser::UNLINK;
  map_ ["--force-destroy"] = ArgParser::FORCE_DESTORY;
  map_ ["--alloc"] = ArgParser::ALLOC;
  map_ ["--free"] = ArgParser::FREE;
}
 
ArgSwitchChecker::TAction ArgSwitchChecker::checkSwitch (std::string stringToCheck)
{
  // Map look-up
  TMap::const_iterator i = map_.find (stringToCheck);
  if (i == map_.end())
    return ArgParser::NONE;
  else
    return i->second;
}
 
SharedSegmentWrapper::SharedSegmentWrapper():
  segment_(0)
{
}
 
SharedSegmentWrapper::~SharedSegmentWrapper()
{
  delete segment_;
}
 
void SharedSegmentWrapper::create (const char *name, size_t size) throw (ShareException)
{
  if (segment_)
    throw ShareException("internal exception");
 
  try {
    segment_ = new SharedSegment (name, size);
    ShareManager::instance()-> initDebugMode (segment_);
 
    void *atAddr = segment_ -> atAddress();
    new (atAddr) SegmentHeader (name, size);
  }
  catch (ShareException e) {
    std::cerr << e.message() << std::endl;
    std::ostringstream stream;
    stream << "Unable to create shared segment '" << name << "' of size " << size;
    throw ShareException (stream.str().c_str());
  }
}
 
void SharedSegmentWrapper::attach (const char *name) throw (ShareException)
{
  if (segment_)
    throw ShareException("internal exception");
 
  try {
    segment_ = new SharedSegment (name);
    ShareManager::instance()-> initDebugMode (segment_);
  }
  catch (ShareException e) {
    std::cerr << e.message() << std::endl;
    std::ostringstream stream;
    stream << "Unable to attach shared segment '" << name << "'";
    throw ShareException (stream.str().c_str());
  }
}
 
SegmentHeader* SharedSegmentWrapper::atAddr() throw (ShareException)
{
  if (0 == segment_)
    throw ShareException("internal exception");
 
  return static_cast<SegmentHeader *> (segment_ -> atAddress());
}
 
void SharedSegmentWrapper::destroy()
{
  std::cout << "Attempting to destroy shared segment '" << segment_->name() << "'" << std::endl;
  //segment_ -> destroy();
  ShareManager::instance()-> destroySegment();
}
 
SegmentDebuger::SegmentDebuger (SegmentHeader *segmentManager):
  segmentManager_ (segmentManager)
{
}
 
std::ostream& Share::operator<< (std::ostream &stream, SegmentDebuger &m)
{
  stream << "Shared segment statistics:" << std::endl;
 
  stream << "              Size: " << m.segmentManager_ -> size() << std::endl;
  stream << "         Available: " << m.segmentManager_ -> available() << std::endl;
  stream << "  Current RefCount: " << m.segmentManager_ -> refCount() << std::endl;
  stream << "          Unlinked: " << m.segmentManager_ -> isUnlinked() << std::endl;
 
  return stream;
}
 
void SegmentDebuger::refCountAction (ArgParser::Action action)
{
  switch (action) {
    case ArgParser::NOTIFY_ATTACH:
      std::cout << "Calling SegmentHeader::notifyAttach()" << std::endl;
      segmentManager_ -> notifyAttach();
      break;
 
    case ArgParser::NOTIFY_DETACH:
      std::cout << "Calling SegmentHeader::notifyDetach()" << std::endl;
      segmentManager_ -> notifyDetach();
      break;
 
    case ArgParser::UNLINK:
      std::cout << "Calling SegmentHeader::unlink()" << std::endl;
      segmentManager_ -> unlink();
      break;
 
    default:
      throw ShareException("internal exception");
  }
}
 
bool SegmentDebuger::shouldBeDestroyed()
{
  return segmentManager_ -> shouldBeDestroyed();
}
 
void SegmentDebuger::alloc (size_t size)
{
  std::cout << "Attempting to allocate block of size " << size << std::endl;
  RelocPtr<void> addr = segmentManager_ -> alloc (size);
  std::cout << "Relative address of allocated block is " << addr.toRel() << std::endl;
}
 
void SegmentDebuger::free (size_t relativePointer)
{
  std::cout << "Attempting to free block at relative address " << relativePointer << std::endl;
  typedef RelocPtr<void> TPointer;
  TPointer addr = TPointer::fromRel (relativePointer);
  segmentManager_ -> free (addr);
}