[ace-users] [ace-bugs] UUID_Generator

Douglas C. Schmidt schmidt at dre.vanderbilt.edu
Thu Sep 13 19:38:06 CDT 2007


Hi Wim,

   Great, thanks - I've added this fix.  It'll appear in ACE 5.6.2.
   
   Doug

>Hello Doug,
>
>I ran into an other problem when a lot UUIDs are generated quickly after 
>each other, again duplicates are generated. This is being caused by the 
>two occurences of the following line in UUID.cpp:
>      uuid_state_.clockSequence = static_cast<u_char> 
>((uuid_state_.clockSequence + 1) & ACE_UUID_CLOCK_SEQ_MASK);
>
>This line should be:
>      uuid_state_.clockSequence = static_cast<ACE_UINT16> 
>((uuid_state_.clockSequence + 1) & ACE_UUID_CLOCK_SEQ_MASK);
>
>Due to the casting to u_char instead of ACE_UINT16, duplicates are 
>generated after more then 255.
>
>Kind regards,
>
>Wim van den Boogaard.
>
>> Hi Wim,
>>
>>    ok, great, thanks for all the improvements and documentation.  I'll
>> check this in after the x.6 release goes out tomorrow.  
>>
>>    BTW, Johnny, I've made a pass through UUID.{h,inl,cpp} and
>> "ACE-ified" everything.  This may require some changes to user code,
>> but the original API was totally inconsistent with ACE.
>>
>> Thanks,
>>
>>         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
>>>>>     
>>>>>         
>>>>   
>>>>       
>>
>>
>>   
>


-- 
Dr. Douglas C. Schmidt                       Professor and Associate Chair
Electrical Engineering and Computer Science  TEL: (615) 343-8197
Vanderbilt University                        WEB: www.dre.vanderbilt.edu/~schmidt
Nashville, TN 37203                          NET: d.schmidt at vanderbilt.edu



More information about the Ace-users mailing list