summaryrefslogtreecommitdiff
path: root/ACE/ace/Message_Block.h
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/ace/Message_Block.h')
-rw-r--r--ACE/ace/Message_Block.h1051
1 files changed, 1051 insertions, 0 deletions
diff --git a/ACE/ace/Message_Block.h b/ACE/ace/Message_Block.h
new file mode 100644
index 00000000000..1588e16dd3a
--- /dev/null
+++ b/ACE/ace/Message_Block.h
@@ -0,0 +1,1051 @@
+// -*- C++ -*-
+
+//==========================================================================
+/**
+ * @file Message_Block.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//==========================================================================
+
+#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"
+
+ACE_BEGIN_VERSIONED_NAMESPACE_DECL
+
+// 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
+ * <mb> 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 @a mb.
+ */
+ ACE_Message_Block (const ACE_Message_Block &mb,
+ size_t align);
+
+ /**
+ * Create a Message Block that assumes it has ownership of @a data,
+ * but in reality it doesnt (i.e., cannot delete it since it didn't
+ * malloc it!). Note that the @c size of the Message_Block will
+ * be @a size, but the <length> will be 0 until <wr_ptr> is set.
+ */
+ int init (const char *data,
+ size_t size = 0);
+
+ /**
+ * Create an initialized message of type @a type containing @a size
+ * bytes. The @a cont argument initializes the continuation field in
+ * the <Message_Block>. If @a data == 0 then we create and own the
+ * @a data, using @a allocator_strategy to get the data if it's non-0. If
+ * @a data != 0 we assume that we have ownership of the @a data till
+ * this object ceases to exist (and don't delete it during
+ * 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 <size>
+ * of the <Message_Block> will be @a size, but the <length> will be 0
+ * until <wr_ptr> is set. The @a data_block_allocator is use to
+ * allocate the data blocks while the @a allocator_strategy 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 <release()> is designed to release the continuation
+ * chain; the destructor is not. See <release()> 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,
+ /// @c normal messages and @c high-priority messages).
+ ACE_Message_Type msg_class (void) const;
+
+ // = Message flag accessors and mutators.
+ /// Bitwise-or the @a more_flags 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 @a less_flags 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 <more_flags> 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 @a less_flags 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 <mb> 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 <release>, except that it
+ * checks if <mb> is 0. This is similar to <CORBA::release>, which
+ * is useful if you want to eliminate lots of checks for NULL
+ * pointers before calling <release> on them. Returns <mb>.
+ */
+ 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 <Message_Block> to align with the base,
+ /// i.e., it "shifts" the data pointed to by <rd_ptr> down to the <base> and
+ /// then readjusts <rd_ptr> to point to <base> and <wr_ptr> to point
+ /// to <base> + the length of the moved data. Returns -1 and does
+ /// nothing if the <rd_ptr> is > <wr_ptr>, 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 @a ptr.
+ void rd_ptr (char *ptr);
+
+ /// Set the read pointer ahead @a n bytes.
+ void rd_ptr (size_t n);
+
+ /// Get the write pointer.
+ char *wr_ptr (void) const;
+
+ /// Set the write pointer to @a ptr.
+ void wr_ptr (char *ptr);
+
+ /// Set the write pointer ahead <n> bytes. This is used to compute
+ /// the <length> 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 <Message_Block>s, including chained
+ /// <Message_Block>s.
+ size_t total_length (void) const;
+
+ /// Get the total number of bytes in all <Message_Block>s, including
+ /// chained <Message_Block>s.
+ size_t total_size (void) const;
+
+ /// Get the total number of bytes and total length in all
+ /// <Message_Block>s, including chained <Message_Block>s.
+ void total_size_and_length (size_t &mb_size,
+ size_t &mb_length) const;
+
+ /// Get the number of bytes in the top-level <Message_Block> (i.e.,
+ /// does not consider the bytes in chained <Message_Block>s).
+ size_t size (void) const;
+
+ /**
+ * Set the number of bytes in the top-level <Message_Block>,
+ * reallocating space if necessary. However, the <rd_ptr_> and
+ * <wr_ptr_> 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 <Message_Block>, including
+ /// chained <Message_Block>s.
+ size_t total_capacity (void) const;
+
+ /// Get the number of allocated bytes in the top-level <Message_Block>.
+ size_t capacity (void) const;
+
+ /// Get the number of bytes available after the <wr_ptr_> in the
+ /// top-level <Message_Block>.
+ size_t space (void) const;
+ //@}
+
+ // = ACE_Data_Block methods.
+
+ /**
+ * Get a pointer to the data block. Note that the ACE_Message_Block
+ * 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 ACE_Data_Block is released
+ * as a result of this call. If you need to keep the original block, call
+ * <replace_data_block> instead. Upon return, this ACE_Message_Block
+ * holds a pointer to the new ACE_Data_Block, 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 ACE_Data_Block
+ /// is returned, and not released (as it is with <data_block>).
+ 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 <Message_Block> directly ahead in the ACE_Message_Queue.
+ /// Get link to next message.
+ ACE_Message_Block *next (void) const;
+
+ /// Set link to next message.
+ void next (ACE_Message_Block *);
+
+ // = Pointer to the <Message_Block> directly behind in the ACE_Message_Queue.
+ /// 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 <clone> 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
+ * ACE_Message_Block's.
+ *
+ * This data structure is reference counted to maximize
+ * sharing. It also contains the <locking_strategy_> (which
+ * protects the reference count from race conditions in
+ * concurrent programs) and the <allocation_strategy_> (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 <size()> is passed
+ * an argument less than <capacity()>.
+ */
+ 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 (if @a max_size is zero) but the buffer is unitialized.
+ * If @a max_size is specified other than zero, it will be used when
+ * creating the new data block.
+ */
+ virtual ACE_Data_Block *clone_nocopy (ACE_Message_Block::Message_Flags mask = 0,
+ size_t max_size = 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
+ * <this> and <mb> 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 <more_flags> 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 <less_flags> 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
+ virtual ACE_Data_Block *release_i (void);
+
+ /// Internal get the current reference count.
+ int reference_count_i (void) const;
+
+ /**
+ * Decrease the reference count, but don't delete the object.
+ * Returns 0 if the object should be removed.
+ * If <lock> 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 ACE_Data_Block. Note
+ * that this pointer is shared by all owners of this
+ * ACE_Data_Block.
+ */
+ ACE_Allocator *allocator_strategy_;
+
+ /**
+ * Pointer to the locking strategy defined for this
+ * ACE_Data_Block. This is used to protect regions of code that
+ * access shared ACE_Data_Block state. Note that this lock is
+ * shared by all owners of the ACE_Data_Block's data.
+ */
+ ACE_Lock *locking_strategy_;
+
+ /**
+ * Reference count for this ACE_Data_Block, which is used to avoid
+ * deep copies (i.e., <clone>). Note that this pointer value is
+ * shared by all owners of the <Data_Block>'s data, i.e., all the
+ * ACE_Message_Blocks.
+ */
+ 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 ACE_Dynamic_Message_Queue
+ * class or any other class which needs to manage the priorities
+ * of a collection of ACE_Message_Block'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;
+};
+
+ACE_END_VERSIONED_NAMESPACE_DECL
+
+#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 */