Friday, April 28, 2017

Resource control - rc-03

This program (rc-03) uses the Solaris interface to resource control.
It lists all the controls that are active to its running process.
Following the listing there's a sample output.

#include <rctl.h>
#include <alloca.h>

#include <cstdlib>
#include <cerrno>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <iterator>
#include <sstream>
#include <iostream>
#include <iomanip>

//
// Convenience "special" vector.

//
template< typename T >
struct vector : public std::vector< T >
{
};
 
//
// Convenience operator for just the "special" vector. 
// For simplicity, not dealing with formatting or state issues.
//
template< typename T >
std::istream & operator >> ( std::istream & is, vector<T> & v )
{
  typename vector<T>::value_type element;

  if ( is >> element )
    v.push_back( element );

  return is;
}

//
// The main data structure for organization.
// Key: resource containment.
// Data: list of controls.
//
std::map< const std::string, vector< std::string > > resource;

//

// The resource walking routine.
// 
int active( const char * name, void * )
{
  std::istringstream iss( name );
  std::string containment;

  if ( std::getline( iss, containment, '.' ) )
    iss >> resource[ containment ];

  return 0;
}

const size_t size = ::rctlblk_size( );
typedef ::rctlblk_t * p_blk;

// May suffer from stream formatting issues...
void print_limit( const p_blk rl )
{
  //
  // Type
  //

  std::cout
    << "\t\t"
    << std::setw( 11 ) << std::left;

  switch ( ::rctlblk_get_privilege( rl ) )
  {
      case RCPRIV_BASIC:
          std::cout << "basic";
          break;

      case RCPRIV_PRIVILEGED:
          std::cout << "privileged";
          break;

      case RCPRIV_SYSTEM:
          std::cout << "system";
          break;
  }
 
  //
  // Value
  //

  std::cout
     << ":"
     << std::setw( 21 ) << std::right
     << ::rctlblk_get_value( rl );

  std::cout
     << std::endl; 
 
  std::cout 
     << std::setw( 0 ) << std::left;
}

// May suffer from stream formatting issues... 
void print_control( std::string containment, 
                    vector< std::string > & control_list )

  p_blk rl = static_cast < p_blk >
             (
                 // Never leaks memory
                 ::alloca( size )
             );

  containment += ".";
 
  std::sort( control_list.begin( ), control_list.end( ) );

  for ( auto & control : control_list )
  {
    std::cout
       << "\t";
  
    std::cout
     << std::setw( 32 ) << std::left
     << control;


    const std::string name = containment + control;
   
    p_blk p = 0; // Tracking pointer
    int rv = ::getrctl( name.c_str(), p, rl, RCTL_FIRST );

    const int gflags = ::rctlblk_get_global_flags( rl );
    std::cout
     << std::setw( 9 ) << std::right
     <<
     (
     gflags & RCTL_GLOBAL_BYTES   ? "(bytes)" :
     gflags & RCTL_GLOBAL_SECONDS ? "(seconds)" :
     gflags & RCTL_GLOBAL_COUNT   ? "(count)" :
     "(?)"
     )
     << std::endl;

    std::cout
     << std::setw( 0 ) << std::left;


    while ( rv == 0 )
    {
        print_limit( rl );

        p = rl; // Smart(?) move...
        rv = ::getrctl( name.c_str(), p, rl, RCTL_NEXT );
    }

    if ( errno != ENOENT )
      std::cout
         << "\t\tError getting limits!"
         << std::endl;
   
    std::cout
         << std::endl;
  }
}

// May suffer from stream formatting issues... 
void print( )
{
  std::cout
     << std::endl
     << "Printing active resource controls..."
     << std::endl
     << std::endl;

  // I want to list containments as ordered below
  auto known = { "process", "task", "project", "zone" };

  for ( auto & containment : known )
  {
    std::cout
       << containment
       << std::endl
       << std::endl;
   
    print_control( containment, resource[ containment ] );
  }

  //
  // In case new (currently unknown) containments appear
  // in the future, just list them at the bottom.
  //
  for ( auto & r : resource )
  {
    auto c = r.first; // A containment
    if ( std::none_of( known.begin( ), known.end( ),
            [ &c ]( const char * s ) { return s == c; } ) )
    {
      std::cout
         << c // An unknown containment
         << std::endl
         << std::endl;
     
      print_control( r.first, r.second );
    }
  }
}

