[ace-users] [ace-bugs] UUID_Generator
Douglas C. Schmidt
schmidt at dre.vanderbilt.edu
Mon Sep 3 07:56:23 CDT 2007
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