Logo Search packages:      
Sourcecode: u++ version File versions

SRC2.cc

//                              -*- Mode: C++ -*- 
// 
// uC++ Version 5.0.1, Copyright (C) Peter A. Buhr 2000
// 
// SRC2.cc -- 
// 
// Author           : Peter A. Buhr
// Created On       : Sun Dec 10 08:44:06 2000
// Last Modified By : Peter A. Buhr
// Last Modified On : Thu Jan  4 17:30:36 2001
// Update Count     : 245
// 

#include <uC++.h>
#include <uOStream.h>
#include <uSequence.h>


uMonitor SRC {
      const unsigned int MaxItems;                                // maximum items in the resource pool
      int Free, Taken;
      bool Locked;                                                            // allocates blocked at this time

      struct Node : public uSeqable {
            unsigned int N;                                                   // allocation request
            uCondition c;                                                     // place to wait until request can be serviced
            Node( unsigned int N ) : N( N ) {}
      } *p;                                                                   // index for searching list of pending requests
      uSequence<Node> list;                                             // list of pending requests
      uSeqGen<Node> gen;                                                      // generator to search list of pending requests

      bool CheckPending();
  public:
      SRC( unsigned int MaxItems );
      ~SRC();
      uNoMutex unsigned int Max();
      void Hold();
      void Resume();
      void Deallocate();
      void Allocate( unsigned int N );
}; // SRC

bool SRC::CheckPending() {
      // While locked, multiple deallocates can occur, so multiple pending
      // requests may be able to be processed. A single pass over the FIFO list
      // is sufficient as Free is strictly decreasing.

      bool flag = false;
      int temp = Free;                                                  // temporary count of free resources
      for ( gen.uOver(list); gen >> p && temp > 0; ) {      // O(N) search
            uCerr << uAcquire << &uThisTask() << " CheckPending, temp:" << temp << " p->N:" << p->N << endl << uRelease;
            if ( p->N <= temp ) {                                       // sufficient resources ?
                  flag = true;
                  temp -= p->N;                                               // reduce temporary number of free resource
                  uSignal p->c;                                               // wake up task waiting in Allocate
            } // if
      } // for
      return flag;
} // SRC::CheckPending

SRC::SRC( unsigned int MaxItems = 5 ) : MaxItems( MaxItems ) {
      Free = MaxItems;
      Taken = 0;
      Locked = false;
      uAcceptReturn( Hold, Allocate, ~SRC );                      // only initial calls allowed
} // SRC::SRC

SRC::~SRC() {
      if ( ! list.uEmpty() ) uAbort( "problem 4" );
} // SRC::SRC

unsigned int SRC::Max() {
      return MaxItems;
} // SRC::Max

void SRC::Hold() {
      uCerr << uAcquire << &uThisTask() << " Hold,       Free:" << Free << " Taken:" << Taken << endl << uRelease;
      Locked = true;
      uAcceptReturn( Resume, Deallocate );
} // SRC::Hold

void SRC::Resume() {
      if ( ! Locked ) uAbort( "problem 1" );                      // Resume call before Hold disallowed
      uCerr << uAcquire << &uThisTask() << " Resume,     Free:" << Free << " Taken:" << Taken << " Waiting:" << list.uEmpty() << endl << uRelease;
      Locked = false;
      if ( ! CheckPending() ) uAcceptReturn( Hold, Deallocate, Allocate, ~SRC ); // check for any pending requests
} // SRC::Resume

void SRC::Deallocate() {
      if ( Taken <= 0 ) uAbort( "problem 2" );
      Free += 1;
      Taken -= 1;
      uAssert( Free >= 0 && Taken <= MaxItems );
      uCerr << uAcquire << &uThisTask() << " Deallocate, Free:" << Free << " Taken:" << Taken << " Locked:" << Locked << " Waiting:" << list.uEmpty() << endl << uRelease;
      if ( Locked ) uAcceptReturn( Resume, Deallocate );
      if ( ! CheckPending() ) uAcceptReturn( Hold, Deallocate, Allocate, ~SRC ); // check for any pending requests
} // SRC::Deallocate

void SRC::Allocate( unsigned int N = 1 ) {
      if ( N > MaxItems ) uAbort( "problem 3" );
      uCerr << uAcquire << &uThisTask() << " Allocate(" << N << "), enter, Free:" << Free << " Taken:" << Taken << " Waiting:" << list.uEmpty() << endl << uRelease;
      if ( N > Free ) {                                                 // insufficient resources ?
            Node n( N );                                                      // storage on stack of blocked task => no dynamic allocation
            list.uAdd( &n );                                            // FIFO order, O(1) operation
            uAcceptWait( Hold, Deallocate, Allocate ) n.c;  // block until sufficient resources
//          uWait n.c;                                                        // block until sufficient resources
            list.uRemove( &n );                                               // O(1) operation
            uCerr << uAcquire << &uThisTask() << " Allocate(" << N << "), after, Free:" << Free << " Taken:" << Taken << " Waiting:" << list.uEmpty() << endl << uRelease;
      } // if
      Free -= N;
      Taken += N;
      uAssert( ! Locked && Free >= 0 && Taken <= MaxItems );
      uCerr << uAcquire << &uThisTask() << " Allocate(" << N << "), exit, Free:" << Free << " Taken:" << Taken << endl << uRelease;
      uAcceptReturn( Hold, Deallocate, Allocate );          // block until sufficient resources
} // SRC::Allocate


SRC src;                                                                      // global: used by all workers

uTask worker {
      void main() {
            for ( int i = 0; i < 20; i += 1 ) {
                  if ( random() % 10 < 2 ) {                            // M out of N calls are Hold/Resume
                        src.Hold();
                        uYield( 50 );                                         // pretend to do something
                        src.Resume();
                  } else {
                        int N = random() % src.Max() + 1;         // values between 1 and Max, inclusive
                        src.Allocate( N );
                        uYield( 3 );                                          // pretend to do something
                        for ( int i = 0; i < N; i += 1 ) {
                              src.Deallocate();
                        } //for
                  } // if
            } // for
            uCerr << uAcquire << &uThisTask() << " worker, exit" << endl << uRelease;
      } // worker::main
}; // worker


void uMain::main() {
      {
            worker workers[10];
      } // wait for workers to complete
      uCerr << uAcquire << "successful completion" << endl << uRelease;
} // uMain::main


// Local Variables: //
// tab-width: 4 //
// compile-command: "u++-work SRC2.cc" //
// End: //

Generated by  Doxygen 1.6.0   Back to index