// -*- C++ -*- //========================================================================== /** * @file Message_Block.h * * $Id$ * * @author Douglas C. Schmidt */ //========================================================================== #ifndef ACE_MESSAGE_BLOCK_H #define ACE_MESSAGE_BLOCK_H #include /**/ "ace/pre.h" #include "ace/config-lite.h" #include "ace/ACE_export.h" #if !defined (ACE_LACKS_PRAGMA_ONCE) # pragma once #endif /* ACE_LACKS_PRAGMA_ONCE */ #include "ace/Default_Constants.h" #include "ace/Global_Macros.h" #include "ace/Time_Value.h" #include // Forward declaration. class ACE_Allocator; class ACE_Data_Block; class ACE_Lock; /** * @class ACE_Message_Block * * @brief Stores messages for use throughout ACE (particularly * in an ACE_Message_Queue). * * An ACE_Message_Block is modeled after the message data * structures used in System V STREAMS. Its purpose is to * enable efficient manipulation of arbitrarily large messages * without incurring much memory copying overhead. Here are the * main characteristics of an ACE_Message_Block: * - Contains a pointer to a reference-counted * ACE_Data_Block, which in turn points to the actual data * buffer. This allows very flexible and efficient sharing of * data by multiple ACE_Message_Block objects. * - One or more ACE_Message_Blocks can be linked to form a * ``fragment chain.'' * - ACE_Message_Blocks can be linked together in a doubly linked fashion * to form a queue of messages (this is how ACE_Message_Queue works). * * @see C++NPv1, section 4.2; APG, section 12.3.2. */ class ACE_Export ACE_Message_Block { public: friend class ACE_Data_Block; enum { // = Data and proto /// Undifferentiated data message MB_DATA = 0x01, /// Undifferentiated protocol control MB_PROTO = 0x02, // = Control messages /// Line break (regular and priority) MB_BREAK = 0x03, /// Pass file pointer MB_PASSFP = 0x04, /// Post an event to an event queue MB_EVENT = 0x05, /// Generate process signal MB_SIG = 0x06, /// ioctl; set/get params MB_IOCTL = 0x07, /// Set various stream head options MB_SETOPTS = 0x08, // = Control messages /// Acknowledge ioctl (high priority; go to head of queue) MB_IOCACK = 0x81, /// Negative ioctl acknowledge MB_IOCNAK = 0x82, /// Priority proto message MB_PCPROTO = 0x83, /// Generate process signal MB_PCSIG = 0x84, /// Generate read notification MB_READ = 0x85, /// Flush your queues MB_FLUSH = 0x86, /// Stop transmission immediately MB_STOP = 0x87, /// Restart transmission after stop MB_START = 0x88, /// Line disconnect MB_HANGUP = 0x89, /// Fatal error used to set u.u_error MB_ERROR = 0x8a, /// Post an event to an event queue MB_PCEVENT = 0x8b, // = Message class masks /// Normal priority message mask MB_NORMAL = 0x00, /// High priority control message mask MB_PRIORITY = 0x80, /// User-defined message mask MB_USER = 0x200 }; typedef int ACE_Message_Type; typedef unsigned long Message_Flags; enum { /// Don't delete the data on exit since we don't own it. DONT_DELETE = 01, /// user defined flags start here USER_FLAGS = 0x1000 }; // = Initialization and termination. /// Create an empty message. ACE_Message_Block (ACE_Allocator *message_block_allocator = 0); /** * Create an ACE_Message_Block that owns the specified ACE_Data_Block * without copying it. If the @a flags is set to @c DONT_DELETE we * don't delete the ACE_Data_Block. It is left to the client's * responsibility to take care of the memory allocated for the * data_block */ ACE_Message_Block (ACE_Data_Block *, Message_Flags flags = 0, ACE_Allocator *message_block_allocator = 0); /** * Create an ACE_Message_Block that refers to @a data without * copying it. The @a data memory will not be freed when this block is * destroyed; memory management of @a data is left to the caller. * Note that the @c size of the new ACE_Message_Block will be @a size, but * the @c length will be 0 until the write pointer is changed. */ ACE_Message_Block (const char *data, size_t size = 0, unsigned long priority = ACE_DEFAULT_MESSAGE_BLOCK_PRIORITY); /** * Create an initialized message of type @a type containing @a size * bytes. The @a cont argument initializes the continuation field in * the ACE_Message_Block. If @a data == 0 then this block allocates and * owns the block's memory, using @a allocator to get the data if it's * non-0. If @a data != 0 then this block refers to that memory until * this this block ceases to exist; this object will not free @a data on * destruction. If @a locking_strategy 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 @c size * of the ACE_Message_Block will be @a size, but the @c length will be 0 * until the write pointer is set. The @a data_block_allocator is used to * allocate the data blocks while the @a allocator_strategy is used * to allocate the buffers contained by those. The * @a message_block_allocator is used to allocate new ACE_Message_Block * objects when the duplicate() method is called. If a * @a message_block_allocator is given, this ACE_Message_Block and * future ACE_Message_Block objects created by duplicate() will be * freed using this allocator when they are released. * @note If you use this allocator, the ACE_Message_Block you created * should have been created using this allocator because it will be * released to the same allocator. */ 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, unsigned long priority = ACE_DEFAULT_MESSAGE_BLOCK_PRIORITY, 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, ACE_Allocator *message_block_allocator = 0); /** * A copy constructor. This constructor is a bit different. If the * incoming Message Block has a data block from the stack this * constructor does a deep copy ie. allocates a new data block on * the heap and does a copy of the data from the incoming message * block. As a final note, the alignment information is used to * align the data block if it is created afresh. If the incoming * has a data block has a data block allocated from the heap, * then this constructor just duplicates (ie. a shallow copy) the * data block of the incoming . */ ACE_Message_Block (const ACE_Message_Block &mb, size_t align); /** * Create a Message Block that assumes it has ownership of , * but in reality it doesnt (i.e., cannot 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 (const char *data, size_t size = 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 that we have ownership of the till * this object ceases to exist (and don't delete it during * destruction). 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 (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, unsigned long priority = ACE_DEFAULT_MESSAGE_BLOCK_PRIORITY, 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, ACE_Allocator *message_block_allocator = 0); /** * Delete all the resources held in the message. * * Note that is designed to release the continuation * chain; the destructor is not. See for details. */ virtual ~ACE_Message_Block (void); // = Message Type accessors and mutators. /// Get type of the message. ACE_Message_Type msg_type (void) const; /// Set type of the message. void msg_type (ACE_Message_Type type); /// Find out what type of message this is. int is_data_msg (void) const; /// Find out what class of message this is (there are two classes, /// messages and messages). ACE_Message_Type msg_class (void) const; // = Message flag accessors and mutators. /// Bitwise-or the into the existing message flags and /// return the new value. Message_Flags set_flags (Message_Flags more_flags); /// Clear the message flag bits specified in and return /// the new value. Message_Flags clr_flags (Message_Flags less_flags); /// Get the current message flags. Message_Flags flags (void) const; // = Data Block flag accessors and mutators. /// Bitwise-or the into the existing message flags and /// return the new value. /* @todo: I think the following set of methods could not be used at * all. May be they are useless. Let us have it so that we dont * mess up memory management of the Message_Block. Somebody correct * me if I am totally totally wrong.. */ Message_Flags set_self_flags (ACE_Message_Block::Message_Flags more_flags); /// Clear the message flag bits specified in and return /// the new value. Message_Flags clr_self_flags (ACE_Message_Block::Message_Flags less_flags); /// Get the current message flags. Message_Flags self_flags (void) const; /// Get priority of the message. unsigned long msg_priority (void) const; /// Set priority of the message. void msg_priority (unsigned long priority); /// Get execution time associated with the message. const ACE_Time_Value &msg_execution_time (void) const; /// Set execution time associated with the message. void msg_execution_time (const ACE_Time_Value &et); /// Get absolute time of deadline associated with the message. const ACE_Time_Value &msg_deadline_time (void) const; /// Set absolute time of deadline associated with the message. void msg_deadline_time (const ACE_Time_Value &dt); // = Deep copy and shallow copy methods. /// Return an exact "deep copy" of the message, i.e., create fresh /// new copies of all the Data_Blocks and continuations. virtual ACE_Message_Block *clone (Message_Flags mask = 0) const; /// Return a "shallow" copy that increments our reference count by 1. virtual ACE_Message_Block *duplicate (void) const; /** * 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. */ static ACE_Message_Block *duplicate (const ACE_Message_Block *mb); /** * 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. * * release() is designed to release the continuation chain; the * destructor is not. If we make the destructor release the * continuation chain by calling release() or delete on the message * blocks in the continuation chain, the following code will not * work since the message block in the continuation chain is not off * the heap: * * ACE_Message_Block mb1 (1024); * ACE_Message_Block mb2 (1024); * * mb1.cont (&mb2); * * And hence, call release() on a dynamically allocated message * block. This will release all the message blocks in the * continuation chain. If you call delete or let the message block * fall off the stack, cleanup of the message blocks in the * continuation chain becomes the responsibility of the user. * * @retval 0, always, and the object this method was invoked on is no * longer valid. */ virtual ACE_Message_Block *release (void); /** * 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 . */ static ACE_Message_Block *release (ACE_Message_Block *mb); // = Operations on Message data /** * Copies data into this ACE_Message_Block. Data is copied into the * block starting at the current write pointer. * * @param buf Pointer to the buffer to copy from. * @param n The number of bytes to copy. * * @retval 0 on success; the write pointer is advanced by @arg n. * @retval -1 if the amount of free space following the write pointer * in the block is less than @arg n. Free space can be checked * by calling space(). */ int copy (const char *buf, size_t n); /** * Copies a 0-terminated character string into this ACE_Message_Block. * The string is copied into the block starting at the current write * pointer. The 0-terminator is included in the copied data. * * @param buf Pointer to the character string to copy from. * * @retval 0 on success; the write pointer is advanced by the string's * length, including the 0 terminator. * @retval -1 if the amount of free space following the write pointer * in the block is less than required to hold the entire string. * Free space can be checked by calling space(). */ int copy (const char *buf); /// Normalizes data in the top-level to align with the base, /// i.e., it "shifts" the data pointed to by down to the and /// then readjusts to point to and to point /// to + the length of the moved data. Returns -1 and does /// nothing if the is > , else 0 on success. int crunch (void); /// Resets the Message Block data to contain nothing, i.e., sets the /// read and write pointers to align with the base. void reset (void); /// Access all the allocators in the message block. /// @@todo: Not sure whether we would need finer control while /// trying to access allocators ie. a method for every allocator. /** * This method returns the allocators only from the first message * block in the chain. * * @param allocator_strategy Strategy used to allocate the * underlying buffer * * @param data_block_allocator Strategy used to allocate the * underlying data block * * @param message_block_allocator Strategy used to allocate the * message block */ void access_allocators (ACE_Allocator *&allocator_strategy, ACE_Allocator *&data_block_allocator, ACE_Allocator *&message_block_allocator); /// Reset all the allocators in the message block. /// @@todo: Not sure whether we would need finer control while /// trying to reset allocators ie. a method for every allocator. /** * This method resets the allocators in all the message blocks in * the chain. */ void reset_allocators (ACE_Allocator *allocator_strategy = 0, ACE_Allocator *data_block_allocator = 0, ACE_Allocator *message_block_allocator = 0); /// Get message data. char *base (void) const; /// Set message data (doesn't reallocate). void base (char *data, size_t size, Message_Flags = DONT_DELETE); /// Return a pointer to 1 past the end of the allocated data in a message. char *end (void) const; /** * Return a pointer to 1 past the end of the allotted data in a message. * Allotted data may be less than allocated data if a value smaller than * capacity() to is passed to size(). */ char *mark (void) const; /// Get the read pointer. char *rd_ptr (void) const; /// Set the read pointer to . void rd_ptr (char *ptr); /// Set the read pointer ahead bytes. void rd_ptr (size_t n); /// Get the write pointer. char *wr_ptr (void) const; /// Set the write pointer to . void wr_ptr (char *ptr); /// Set the write pointer ahead bytes. This is used to compute /// the of a message. void wr_ptr (size_t n); /** @name Message length and size operations * * Message length is (wr_ptr - rd_ptr). * * Message size is capacity of the message, including data outside * the [rd_ptr,wr_ptr] range. */ //@{ /// Get the length of the message size_t length (void) const; /// Set the length of the message void length (size_t n); /// Get the length of the s, including chained /// s. size_t total_length (void) const; /// Get the total number of bytes in all s, including /// chained s. size_t total_size (void) const; /// Get the total number of bytes and total length in all /// s, including chained s. void total_size_and_length (size_t &mb_size, size_t &mb_length) const; /// Get the number of bytes in the top-level (i.e., /// does not consider the bytes in chained s). size_t size (void) const; /** * Set the number of bytes in the top-level , * 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. */ int size (size_t length); /// Get the number of allocated bytes in all , including /// chained s. size_t total_capacity (void) const; /// Get the number of allocated bytes in the top-level . size_t capacity (void) const; /// Get the number of bytes available after the in the /// top-level . size_t space (void) const; //@} // = methods. /** * Get a pointer to the data block. Note that the * still references the block; this call does not change the reference * count. */ ACE_Data_Block *data_block (void) const; /** * Set a new data block pointer. The original is released * as a result of this call. If you need to keep the original block, call * instead. Upon return, this * holds a pointer to the new , taking over the reference * you held on it prior to the call. */ void data_block (ACE_Data_Block *); /// Set a new data block pointer. A pointer to the original /// is returned, and not released (as it is with ). ACE_Data_Block *replace_data_block (ACE_Data_Block*); // = The continuation field chains together composite messages. /// Get the continuation field. ACE_Message_Block *cont (void) const; /// Set the continuation field. void cont (ACE_Message_Block *); // = Pointer to the directly ahead in the . /// Get link to next message. ACE_Message_Block *next (void) const; /// Set link to next message. void next (ACE_Message_Block *); // = Pointer to the directly behind in the . /// Get link to prev message. ACE_Message_Block *prev (void) const; /// Set link to prev message. void prev (ACE_Message_Block *); // = The locking strategy prevents race conditions. /// Get the locking strategy. ACE_Lock *locking_strategy (void); /// Set a new locking strategy and return the hold one. ACE_Lock *locking_strategy (ACE_Lock *); /// Get the current reference count. int reference_count (void) const; /// Dump the state of an object. void dump (void) const; /// Declare the dynamic allocation hooks. ACE_ALLOC_HOOK_DECLARE; protected: // = Internal initialization methods. /// Perform the actual initialization. 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, unsigned long priority, const ACE_Time_Value &execution_time, const ACE_Time_Value &deadline_time, ACE_Data_Block *db, ACE_Allocator *data_block_allocator, ACE_Allocator *message_block_allocator); /// Internal release implementation /// Returns 1 if the data block has to be destroyed. int release_i (ACE_Lock *lock); /// Perform the actual initialization. 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, unsigned long priority, const ACE_Time_Value &execution_time, const ACE_Time_Value &deadline_time, ACE_Data_Block *db, ACE_Allocator *data_block_allocator, ACE_Allocator *message_block_allocator); /// Pointer to beginning of next read. size_t rd_ptr_; /// Pointer to beginning of next write. size_t wr_ptr_; /// Priority of message. unsigned long priority_; #if defined (ACE_HAS_TIMED_MESSAGE_BLOCKS) /// Execution time associated with the message. ACE_Time_Value execution_time_; /// Absolute deadline time for message. ACE_Time_Value deadline_time_; #endif /* ACE_HAS_TIMED_MESSAGE_BLOCKS */ // = Links to other ACE_Message_Block *s. /// Pointer to next message block in the chain. ACE_Message_Block *cont_; /// Pointer to next message in the list. ACE_Message_Block *next_; /// Pointer to previous message in the list. ACE_Message_Block *prev_; /// Misc flags (e.g., DONT_DELETE and USER_FLAGS). ACE_Message_Block::Message_Flags flags_; /// Pointer to the reference counted data structure that contains the /// actual memory buffer. ACE_Data_Block *data_block_; /// The allocator used to destroy ourselves when release is called /// and create new message blocks on duplicate. ACE_Allocator *message_block_allocator_; private: // = Disallow these operations for now (use instead). ACE_Message_Block &operator= (const ACE_Message_Block &); ACE_Message_Block (const ACE_Message_Block &); }; /** * @class ACE_Data_Block * * @brief Stores the data payload that is accessed via one or more * s. * * 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). */ class ACE_Export ACE_Data_Block { public: // = Initialization and termination methods. /// Default "do-nothing" constructor. ACE_Data_Block (void); /// Initialize. 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); /// Delete all the resources held in the message. virtual ~ACE_Data_Block (void); /// Get type of the message. ACE_Message_Block::ACE_Message_Type msg_type (void) const; /// Set type of the message. void msg_type (ACE_Message_Block::ACE_Message_Type type); /// Get message data pointer char *base (void) const; /// Set message data pointer (doesn't reallocate). void base (char *data, size_t size, ACE_Message_Block::Message_Flags mflags = ACE_Message_Block::DONT_DELETE); /// Return a pointer to 1 past the end of the allocated data in a message. char *end (void) const; /** * Return a pointer to 1 past the end of the allotted data in a message. * The allotted data may be less than allocated data if is passed * an argument less than . */ char *mark (void) const; // = Message size is the total amount of space alloted. /// Get the total amount of allotted space in the message. The amount of /// allotted space may be less than allocated space. size_t size (void) const; /// Set the total amount of space in the message. Returns 0 if /// successful, else -1. int size (size_t length); /// Get the total amount of allocated space. size_t capacity (void) const; /** * Return an exact "deep copy" of the message, i.e., create fresh * new copies of all the Data_Blocks and continuations. * Notice that Data_Blocks can act as "Prototypes", i.e. derived * classes can override this method and create instances of * themselves. */ virtual ACE_Data_Block *clone (ACE_Message_Block::Message_Flags mask = 0) const; /** * As clone above, but it does not copy the contents of the buffer, * i.e., create a new Data_Block of the same dynamic type, with the * same allocator, locking_strategy, and with the same amount of * storage available but the buffer is unitialized. */ virtual ACE_Data_Block *clone_nocopy (ACE_Message_Block::Message_Flags mask = 0) const; /// Return a "shallow" copy that increments our reference count by 1. ACE_Data_Block *duplicate (void); /** * 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. */ ACE_Data_Block *release (ACE_Lock *lock = 0); // = Message flag accessors and mutators. /// Bitwise-or the into the existing message flags and /// return the new value. ACE_Message_Block::Message_Flags set_flags (ACE_Message_Block::Message_Flags more_flags); /// Clear the message flag bits specified in and return /// the new value. ACE_Message_Block::Message_Flags clr_flags (ACE_Message_Block::Message_Flags less_flags); /// Get the current message flags. ACE_Message_Block::Message_Flags flags (void) const; /// Obtain the allocator strategy. ACE_Allocator *allocator_strategy (void) const; // = The locking strategy prevents race conditions. /// Get the locking strategy. ACE_Lock *locking_strategy (void); /// Set a new locking strategy and return the hold one. ACE_Lock *locking_strategy (ACE_Lock *); /// Dump the state of an object. void dump (void) const; /// Get the current reference count. int reference_count (void) const; /// Get the allocator used to create this object ACE_Allocator *data_block_allocator (void) const; protected: /// Internal release implementation ACE_Data_Block *release_i (void); /** * Decrease the reference count, but don't delete the object. * Returns 0 if the object should be removed. * If is equal to the locking strategy then we assume that * the lock is beign held by the current thread; this is used to * release all the data blocks in a chain while holding a single * lock. */ friend class ACE_Message_Block; ACE_Data_Block *release_no_delete (ACE_Lock *lock); /// Type of message. ACE_Message_Block::ACE_Message_Type type_; /// Current size of message block. size_t cur_size_; /// Total size of buffer. size_t max_size_; /// Misc flags (e.g., DONT_DELETE and USER_FLAGS). ACE_Message_Block::Message_Flags flags_; /// Pointer To beginning of message payload. char *base_; // = Strategies. /** * Pointer to the allocator defined for this . Note * that this pointer is shared by all owners of this * . */ ACE_Allocator *allocator_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. */ ACE_Lock *locking_strategy_; /** * 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. */ int reference_count_; /// The allocator use to destroy ourselves. ACE_Allocator *data_block_allocator_; private: // = Disallow these operations. ACE_Data_Block &operator= (const ACE_Data_Block &); ACE_Data_Block (const ACE_Data_Block &); }; /** * @class ACE_Dynamic_Message_Strategy * * @brief An abstract base class which provides dynamic priority * evaluation methods for use by the * class or any other class which needs to manage the priorities * of a collection of s dynamically. * * 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. */ class ACE_Export ACE_Dynamic_Message_Strategy { public: // = Message priority status // Values are defined as bit flags so that status combinations may // be specified easily. enum Priority_Status { /// Message can still make its deadline PENDING = 0x01, /// Message cannot make its deadline LATE = 0x02, /// Message is so late its priority is undefined BEYOND_LATE = 0x04, /// Mask to match any priority status ANY_STATUS = 0x07 }; /// Constructor. ACE_Dynamic_Message_Strategy (unsigned long static_bit_field_mask, unsigned long static_bit_field_shift, unsigned long dynamic_priority_max, unsigned long dynamic_priority_offset); /// Virtual destructor. virtual ~ACE_Dynamic_Message_Strategy (void); /// Updates the message's priority and returns its priority status. Priority_Status priority_status (ACE_Message_Block &mb, const ACE_Time_Value &tv); /// Get static bit field mask. unsigned long static_bit_field_mask (void) const; /// Set static bit field mask. void static_bit_field_mask (unsigned long); /// Get left shift value to make room for static bit field. unsigned long static_bit_field_shift (void) const; /// Set left shift value to make room for static bit field. void static_bit_field_shift (unsigned long); /// Get maximum supported priority value. unsigned long dynamic_priority_max (void) const; /// Set maximum supported priority value. void dynamic_priority_max (unsigned long); /// Get offset to boundary between signed range and unsigned range. unsigned long dynamic_priority_offset (void) const; /// Set offset to boundary between signed range and unsigned range. void dynamic_priority_offset (unsigned long); /// Dump the state of the strategy. virtual void dump (void) const; protected: /// Hook method for dynamic priority conversion. virtual void convert_priority (ACE_Time_Value &priority, const ACE_Message_Block &mb) = 0; /// This is a bit mask with all ones in the static bit field. unsigned long static_bit_field_mask_; /** * 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). */ unsigned long static_bit_field_shift_; /// Maximum supported priority value. unsigned long dynamic_priority_max_; /// Offset to boundary between signed range and unsigned range. unsigned long dynamic_priority_offset_; /// Maximum late time value that can be represented. ACE_Time_Value max_late_; /// Minimum pending time value that can be represented. ACE_Time_Value min_pending_; /// Time value by which to shift pending priority. ACE_Time_Value pending_shift_; }; /** * @class ACE_Deadline_Message_Strategy * * @brief Deadline based message priority strategy. * * Assigns dynamic message priority according to time to deadline. The * message priority is divided into high and low order bit fields. The * high order bit field is used for dynamic message priority, which is * updated whenever the convert_priority() method is called. The * low order bit field is used for static message priority and is left * unchanged. The partitioning of the priority value into high and low * order bit fields is done according to the arguments passed to the * strategy object's constructor. */ class ACE_Export ACE_Deadline_Message_Strategy : public ACE_Dynamic_Message_Strategy { public: /// Ctor, with all arguments defaulted. ACE_Deadline_Message_Strategy (unsigned long static_bit_field_mask = 0x3FFUL, // 2^(10) - 1 unsigned long static_bit_field_shift = 10, // 10 low order bits unsigned long dynamic_priority_max = 0x3FFFFFUL, // 2^(22)-1 unsigned long dynamic_priority_offset = 0x200000UL); // 2^(22-1) /// Virtual dtor. virtual ~ACE_Deadline_Message_Strategy (void); /// Dynamic priority conversion function based on time to deadline. virtual void convert_priority (ACE_Time_Value &priority, const ACE_Message_Block &mb); /// Dump the state of the strategy. virtual void dump (void) const; }; /** * @class ACE_Laxity_Message_Strategy * * @brief Laxity based message priority strategy. * * Assigns dynamic message priority according to laxity (time to * deadline minus worst case execution time). The message priority is * divided into high and low order bit fields. The high order * bit field is used for dynamic message priority, which is * updated whenever the convert_priority() method is called. The * low order bit field is used for static message priority and is left * unchanged. The partitioning of the priority value into high and low * order bit fields is done according to the arguments passed to the * strategy object's constructor. */ class ACE_Export ACE_Laxity_Message_Strategy : public ACE_Dynamic_Message_Strategy { public: /// Ctor, with all arguments defaulted. ACE_Laxity_Message_Strategy (unsigned long static_bit_field_mask = 0x3FFUL, // 2^(10) - 1 unsigned long static_bit_field_shift = 10, // 10 low order bits unsigned long dynamic_priority_max = 0x3FFFFFUL, // 2^(22)-1 unsigned long dynamic_priority_offset = 0x200000UL); // 2^(22-1) /// virtual dtor. virtual ~ACE_Laxity_Message_Strategy (void); /// Dynamic priority conversion function based on laxity. virtual void convert_priority (ACE_Time_Value &priority, const ACE_Message_Block &mb); /// Dump the state of the strategy. virtual void dump (void) const; }; #if defined (__ACE_INLINE__) #include "ace/Message_Block.inl" #endif /* __ACE_INLINE__ */ #include "ace/Message_Block_T.h" #include /**/ "ace/post.h" #endif /* ACE_MESSAGE_BLOCK_H */