[Ace-users] Re: [ace-bugs] UUID_Generator

Wim van den Boogaard wim.van.den.boogaard at varianinc.com
Mon Sep 3 04:20:18 CDT 2007


Hello Doug,

Thanks for the changes.

This fix is working correctly for me.

Changelog entry:
Implemented an accessor to obtain the timestamp and clockSequence in an 
atomic manner. The clockSequence could change between the moment the 
timestamp is obtained and the moment the clockSequence is used in a 
multithreaded environment and that results in duplicate UUIDs.

Kind regards,

Wim van den Boogaard.
> Hi Wim,
>
>   
>> Hereby I sent you the source files, see attachments.
>>     
>
> Great, thanks!
>
>   
>> Maybe it is better to rename the method get_timestamp to
>> get_timestampAndClocksequence.
>>     
>
> I've tweaked things a bit to ensure backwards compatibility with 
> existing applications.  Can you please check out
>
> http://www.dre.vanderbilt.edu/~schmidt/DOC_ROOT/ACE/ace/UUID.h
> http://www.dre.vanderbilt.edu/~schmidt/DOC_ROOT/ACE/ace/UUID.cpp
>
> and let me know if it's ok?  Also, could you please send me a brief
> ChangeLog entry explaining what you've done and why.
>
> Thanks very much,
>
>         Doug
>
>   
>> Kind regards,
>>
>> Wim van den Boogaard
>>     
>>> Hi Wim,
>>>
>>> Thanks for using the PRF.
>>>
>>>
>>>       
>>>> ACE VERSION: 5.5.8 / 10
>>>>
>>>> HOST MACHINE and OPERATING SYSTEM:
>>>>    WinXP
>>>>
>>>> TARGET MACHINE and OPERATING SYSTEM, if different from HOST:
>>>> COMPILER NAME AND VERSION (AND PATCHLEVEL):
>>>>
>>>> THE $ACE_ROOT/ace/config.h FILE [if you use a link to a platform-
>>>>    specific file, simply state which one]:
>>>>    config-win32.h
>>>>
>>>>
>>>> THE $ACE_ROOT/include/makeinclude/platform_macros.GNU FILE [if you
>>>>    use a link to a platform-specific file, simply state which one
>>>>    (unless this isn't used in this case, e.g., with Microsoft Visual
>>>>    C++)]:
>>>>
>>>> CONTENTS OF $ACE_ROOT/bin/MakeProjectCreator/config/default.features
>>>>    (used by MPC when you generate your own makefiles):
>>>>     ---
>>>>
>>>> AREA/CLASS/EXAMPLE AFFECTED:
>>>>
>>>>    DOES THE PROBLEM AFFECT:
>>>>        COMPILATION?
>>>>        LINKING
>>>>        EXECUTION
>>>>                 OTHER (please specify)?
>>>>
>>>>    SYNOPSIS:
>>>>        Double UUID generated in a multi threaded application.
>>>>
>>>>    DESCRIPTION:
>>>>         The method UUID_Generator::generateUUID is not thread safe
>>>> in respect to the combination uuid_state_.clockSequence
>>>>         and timestamp.
>>>>         The combination timestamp and clockSequence should be
>>>> accessed in a thread safe manner. The method
>>>>         UUID_Generator::get_timestamp returns the timestamp thread
>>>> safe, but also modifies the uuid_state_.clockSequence.
>>>>         The uuid_state_.clockSequence is accessed thread safe in
>>>> UUID_Generator::generateUUID, but could have been modified
>>>>         between the moment get_timestamp is being done and the
>>>> moment it is being used.
>>>>
>>>>    REPEAT BY:
>>>>
>>>>    SAMPLE FIX/WORKAROUND:
>>>>         Return the timestamp and clockSequence in a atomic manner
>>>> via the get_timestamp method. I added an other argument
>>>>         to the get_timestamp.
>>>>         void get_timestamp(UUID_time& timestamp, ACE_UINT16& clockSequence);
>>>>
>>>>         Return the actual clockSequence in the get_timestamp method.
>>>>
>>>>         
>>> Could you please send the code that implements this and we'll add it to ACE!
>>>
>>> Thanks,
>>>
>>>         Doug
>>>
>>>
>>>       
>> //$Id: UUID.cpp 78180 2007-04-25 07:05:02Z johnnyw $
>>
>> #include "ace/UUID.h"
>> #include "ace/Guard_T.h"
>>
>> #if !defined (__ACE_INLINE__)
>> #include "ace/UUID.inl"
>> #endif /* __ACE_INLINE__ */
>>
>> #include "ace/Log_Msg.h"
>> #include "ace/OS_NS_stdio.h"
>> #include "ace/OS_NS_string.h"
>> #include "ace/OS_NS_sys_time.h"
>> #include "ace/OS_NS_netdb.h"
>> #include "ace/OS_NS_unistd.h"
>> #include "ace/ACE.h"
>>
>> ACE_RCSID (ace,
>>            UUID,
>>            "$Id: UUID.cpp 78180 2007-04-25 07:05:02Z johnnyw $")
>>
>>
>> ACE_BEGIN_VERSIONED_NAMESPACE_DECL
>>
>> namespace ACE_Utils
>> {
>>
>>   UUID_node::UUID_node (void)
>>   {
>>     for (int i = 0; i < UUID_node::NODE_ID_SIZE; ++i)
>>       {
>>         nodeID_[i] = 0;
>>       }
>>   }
>>
>>   UUID_node::NodeID&
>>   UUID_node::nodeID (void)
>>   {
>>     return nodeID_;
>>   }
>>
>>   void
>>   UUID_node::nodeID (NodeID& nodeID)
>>   {
>>     for (int i = 0; i < UUID_node::NODE_ID_SIZE; ++i)
>>       {
>>         nodeID_[i] = nodeID[i];
>>       }
>>   }
>>
>>   UUID UUID::NIL_UUID;
>>
>>   /// Construct a nil UUID. Such a UUID has every one of it's data
>>   /// elements set to zero.
>>   UUID::UUID(void)
>>     : timeLow_ (0),
>>       timeMid_ (0),
>>       timeHiAndVersion_ (0),
>>       clockSeqHiAndReserved_ (0),
>>       clockSeqLow_ (0),
>>       node_ (0),
>>       node_release_ (true),
>>       as_string_ (0)
>>   {
>>     ACE_NEW (node_,
>>              UUID_node);
>>   }
>>
>>   /// Construct a UUID from a string representation of an UUID.
>>   UUID::UUID (const ACE_CString& uuid_string)
>>     : timeLow_ (0),
>>       timeMid_ (0),
>>       timeHiAndVersion_ (0),
>>       clockSeqHiAndReserved_ (0),
>>       clockSeqLow_ (0),
>>       node_ (0),
>>       node_release_ (true),
>>       as_string_ (0)
>>   {
>>     ACE_NEW (node_,
>>              UUID_node);
>>
>>     this->from_string_i (uuid_string);
>>   }
>>
>>   UUID::UUID(const UUID &right)
>>     : timeLow_ (right.timeLow_),
>>       timeMid_ (right.timeMid_),
>>       timeHiAndVersion_ (right.timeHiAndVersion_),
>>       clockSeqHiAndReserved_ (right.clockSeqHiAndReserved_),
>>       clockSeqLow_ (right.clockSeqLow_),
>>       as_string_ (0)
>>   {
>>     ACE_NEW (node_,
>>              UUID_node (*right.node_));
>>   }
>>
>>   UUID::~UUID (void)
>>   {
>>     if (node_release_)
>>       delete node_;
>>
>>     if (as_string_ != 0)
>>       delete as_string_;
>>   }
>>
>>   const ACE_CString*
>>   UUID::to_string (void)
>>   {
>>     /// Only compute the string representation once.
>>     if (as_string_ == 0)
>>       {
>>         // Get a buffer exactly the correct size. Use the nil UUID as a
>>         // gauge.  Don't forget the trailing nul.
>>         size_t UUID_STRING_LENGTH = 36 + thr_id_.length () + pid_.length ();
>>         char *buf = 0;
>>
>>         if ((thr_id_.length () != 0) && (pid_.length () != 0))
>>           {
>>             UUID_STRING_LENGTH += 2; //for '-'
>>             ACE_NEW_RETURN (buf,
>>                             char[UUID_STRING_LENGTH + 1],
>>                             0);
>>
>>             ACE_OS::sprintf(buf,
>>                             "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x-%s-%s",
>>                             this->timeLow_,
>>                             this->timeMid_,
>>                             this->timeHiAndVersion_,
>>                             this->clockSeqHiAndReserved_,
>>                             this->clockSeqLow_,
>>                             (this->node_->nodeID ()) [0],
>>                             (this->node_->nodeID ()) [1],
>>                             (this->node_->nodeID ()) [2],
>>                             (this->node_->nodeID ()) [3],
>>                             (this->node_->nodeID ()) [4],
>>                             (this->node_->nodeID ()) [5],
>>                             thr_id_.c_str (),
>>                             pid_.c_str ()
>>                             );
>>           }
>>         else
>>           {
>>             ACE_NEW_RETURN (buf,
>>                             char[UUID_STRING_LENGTH + 1],
>>                             0);
>>
>>             ACE_OS::sprintf (buf,
>>                              "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
>>                              this->timeLow_,
>>                              this->timeMid_,
>>                              this->timeHiAndVersion_,
>>                              this->clockSeqHiAndReserved_,
>>                              this->clockSeqLow_,
>>                              (this->node_->nodeID ()) [0],
>>                              (this->node_->nodeID ()) [1],
>>                              (this->node_->nodeID ()) [2],
>>                              (this->node_->nodeID ()) [3],
>>                              (this->node_->nodeID ()) [4],
>>                              (this->node_->nodeID ()) [5]
>>                              );
>>           }
>>
>>         // We allocated 'buf' above dynamically, so we shouldn't use
>>         // ACE_NEW_RETURN here to avoid a possible memory leak.
>>         ACE_NEW_NORETURN (this->as_string_,
>>                           ACE_CString (buf, UUID_STRING_LENGTH));
>>
>>         // we first free the dynamically allocated 'buf'.
>>         delete [] buf;
>>
>>         // then we test that ACE_NEW succeded for 'as_string_'
>>         // if not, we return 0 (NULL) to indicate failure.
>>         if( this->as_string_ == 0 )
>>         {
>>            return 0;
>>         }
>>       }
>>
>>     return as_string_;
>>   }
>>
>>   void
>>   UUID::from_string_i (const ACE_CString& uuid_string)
>>   {
>>     if (uuid_string.length() < NIL_UUID.to_string ()->length ())
>>       {
>>         ACE_ERROR ((LM_ERROR,
>>                     "%N ACE_UUID::from_string_i - "
>>                     "IllegalArgument(incorrect string length)\n"));
>>         return;
>>       }
>>
>>     /// Special case for the nil UUID.
>>     if (uuid_string == *NIL_UUID.to_string ())
>>       {
>>         bool copy_constructor_not_supported = false;
>>         ACE_ASSERT (copy_constructor_not_supported);
>>         //*this = NIL_UUID;
>>         ACE_UNUSED_ARG (copy_constructor_not_supported);
>>         return;
>>       }
>>
>>     unsigned int timeLow;
>>     unsigned int timeMid;
>>     unsigned int timeHiAndVersion;
>>     unsigned int clockSeqHiAndReserved;
>>     unsigned int clockSeqLow;
>>     unsigned int node [UUID_node::NODE_ID_SIZE];
>>     char thr_pid_buf [BUFSIZ];
>>
>>     if (uuid_string.length() == NIL_UUID.to_string()->length())
>>       {
>>         // This might seem quite strange this being in ACE, but it
>>         // seems to be a bit difficult to write a facade for ::sscanf
>>         // because some compilers dont support vsscanf, including
>>         // MSVC. It appears that most platforms support sscanf though
>>         // so we need to use it directly.
>>         const int nScanned =
>> #if defined (ACE_HAS_TR24731_2005_CRT)
>>           sscanf_s (
>> #else
>>           ::sscanf(
>> #endif
>>                    uuid_string.c_str(),
>>                    "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x",
>>                    &timeLow,
>>                    &timeMid,
>>                    &timeHiAndVersion,
>>                    &clockSeqHiAndReserved,
>>                    &clockSeqLow,
>>                    &node[0],
>>                    &node[1],
>>                    &node[2],
>>                    &node[3],
>>                    &node[4],
>>                    &node[5]
>>                    );
>>
>>         if (nScanned != 11)
>>           {
>>             ACE_DEBUG ((LM_DEBUG,
>>                         "UUID::from_string_i - "
>>                         "IllegalArgument(invalid string representation)\n"));
>>             return;
>>           }
>>       }
>>     else
>>       {
>>         const int nScanned =
>> #if defined (ACE_HAS_TR24731_2005_CRT)
>>           sscanf_s (uuid_string.c_str(),
>>                     "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x-%s",
>>                     &timeLow,
>>                     &timeMid,
>>                     &timeHiAndVersion,
>>                     &clockSeqHiAndReserved,
>>                     &clockSeqLow,
>>                     &node[0],
>>                     &node[1],
>>                     &node[2],
>>                     &node[3],
>>                     &node[4],
>>                     &node[5],
>>                     thr_pid_buf,
>>                     BUFSIZ
>>                     );
>> #else
>>           ::sscanf (uuid_string.c_str(),
>>                     "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x-%s",
>>                     &timeLow,
>>                     &timeMid,
>>                     &timeHiAndVersion,
>>                     &clockSeqHiAndReserved,
>>                     &clockSeqLow,
>>                     &node[0],
>>                     &node[1],
>>                     &node[2],
>>                     &node[3],
>>                     &node[4],
>>                     &node[5],
>>                     thr_pid_buf
>>                     );
>> #endif /* ACE_HAS_TR24731_2005_CRT */
>>
>>         if (nScanned != 12)
>>           {
>>             ACE_DEBUG ((LM_DEBUG,
>>                         "ACE_UUID::from_string_i - "
>>                         "IllegalArgument(invalid string representation)\n"));
>>             return;
>>           }
>>       }
>>
>>     this->timeLow_ = static_cast<ACE_UINT32> (timeLow);
>>     this->timeMid_ = static_cast<ACE_UINT16> (timeMid);
>>     this->timeHiAndVersion_ = static_cast<ACE_UINT16> (timeHiAndVersion);
>>     this->clockSeqHiAndReserved_ = static_cast<u_char> (clockSeqHiAndReserved);
>>     this->clockSeqLow_ = static_cast<u_char> (clockSeqLow);
>>
>>     UUID_node::NodeID nodeID;
>>     for (int i = 0; i < UUID_node::NODE_ID_SIZE; ++i)
>>       nodeID [i] = static_cast<u_char> (node[i]);
>>
>>     this->node_->nodeID (nodeID);
>>
>>     // Support varient 10- only
>>     if ((this->clockSeqHiAndReserved_ & 0xc0) != 0x80 && (this->clockSeqHiAndReserved_ & 0xc0) != 0xc0)
>>       {
>>         ACE_DEBUG ((LM_DEBUG,
>>                     "ACE_UUID::from_string_i - "
>>                     "IllegalArgument(unsupported variant)\n"));
>>         return;
>>       }
>>
>>     /// Support versions 1, 3, and 4 only
>>     ACE_UINT16 V1 = this->timeHiAndVersion_;
>>
>>     if ((V1 & 0xF000) != 0x1000 &&
>>         (V1 & 0xF000) != 0x3000 &&
>>       (V1 & 0xF000) != 0x4000)
>>       {
>>         ACE_DEBUG ((LM_DEBUG,
>>                     "ACE_UUID::from_string_i - "
>>                     "IllegalArgument(unsupported version)\n"));
>>         return;
>>       }
>>     if ((this->clockSeqHiAndReserved_ & 0xc0) == 0xc0)
>>       {
>>         if (uuid_string.length() == NIL_UUID.to_string()->length())
>>           {
>>             ACE_DEBUG ((LM_DEBUG,
>>                       "ACE_UUID::from_string_i - "
>>                         "IllegalArgument (Missing Thread and Process Id)\n"));
>>             return;
>>           }
>>         ACE_CString thr_pid_str (thr_pid_buf);
>>         ssize_t pos = static_cast<ssize_t> (thr_pid_str.find ('-'));
>>         if (pos == -1)
>>           ACE_DEBUG ((LM_DEBUG,
>>                       "ACE_UUID::from_string_i - "
>>                       "IllegalArgument (Thread and Process Id format incorrect)\n"));
>>
>>         this->thr_id_ = thr_pid_str.substr (0, pos);
>>       this->pid_ = thr_pid_str.substr (pos+1, thr_pid_str.length ()-pos-1);
>>       }
>>   }
>>
>>   UUID_Generator::UUID_Generator ()
>>     : timeLast_ (0),
>>       destroy_lock_ (true)
>>   {
>>     ACE_NEW (lock_,
>>              ACE_SYNCH_MUTEX);
>>   }
>>
>>   UUID_Generator::~UUID_Generator()
>>   {
>>     if (destroy_lock_)
>>       delete lock_;
>>   }
>>
>>   void
>>   UUID_Generator::init (void)
>>   {
>>     ACE_OS::macaddr_node_t macaddress;
>>     int result = ACE_OS::getmacaddress (&macaddress);
>>
>>     UUID_node::NodeID nodeID;
>>     if (result != -1)
>>       {
>> //         ACE_DEBUG ((LM_DEBUG,
>> //                     "%02X-%02X-%02X-%02X-%02X-%02X\n",
>> //                     macaddress.node [0],
>> //                     macaddress.node [1],
>> //                     macaddress.node [2],
>> //                     macaddress.node [3],
>> //                     macaddress.node [4],
>> //                     macaddress.node [5]));
>>
>>         ACE_OS::memcpy (&nodeID,
>>                         macaddress.node,
>>                         sizeof (nodeID));
>>       }
>>     else
>>       {
>>         nodeID [0] = static_cast<u_char> (ACE_OS::rand());
>>         nodeID [1] = static_cast<u_char> (ACE_OS::rand());
>>         nodeID [2] = static_cast<u_char> (ACE_OS::rand());
>>         nodeID [3] = static_cast<u_char> (ACE_OS::rand());
>>         nodeID [4] = static_cast<u_char> (ACE_OS::rand());
>>         nodeID [5] = static_cast<u_char> (ACE_OS::rand());
>>       }
>>
>> 	ACE_UINT16 dummy;
>>     this->get_timestamp (timeLast_,dummy);
>>
>>     {
>>       ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, *lock_);
>>       uuid_state_.timestamp = timeLast_;
>>       uuid_state_.node.nodeID (nodeID);
>>     }
>>   }
>>
>>
>>   void
>>   UUID_Generator::generateUUID (UUID& uuid,ACE_UINT16 version, u_char variant)
>>   {
>>     UUID_time timestamp;
>> 	ACE_UINT16 clockSequence;
>>     this->get_timestamp (timestamp,clockSequence);
>>
>>
>>     // Construct a Version 1 UUID with the information in the arguements.
>>     uuid.timeLow (static_cast<ACE_UINT32> (timestamp & 0xFFFFFFFF));
>>     uuid.timeMid (static_cast<ACE_UINT16> ((timestamp >> 32) & 0xFFFF));
>>
>>
>>     ACE_UINT16 tHAV = static_cast<ACE_UINT16> ((timestamp >> 48) & 0xFFFF);
>>     tHAV |= (version << 12);
>>     uuid.timeHiAndVersion (tHAV);
>>
>>     u_char cseqHAV;
>>     uuid.clockSeqLow (static_cast<u_char> (clockSequence & 0xFF));
>>     cseqHAV = static_cast<u_char> ((clockSequence & 0x3f00) >> 8);
>>     uuid_state_.timestamp = timestamp;
>>
>>     cseqHAV |= variant;
>>     uuid.clockSeqHiAndReserved (cseqHAV);
>>     uuid.node (&(uuid_state_.node));
>>
>>     if (variant == 0xc0)
>>     {
>>       ACE_Thread_ID thread_id;
>>       char buf [BUFSIZ];
>>       thread_id.to_string (buf);
>>       uuid.thr_id (buf);
>>
>>       ACE_OS::sprintf (buf,
>>                        "%d",
>>                        static_cast<int> (ACE_OS::getpid ()));
>>       uuid.pid (buf);
>>     }
>>   }
>>
>>   UUID*
>>   UUID_Generator::generateUUID (ACE_UINT16 version, u_char variant)
>>   {
>>     UUID* uuid;
>>     ACE_NEW_RETURN (uuid,
>>                     UUID,
>>                     0);
>>
>>     this->generateUUID (*uuid, version, variant);
>>     return uuid;
>>   }
>>
>>   /// Obtain a new timestamp. If UUID's are being generated too quickly
>>   /// the clock sequence will be incremented
>>   void
>>   UUID_Generator::get_timestamp (UUID_time& timestamp,ACE_UINT16& clockSequence)
>>   {
>>     ACE_GUARD (ACE_SYNCH_MUTEX, mon, *lock_);
>>
>>     this->get_systemtime(timestamp);
>>
>>     // Account for the clock being set back. Increment the clock /
>>     // sequence.
>>     if (timestamp <= timeLast_)
>>       uuid_state_.clockSequence = static_cast<u_char> ((uuid_state_.clockSequence + 1) & ACE_UUID_CLOCK_SEQ_MASK);
>>
>>     // If the system time ticked since the last UUID was
>>     // generated. Set / the clock sequence back.
>>     else if (timestamp > timeLast_)
>>       uuid_state_.clockSequence = 0;
>>
>>     timeLast_ = timestamp;
>> 	clockSequence = uuid_state_.clockSequence;
>>   }
>>
>>   /**
>>    * ACE_Time_Value is in POSIX time, seconds since Jan 1, 1970. UUIDs use
>>    * time in 100ns ticks since 15 October 1582. The difference is:
>>    *   15 Oct 1582 - 1 Jan 1600: 17 days in Oct, 30 in Nov,  31 in Dec +
>>    *       17 years and 4 leap days (1584, 88, 92 and 96)
>>    *   1 Jan 1600 - 1 Jan 1900: 3 centuries + 73 leap days ( 25 in 17th cent.
>>    *       and 24 each in 18th and 19th centuries)
>>    *   1 Jan 1900 - 1 Jan 1970: 70 years + 17 leap days.
>>    * This adds up, in days: (17+30+31+365*17+4)+(365*300+73)+(365*70+17) or
>>    * 122192928000000000U (0x1B21DD213814000) 100 ns ticks.
>>    */
>>   void
>>   UUID_Generator::get_systemtime (UUID_time & timestamp)
>>   {
>>     const UUID_time timeOffset =
>> #if defined (ACE_LACKS_UNSIGNEDLONGLONG_T)
>>       ACE_U_LongLong (ACE_INT64_LITERAL (0x1B21DD213814000));
>> #elif defined (ACE_LACKS_LONGLONG_T)
>>       ACE_U_LongLong (0x13814000u, 0x1B21DD2u);
>> #else
>>       ACE_UINT64_LITERAL (0x1B21DD213814000);
>> #endif  /* ACE_LACKS_UNSIGNEDLONGLONG_T */
>>
>>     /// Get the time of day, convert to 100ns ticks then add the offset.
>>     ACE_Time_Value now = ACE_OS::gettimeofday();
>>     ACE_UINT64 time;
>>     now.to_usec (time);
>>     time = time * 10;
>>     timestamp = time + timeOffset;
>> }
>>
>>   ACE_SYNCH_MUTEX*
>>   UUID_Generator::lock (void)
>>   {
>>     return this->lock_;
>>   }
>>
>>   void
>>   UUID_Generator::lock (ACE_SYNCH_MUTEX* lock,
>>                         bool release_lock)
>>   {
>>     if (this->destroy_lock_)
>>       delete this->lock_;
>>
>>     this->lock_ = lock;
>>     this->destroy_lock_ = release_lock;
>>   }
>>
>> }
>>
>> #if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION)
>> template ACE_Singleton<ACE_Utils::UUID_Generator, ACE_SYNCH_MUTEX> *
>>   ACE_Singleton<ACE_Utils::UUID_Generator, ACE_SYNCH_MUTEX>::singleton_;
>> #endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */
>>
>> ACE_END_VERSIONED_NAMESPACE_DECL
>> // -*- C++ -*-
>>
>> //=============================================================================
>> /**
>>  *  @file  UUID.h
>>  *
>>  *  $Id: UUID.h 74958 2006-10-23 23:31:00Z ossama $
>>  *
>>  *  @author Andrew T. Finnel <andrew at activesol.net>
>>  *  @author Yamuna Krishnmaurthy <yamuna at oomworks.com>
>>  */
>> //=============================================================================
>>
>> #ifndef ACE_UUID_H
>> #define ACE_UUID_H
>> #include /**/ "ace/pre.h"
>>
>> #include /**/ "ace/config-all.h"
>>
>> #if !defined (ACE_LACKS_PRAGMA_ONCE)
>> # pragma once
>> #endif /* ACE_LACKS_PRAGMA_ONCE */
>>
>> #include "ace/SString.h"
>> #include "ace/Singleton.h"
>> #include "ace/Synch_Traits.h"
>>
>> ACE_BEGIN_VERSIONED_NAMESPACE_DECL
>>
>> namespace ACE_Utils
>> {
>>   /// Class to hold a MAC address
>>   class ACE_Export UUID_node
>>   {
>>   public:
>>
>>     /// Constructor
>>     UUID_node (void);
>>
>>     enum {NODE_ID_SIZE = 6};
>>     typedef u_char NodeID[NODE_ID_SIZE];
>>
>>     NodeID& nodeID (void);
>>     void nodeID (NodeID&);
>>
>>     ///// Equality Operations
>>     bool operator == (const UUID_node& right) const;
>>     bool operator != (const UUID_node& right) const;
>>
>>     ///// Relational Operations
>>     //bool operator <  (const UUID_node& right) const;
>>
>>   private:
>>     NodeID nodeID_;
>>   };
>>
>>
>>
>>   /**
>>    *  @class ACE_UUID
>>    *
>>    * ACE_UUID represents a Universally Unique IDentifier (UUID) as
>>    * described in (the expired) INTERNET-DRAFT specification entitled
>>    * UUIDs and GUIDs. All instances of UUID are of the time-based
>>    * variety. That is, the version number part of the timeHiAndVersion
>>    * field is 1.
>>    *
>>    * The default constructor creates a nil UUID.
>>    *
>>    * UUIDs have value semantics. In addition, they may be compared for
>>    * ordering and equality.
>>    *
>>    * Additionally in this implementation provisions have been made to include
>>    * process and thread ids to make the UUIDs more unique. The variant 0xc0
>>    * has been added to facilitate this.
>>    */
>>   class ACE_Export UUID
>>   {
>>   public:
>>
>>     /// Constructor
>>     UUID (void);
>>
>>     /// Constructs a UUID from a string representation.
>>     UUID (const ACE_CString& uuidString);
>>
>>     UUID (const UUID &right);
>>
>>     // Destructor
>>     ~UUID (void);
>>
>>     ACE_UINT32 timeLow (void) const;
>>     void timeLow (ACE_UINT32);
>>
>>     ACE_UINT16 timeMid (void) const;
>>     void timeMid (ACE_UINT16);
>>
>>     ACE_UINT16 timeHiAndVersion (void) const;
>>     void timeHiAndVersion (ACE_UINT16);
>>
>>     u_char clockSeqHiAndReserved (void) const;
>>     void clockSeqHiAndReserved (u_char);
>>
>>     u_char clockSeqLow (void) const;
>>     void clockSeqLow (u_char);
>>
>>     UUID_node* node (void) const;
>>     void node (UUID_node*);
>>
>>     ACE_CString* thr_id (void);
>>     void thr_id (char*);
>>
>>     ACE_CString* pid (void);
>>     void pid (char*);
>>
>>     /// Returns a string representation of the UUID
>>     const ACE_CString* to_string (void);
>>
>>     /// Set the value using a string
>>     void from_string (const ACE_CString& uuid_string);
>>
>>     static UUID NIL_UUID;
>>
>>     /// Equality Operations
>>     bool operator== (const UUID &right) const;
>>     bool operator!= (const UUID &right) const;
>>
>>     /// Relational Operations
>>     //bool operator<  (const UUID &right) const;
>>     //bool operator>  (const UUID &right) const;
>>     //bool operator<= (const UUID &right) const;
>>     //bool operator>= (const UUID &right) const;
>>
>>   private:
>>     void from_string_i (const ACE_CString& uuidString);
>>
>>     UUID& operator= (const UUID&);
>>
>>     /// Data Members for Class Attributes
>>     ACE_UINT32 timeLow_;
>>     ACE_UINT16 timeMid_;
>>     ACE_UINT16 timeHiAndVersion_;
>>     u_char clockSeqHiAndReserved_;
>>     u_char clockSeqLow_;
>>     UUID_node* node_;
>>     bool node_release_;
>>     ACE_CString thr_id_;
>>     ACE_CString pid_;
>>
>>     /// The string representation of the UUID. This is created and
>>     /// updated only on demand.
>>     ACE_CString *as_string_;
>>   };
>>
>>
>>   /**
>>    * @class ACE_UUID_Generator
>>    *
>>    * Singleton class that generates UUIDs.
>>    *
>>    */
>>   class ACE_Export UUID_Generator
>>   {
>>   public:
>>
>>     enum {ACE_UUID_CLOCK_SEQ_MASK = 0x3FFF};
>>
>>     UUID_Generator();
>>     ~UUID_Generator();
>>
>>     void init (void);
>>
>>     /// Format timestamp, clockseq, and nodeID into an UUID of the
>>     /// specified version and variant. For generating UUID's with
>>     /// thread and process ids use variant=0xc0
>>     void generateUUID (UUID&, ACE_UINT16 version=0x0001, u_char variant=0x80);
>>
>>     /// Format timestamp, clockseq, and nodeID into a VI UUID. For
>>     /// generating UUID's with thread and process ids use variant=0xc0
>>     UUID* generateUUID (ACE_UINT16 version=0x0001, u_char variant=0x80);
>>
>>     /// Type to represent UTC as a count of 100 nanosecond intervals
>>     /// since 00:00:00.00, 15 October 1582.
>>     typedef ACE_UINT64 UUID_time;
>>
>>     /// The locking strategy prevents multiple generators from accessing
>>     /// the UUID_state at the same time. Get the locking strategy.
>>     ACE_SYNCH_MUTEX* lock (void);
>>
>>     /// Set a new locking strategy and return the old one.
>>     void lock (ACE_SYNCH_MUTEX* lock,
>>                bool release_lock);
>>
>>   private:
>>
>>     /// The system time when that last uuid was generated.
>>     UUID_time timeLast_;
>>
>>     /// Type to contain the UUID generator persistent state. This will
>>     /// be kept in memory mapped shared memory
>>     struct UUID_State
>>     {
>>       UUID_time timestamp;
>>       UUID_node node;
>>       ACE_UINT16 clockSequence;
>>     };
>>
>>     /// Obtain a UUID timestamp. Compensate for the fact that the time
>>     /// obtained from getSystem time has a resolution less than 100ns.
>>   void get_timestamp (UUID_time& timestamp, ACE_UINT16& clockSequence);
>>
>>     /// Obtain the system time in UTC as a count of 100 nanosecond intervals
>>     /// since 00:00:00.00, 15 October 1582 (the date of Gregorian reform to
>>   /// the Christian calendar).
>>     void get_systemtime( UUID_time& timeNow);
>>
>>     /// The UUID generator persistent state.
>>     UUID_State uuid_state_;
>>
>>     ACE_SYNCH_MUTEX* lock_;
>>     bool destroy_lock_;
>>   };
>>
>>   typedef ACE_Singleton<UUID_Generator, ACE_SYNCH_MUTEX> UUID_GENERATOR;
>>
>> }
>>
>> ACE_END_VERSIONED_NAMESPACE_DECL
>>
>> #if defined (__ACE_INLINE__)
>> #include "ace/UUID.inl"
>> #endif /* __ACE_INLINE__ */
>>
>> #include /**/ "ace/post.h"
>> #endif // ACE_UUID_H
>>     
>
>   



More information about the Ace-users mailing list