// May suffer from stream formatting issues... 
int main( )
{
  std::cout
     << std::endl
     << "Gathering active resource controls..."
     << std::endl
     << std::endl;

  std::cout
     << "\tRC walk starting..."
     << std::endl;

  if ( ::rctl_walk( active, 0 ) == 0 )
    std::cout
     << "\tRC walk completed successfuly!"
     << std::endl;

  print( );

  return EXIT_SUCCESS;
}


A possible output is:

$ ./rc-03

Gathering active resource controls...

    RC walk starting...
    RC walk completed successfuly!

Printing active resource controls...


process

    max-address-space             (bytes)
        privileged : 18446744073709551615
        system     : 18446744073709551615

    max-core-size                 (bytes)
        privileged :  9223372036854775807
        system     :  9223372036854775807

    max-cpu-time                (seconds)
        privileged : 18446744073709551615
        system     : 18446744073709551615

    max-data-size                 (bytes)
        privileged : 18446744073709551615
        system     : 18446744073709551615

    max-deferred-posts            (count)
        basic      :                   32
        privileged :                  100
        system     :                 8192

    max-file-descriptor           (count)
        basic      :                 1024
        privileged :                65536
        system     :           2147483647

    max-file-size                 (bytes)
        privileged :  9223372036854775807
        system     :  9223372036854775807

    max-itimers                   (count)
        privileged :                 1000
        system     :                65536

    max-msg-messages              (count)
        privileged :                 8192
        system     :           4294967295

    max-msg-qbytes                (bytes)
        privileged :                65536
        system     : 18446744073709551615

    max-port-events               (count)
        privileged :                65536
        system     :           2147483647

    max-sem-nsems                 (count)
        privileged :                  512
        system     :                32767

    max-sem-ops                   (count)
        privileged :                  512
        system     :           2147483647

    max-sigqueue-size             (count)
        basic      :                  128
        privileged :                  512
        system     :                 8192

    max-stack-size                (bytes)
        basic      :              8388608
        privileged :        1098437885952
        system     :        1098437885952

task

    max-cpu-time                (seconds)
        system     : 18446744073709551615

    max-lwps                      (count)
        system     :           2147483647

    max-processes                 (count)
        system     :           2147483647

project

    cpu-cap                       (count)
        system     :           4294967295

    cpu-shares                    (count)
        privileged :                    1
        system     :                65535

    max-contracts                 (count)
        privileged :                10000
        system     :           2147483647

    max-crypto-memory             (bytes)
        privileged :           2143089664
        system     : 18446744073709551615

    max-locked-memory             (bytes)
        system     : 18446744073709551615

    max-lwps                      (count)
        system     :           2147483647

    max-mrp-ids                   (count)
        privileged :                  128
        system     :             16777216

    max-msg-ids                   (count)
        privileged :                  128
        system     :             16777216

    max-port-ids                  (count)
        privileged :                 8192
        system     :                65536

    max-processes                 (count)
        system     :           2147483647

    max-sem-ids                   (count)
        privileged :                  128
        system     :             16777216

    max-shm-ids                   (count)
        privileged :                  128
        system     :             16777216

    max-shm-memory                (bytes)
        privileged :           2143089664
        system     : 18446744073709551615

    max-tasks                     (count)
        system     :           2147483647

zone

    cpu-cap                       (count)
        system     :           4294967295

    cpu-shares                    (count)
        privileged :                    1
        system     :                65535

    max-locked-memory             (bytes)
        system     : 18446744073709551615

    max-lofi                      (count)
        system     : 18446744073709551615

    max-lwps                      (count)
        system     :           2147483647

    max-mrp-ids                   (count)
        system     :             16777216

    max-msg-ids                   (count)
        system     :             16777216

    max-processes                 (count)
        system     :           2147483647

    max-sem-ids                   (count)
        system     :             16777216

    max-shm-ids                   (count)
        system     :             16777216

    max-shm-memory                (bytes)
        system     : 18446744073709551615

    max-swap                      (bytes)
        system     : 18446744073709551615