[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