/* -*- C++ -*- */ // $Id$ // ============================================================================ // // = LIBRARY // ace // // = FILENAME // Message_Block.h // // = AUTHOR // Doug Schmidt // // ============================================================================ #include "ace/ACE.h" #if !defined (ACE_MESSAGE_BLOCK_H) #define ACE_MESSAGE_BLOCK_H #include "ace/Malloc.h" // Forward declaration. class ACE_Data_Block; class ACE_Lock; class ACE_Time_Value; class ACE_Export ACE_Message_Block { // = TITLE // Stores messages for use throughout ACE (particularly // ). // // = DESCRIPTION // An is modeled after the message data // structures used in System V STREAMS. Its purpose is to // enable efficient manipulation of arbitrarily-large messages // without much incurring memory copying overhead. Here are the // main characteristics of an : // // 1. Contains a pointer to a reference-counted // , which in turn points to the actual data // buffer. This allows very flexible and efficient sharing of // data by multiple s. // // 2. One or more can be linked to form a // ``fragment chain.'' // // 3. can be linked together by and // pointers to form a queue of messages (e.g., this is how // works). public: friend class ACE_Data_Block; enum ACE_Message_Type { // = Data and protocol messages (regular and priority) MB_DATA = 0x01, // regular data MB_PROTO = 0x02, // protocol control // = Control messages (regular and priority) MB_BREAK = 0x03, // line break MB_PASSFP = 0x04, // pass file pointer MB_EVENT = 0x05, // post an event to an event queue MB_SIG = 0x06, // generate process signal MB_IOCTL = 0x07, // ioctl; set/get params MB_SETOPTS = 0x08, // set various stream head options // = Control messages (high priority; go to head of queue) MB_IOCACK = 0x81, // acknowledge ioctl MB_IOCNAK = 0x82, // negative ioctl acknowledge MB_PCPROTO = 0x83, // priority proto message MB_PCSIG = 0x84, // generate process signal MB_READ = 0x85, // generate read notification MB_FLUSH = 0x86, // flush your queues MB_STOP = 0x87, // stop transmission immediately MB_START = 0x88, // restart transmission after stop MB_HANGUP = 0x89, // line disconnect MB_ERROR = 0x8a, // fatal error used to set u.u_error MB_PCEVENT = 0x8b, // post an event to an event queue // Message class masks MB_NORMAL = 0x00, // Normal priority messages MB_PRIORITY = 0x80, // High priority control messages MB_USER = 0x200 // User-defined control messages }; typedef u_long Message_Flags; enum { DONT_DELETE = 01, // Don't delete the data on exit since we don't own it. USER_FLAGS = 0x1000 // user defined flags start here }; // = Initialization and termination. ACE_Message_Block (void); // Create an empty message. ACE_Message_Block (ACE_Data_Block *); // Create an that owns the *. ACE_Message_Block (const char *data, size_t size = 0); // Create a Message Block that assumes ownership of without // copying it (i.e., we don't delete it since we don't malloc it!). // Note that the of the will be , but // the will be 0 until is set. ACE_Message_Block (size_t size, ACE_Message_Type type = MB_DATA, ACE_Message_Block *cont = 0, const char *data = 0, ACE_Allocator *allocator_strategy = 0, ACE_Lock *locking_strategy = 0, u_long priority = 0, const ACE_Time_Value & execution_time = ACE_Time_Value::zero, const ACE_Time_Value & deadline_time = ACE_Time_Value::max_time, ACE_Allocator *data_block_allocator = 0); // Create an initialized message of type containing // bytes. The argument initializes the continuation field in // the . If == 0 then we create and own the // , using to get the data if it's non-0. If // != 0 we assume ownership of the (and don't delete // it). If is non-0 then this is used to protect // regions of code that access shared state (e.g., reference // counting) from race conditions. Note that the of the // will be , but the will be 0 until // is set. // The is use to allocate the data blocks // while the is used to allocate the buffers // contained by those. int init (const char *data, size_t size = 0); // Create a Message Block that assumes ownership of (i.e., // doesn't delete it since it didn't malloc it!). Note that the // of the will be , but the // will be 0 until is set. int init (size_t size, ACE_Message_Type type = MB_DATA, ACE_Message_Block *cont = 0, const char *data = 0, ACE_Allocator *allocator_strategy = 0, ACE_Lock *locking_strategy = 0, u_long priority = 0, const ACE_Time_Value & execution_time = ACE_Time_Value::zero, const ACE_Time_Value & deadline_time = ACE_Time_Value::max_time, ACE_Allocator *data_block_allocator = 0); // Create an initialized message of type containing // bytes. The argument initializes the continuation field in // the . If == 0 then we create and own the // , using to get the data if it's non-0. If // != 0 we assume ownership of the (and don't delete // it). If is non-0 then this is used to protect // regions of code that access shared state (e.g., reference // counting) from race conditions. Note that the of the // will be , but the will be 0 until // is set. // The is use to allocate the data blocks // while the is used to allocate the buffers // contained by those. virtual ~ACE_Message_Block (void); // Delete all the resources held in the message. // = Message Type accessors and mutators. ACE_Message_Type msg_type (void) const; // Get type of the message. void msg_type (ACE_Message_Type type); // Set type of the message. int is_data_msg (void) const; // Find out what type of message this is. ACE_Message_Type msg_class (void) const; // Find out what class of message this is (there are two classes, // messages and messages). // = Message flag accessors and mutators. Message_Flags set_flags (Message_Flags more_flags); // Bitwise-or the into the existing message flags and // return the new value. Message_Flags clr_flags (Message_Flags less_flags); // Clear the message flag bits specified in and return // the new value. Message_Flags flags (void) const; // Get the current message flags. u_long msg_priority (void) const; // Get priority of the message. void msg_priority (u_long priority); // Set priority of the message. const ACE_Time_Value & msg_execution_time (void) const; // Get execution time associated with the message. void msg_execution_time (const ACE_Time_Value & et); // Set execution time associated with the message. const ACE_Time_Value & msg_deadline_time (void) const; // Get absolute time of deadline associated with the message. void msg_deadline_time (const ACE_Time_Value & dt); // Set absolute time of deadline associated with the message. // = Deep copy and shallow copy methods. virtual ACE_Message_Block *clone (Message_Flags mask = 0) const; // Return an exact "deep copy" of the message, i.e., create fresh // new copies of all the Data_Blocks and continuations. ACE_Message_Block *duplicate (void) const; // Return a "shallow" copy that increments our reference count by 1. static ACE_Message_Block *duplicate (const ACE_Message_Block *mb); // Return a "shallow" copy that increments our reference count by 1. // This is similar to CORBA's <_duplicate> method, which is useful // if you want to eliminate lots of checks for NULL pointers // before calling <_duplicate> on them. ACE_Message_Block *release (void); // Decrease the shared ACE_Data_Block's reference count by 1. If the // ACE_Data_Block's reference count goes to 0, it is deleted. // In all cases, this ACE_Message_Block is deleted - it must have come // from the heap, or there will be trouble. static ACE_Message_Block *release (ACE_Message_Block *mb); // This behaves like the non-static method , except that it // checks if is 0. This is similar to , which // is useful if you want to eliminate lots of checks for NULL // pointers before calling on them. Returns . // = Operations on Message data int copy (const char *buf, size_t n); // Copies bytes from into the Message_Block starting at // the wr_ptr() offset. Return 0 if succeeds and -1 if the size of // the message is too small, i.e., for this to work correct, // must be >= . int copy (const char *buf); // Copies into the Message_Block starting at the wr_ptr() // offset. This call assumees that is NUL-terminated. Return // 0 if succeeds and -1 if the size of the message is too small... char *base (void) const; // Get message data. void base (char *data, size_t size, Message_Flags = DONT_DELETE); // Set message data (doesn't reallocate). char *end (void) const; // Return a pointer to 1 past the end of the data in a message. char *rd_ptr (void) const; // Get the read pointer. void rd_ptr (char *ptr); // Set the read pointer to . void rd_ptr (size_t n); // Set the read pointer ahead bytes. char *wr_ptr (void) const; // Get the write pointer. void wr_ptr (char *ptr); // Set the write pointer to . void wr_ptr (size_t n); // Set the write pointer ahead bytes. This is used to compute // the of a message. // = Message length is wr_ptr() - rd_ptr (). size_t length (void) const; // Get the length of the message void length (size_t n); // Set the length of the message // = Message size is the total amount of space alloted. size_t size (void) const; // Get the total amount of space in the message. int size (size_t length); // Set the total amount of space in the message, reallocating space // if necessary. However, the and remain at the // original offsets into the buffer, even if it is reallocated. // Returns 0 if successful, else -1. size_t space (void) const; // Get the amount of space remaining in the message. // = methods. ACE_Data_Block *data_block (void) const; // Get the data block. void data_block (ACE_Data_Block *); // Set the data block (releasing the original one). // = The continuation field chains together composite messages. ACE_Message_Block *cont (void) const; // Get the continuation field. void cont (ACE_Message_Block *); // Set the continuation field. // = Pointer to the directly ahead in the . ACE_Message_Block *next (void) const; // Get link to next message. void next (ACE_Message_Block *); // Set link to next message. // = Pointer to the directly behind in the . ACE_Message_Block *prev (void) const; // Get link to prev message. void prev (ACE_Message_Block *); // Set link to prev message. // = The locking strategy prevents race conditions. ACE_Lock *locking_strategy (void); // Get the locking strategy. ACE_Lock *locking_strategy (ACE_Lock *); // Set a new locking strategy and return the hold one. void dump (void) const; // Dump the state of an object. ACE_ALLOC_HOOK_DECLARE; // Declare the dynamic allocation hooks. private: // = Internal initialization methods. ACE_Message_Block (size_t size, ACE_Message_Type type, ACE_Message_Block *cont, const char *data, ACE_Allocator *allocator_strategy, ACE_Lock *locking_strategy, Message_Flags flags, u_long priority, const ACE_Time_Value & execution_time, const ACE_Time_Value & deadline_time, ACE_Data_Block *db, ACE_Allocator *data_block_allocator); // Perform the actual initialization. ACE_Message_Block *release_i (ACE_Lock *lock); // Internal release implementation int init_i (size_t size, ACE_Message_Type type, ACE_Message_Block *cont, const char *data, ACE_Allocator *allocator_strategy, ACE_Lock *locking_strategy, Message_Flags flags, u_long priority, const ACE_Time_Value & execution_time, const ACE_Time_Value & deadline_time, ACE_Data_Block *db, ACE_Allocator *data_block_allocator); // Perform the actual initialization. char *rd_ptr_; // Pointer to beginning of next read. char *wr_ptr_; // Pointer to beginning of next write. u_long priority_; // Priority of message. ACE_Time_Value execution_time_; // execution time associated with the message ACE_Time_Value deadline_time_; // absolute deadline time for message // = Links to other ACE_Message_Block *s. ACE_Message_Block *cont_; // Pointer to next message block in the chain. ACE_Message_Block *next_; // Pointer to next message in the list. ACE_Message_Block *prev_; // Pointer to previous message in the list. ACE_Data_Block *data_block_; // Pointer to the reference counted data structure that contains the // actual memory buffer. // = Disallow these operations for now (use instead). ACE_Message_Block &operator= (const ACE_Message_Block &); ACE_Message_Block (const ACE_Message_Block &); }; class ACE_Export ACE_Data_Block { // = TITLE // Stores the data payload that is accessed via one or more // s. // // = DESCRIPTION // This data structure is reference counted to maximize // sharing. It also contains the (which // protects the reference count from race conditions in // concurrent programs) and the (which // determines what memory pool is used to allocate the memory). public: // = Initialization and termination methods. ACE_Data_Block (void); // Default "do-nothing" constructor. ACE_Data_Block (size_t size, ACE_Message_Block::ACE_Message_Type msg_type, const char *msg_data, ACE_Allocator *allocator_strategy, ACE_Lock *locking_strategy, ACE_Message_Block::Message_Flags flags, ACE_Allocator *data_block_allocator); // Initialize. virtual ~ACE_Data_Block (void); // Delete all the resources held in the message. ACE_Message_Block::ACE_Message_Type msg_type (void) const; // Get type of the message. void msg_type (ACE_Message_Block::ACE_Message_Type type); // Set type of the message. char *base (void) const; // Get message data pointer void base (char *data, size_t size, ACE_Message_Block::Message_Flags mflags = ACE_Message_Block::DONT_DELETE); // Set message data pointer (doesn't reallocate). char *end (void) const; // Return a pointer to 1 past the end of the data in a message. // = Message size is the total amount of space alloted. size_t size (void) const; // Get the total amount of space in the message. int size (size_t length); // Set the total amount of space in the message. Returns 0 if // successful, else -1. ACE_Data_Block *clone (ACE_Message_Block::Message_Flags mask = 0) const; // Return an exact "deep copy" of the message, i.e., create fresh // new copies of all the Data_Blocks and continuations. ACE_Data_Block *duplicate (void); // Return a "shallow" copy that increments our reference count by 1. ACE_Data_Block *release (ACE_Lock *lock = 0); // Decrease the shared reference count by 1. If the reference count // is > 0 then return this; else if reference count == 0 then delete // and and return 0. Behavior is undefined if reference // count < 0. // = Message flag accessors and mutators. ACE_Message_Block::Message_Flags set_flags (ACE_Message_Block::Message_Flags more_flags); // Bitwise-or the into the existing message flags and // return the new value. ACE_Message_Block::Message_Flags clr_flags (ACE_Message_Block::Message_Flags less_flags); // Clear the message flag bits specified in and return // the new value. ACE_Message_Block::Message_Flags flags (void) const; // Get the current message flags. // = The locking strategy prevents race conditions. ACE_Lock *locking_strategy (void); // Get the locking strategy. ACE_Lock *locking_strategy (ACE_Lock *); // Set a new locking strategy and return the hold one. void dump (void) const; // Dump the state of an object. int reference_count (void) const; // Get the current reference count. ACE_Allocator *data_block_allocator (void); // Get the allocator used to create this object private: ACE_Data_Block *release_i (void); // Internal release implementation ACE_Message_Block::ACE_Message_Type type_; // Type of message. size_t cur_size_; // Current size of message block. size_t max_size_; // Total size of buffer. ACE_Message_Block::Message_Flags flags_; // Misc flags (e.g., DONT_DELETE and USER_FLAGS). char *base_; // Pointer to beginning of message payload. // = Strategies. ACE_Allocator *allocator_strategy_; // Pointer to the allocator defined for this . Note // that this pointer is shared by all owners of this // . ACE_Lock *locking_strategy_; // Pointer to the locking strategy defined for this // . This is used to protect regions of code that // access shared state. Note that this lock is // shared by all owners of the 's data. int reference_count_; // Reference count for this , which is used to avoid // deep copies (i.e., ). Note that this pointer value is // shared by all owners of the 's data, i.e., all the // s. ACE_Allocator *data_block_allocator_; // The allocator use to destroy ourselves. // = Disallow these operations. ACE_Data_Block &operator= (const ACE_Data_Block &); ACE_Data_Block (const ACE_Data_Block &); }; class ACE_Export ACE_Dynamic_Message_Strategy { // = TITLE // An abstract base class which provides dynamic priority evaluation // methods for use by the ACE_Dynamic_Message_Queue class // or any other class which needs to manage the priorities // of a collection of ACE_Message_Blocks dynamically // // = DESCRIPTION // Methods for deadline and laxity based priority evaluation // are provided. These methods assume a specific partitioning // of the message priority number into a higher order dynamic // bit field and a lower order static priority bit field. The // default partitioning assumes an unsigned dynamic message // priority field of 22 bits and an unsigned static message // priority field of 10 bits. This corresponds to the initial // values of the static class members. To provide a different // partitioning, assign a different set of values to the static // class memebers before using the static member functions. public: enum Priority_Status { PENDING = 0x01, // message can still make its deadline LATE = 0x02, // message cannot make its deadline BEYOND_LATE = 0x04, // message is so late its priority is undefined ANY_STATUS = 0x07 // mask to match any priority status }; // message priority status: values are defined as bit flags // so that status combinations may be specified easily. ACE_Dynamic_Message_Strategy (u_long static_bit_field_mask, u_long static_bit_field_shift, u_long dynamic_priority_max, u_long dynamic_priority_offset); // ctor virtual ~ACE_Dynamic_Message_Strategy (); // virtual dtor Priority_Status priority_status (ACE_Message_Block & mb, const ACE_Time_Value & tv); // updates the message's priority and returns its priority status u_long static_bit_field_mask (void); // get static bit field mask void static_bit_field_mask (u_long); // set static bit field mask u_long static_bit_field_shift (void); // get left shift value to make room for static bit field void static_bit_field_shift (u_long); // set left shift value to make room for static bit field u_long dynamic_priority_max (void); // get maximum supported priority value void dynamic_priority_max (u_long); // set maximum supported priority value u_long dynamic_priority_offset (void); // get offset to boundary between signed range and unsigned range void dynamic_priority_offset (u_long); // set offset to boundary between signed range and unsigned range virtual void dump (void) const; // Dump the state of the strategy. protected: virtual void convert_priority (ACE_Time_Value & priority, const ACE_Message_Block & mb) = 0; // hook method for dynamic priority conversion u_long static_bit_field_mask_; // this is a bit mask with all ones in the static bit field u_long static_bit_field_shift_; // this is a left shift value to make room for static bit // field: this value should be the logarithm base 2 of // (static_bit_field_mask_ + 1) u_long dynamic_priority_max_; // maximum supported priority value u_long dynamic_priority_offset_; // offset to boundary between signed range and unsigned range ACE_Time_Value max_late_; // maximum late time value that can be represented ACE_Time_Value min_pending_; // minimum pending time value that can be represented ACE_Time_Value pending_shift_; // time value by which to shift pending priority }; class ACE_Export ACE_Deadline_Message_Strategy : public ACE_Dynamic_Message_Strategy { public: ACE_Deadline_Message_Strategy (u_long static_bit_field_mask = 0x3FFUL, // 2^(10) - 1 u_long static_bit_field_shift = 10, // 10 low order bits u_long dynamic_priority_max = 0x3FFFFFUL, // 2^(22)-1 u_long dynamic_priority_offset = 0x200000UL); // 2^(22-1) // ctor, with all arguments defaulted virtual ~ACE_Deadline_Message_Strategy (); // virtual dtor virtual void convert_priority (ACE_Time_Value & priority, const ACE_Message_Block & mb); // dynamic priority conversion function based on time to deadline virtual void dump (void) const; // Dump the state of the strategy. }; class ACE_Export ACE_Laxity_Message_Strategy : public ACE_Dynamic_Message_Strategy { public: ACE_Laxity_Message_Strategy (u_long static_bit_field_mask = 0x3FFUL, // 2^(10) - 1 u_long static_bit_field_shift = 10, // 10 low order bits u_long dynamic_priority_max = 0x3FFFFFUL, // 2^(22)-1 u_long dynamic_priority_offset = 0x200000UL); // 2^(22-1) // ctor, with all arguments defaulted virtual ~ACE_Laxity_Message_Strategy (); // virtual dtor virtual void convert_priority (ACE_Time_Value & priority, const ACE_Message_Block & mb); // dynamic priority conversion function based on laxity virtual void dump (void) const; // Dump the state of the strategy. }; #if defined (__ACE_INLINE__) #include "ace/Message_Block.i" #endif /* __ACE_INLINE__ */ #endif /* ACE_MESSAGE_BLOCK_H */