Source code of Windows XP (NT5)
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
/*===================================================================
Microsoft Denali
Microsoft Confidential. Copyright 1997 Microsoft Corporation. All Rights Reserved.
Component: ID Generator
File: Idgener.cpp
Owner: DmitryR
This is the ID Generator source file. ===================================================================*/ #include "denpre.h"
#pragma hdrstop
#include "Idgener.h"
#include "memchk.h"
/*===================================================================
CIdGenerator::CIdGenerator
NOTE: Constructor
Parameters:
Returns: ===================================================================*/ CIdGenerator::CIdGenerator() : m_fInited(FALSE), m_dwStartId(0), m_dwLastId(0) { }
/*===================================================================
CIdGenerator::~CIdGenerator()
NOTE: Destructor
Parameters:
Returns: ===================================================================*/ CIdGenerator::~CIdGenerator() { if ( m_fInited ) DeleteCriticalSection( &m_csLock ); } /*===================================================================
HRESULT CIdGenerator::Init()
NOTE: Seed new starting Id
Parameters:
Returns: HRESULT (could fail to create critical section) ===================================================================*/ HRESULT CIdGenerator::Init() { Assert(!m_fInited); /*===
Seed the starting id The starting Id should be: 1) random 2) not to close to recently generated starting ids To accomplish the above, starting Id is in the following (binary) format: 00TT.TTTT TTTT.TTTT TTT1.RRRR RRRR.RRRR RRR is random number to introduce some randomness 1 is needed to make sure the id is far enough from 0 TTT is current time() in 4 second increments. This means that 4 second in server restart delay translates into 8,192 difference in the starting Id (122880 sessions / minute). 17 bits of 4 sec intervals make a roll over time of about 145 hours, hopefully longer than a client's connection lifetime (not that it REALLY matters). 00 in the highest bits is to make sure it doesn't reach 0xffffffff too soon ===*/ DWORD dwRRR = rand() & 0x00000FFF; DWORD dwTTT = (((DWORD)time(NULL)) >> 2) & 0x0001FFFF; m_dwStartId = (dwTTT << 13) | (1 << 12) | dwRRR; m_dwLastId = m_dwStartId;
HRESULT hr = S_OK; ErrInitCriticalSection( &m_csLock, hr ); if ( FAILED( hr ) ) return hr; m_fInited = TRUE; return S_OK; }
/*===================================================================
HRESULT CIdGenerator::Init(CIdGenerator StartId)
NOTE: Seed new starting Id with Id passed in
Parameters:
Returns: HRESULT (could fail to create critical section) ===================================================================*/ HRESULT CIdGenerator::Init(CIdGenerator & StartId) { Assert(!m_fInited); m_dwStartId = StartId.m_dwStartId; m_dwLastId = m_dwStartId;
HRESULT hr = NOERROR; ErrInitCriticalSection( &m_csLock, hr ); if ( FAILED( hr ) ) return hr; m_fInited = TRUE; return NOERROR; }
/*===================================================================
DWORD CIdGenerator::NewId()
NOTE: Generates new ID
Parameters:
Returns: generated ID ===================================================================*/ DWORD CIdGenerator::NewId() { Assert(m_fInited); DWORD dwId;
EnterCriticalSection(&m_csLock); dwId = ++m_dwLastId; LeaveCriticalSection(&m_csLock); if (dwId == INVALID_ID) { // doesn't happen very often do critical section again
// to make the above critical section shorter
EnterCriticalSection(&m_csLock); // check again in case other thread changed it
if (m_dwLastId == INVALID_ID) m_dwLastId = m_dwStartId; // roll over
m_dwLastId++; LeaveCriticalSection(&m_csLock); dwId = m_dwLastId; }
return dwId; }
/*===================================================================
BOOL CIdGenerator::IsValidId(DWORD dwId)
NOTE: Checks if the given Id is valid (with start-last range)
Parameters: DWORD dwId Id value to check
Returns: generated ID ===================================================================*/ BOOL CIdGenerator::IsValidId ( DWORD dwId ) { Assert(m_fInited); return (dwId > m_dwStartId && dwId <= m_dwLastId); }
|