Leaked source code of windows server 2003
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.

540 lines
15 KiB

  1. /*++
  2. Copyright (c) 1998-2001 Microsoft Corporation
  3. Module Name :
  4. IniFile.cpp
  5. Abstract:
  6. Test harness for LKRhash
  7. Author:
  8. George V. Reilly (GeorgeRe) 06-Jan-1998
  9. Environment:
  10. Win32 - User Mode
  11. Project:
  12. LKRhash
  13. Revision History:
  14. --*/
  15. #include "precomp.hxx"
  16. #include "WordHash.h"
  17. #include "IniFile.h"
  18. enum INI_TYPE {
  19. INI_WORD = 1,
  20. INI_DWORD,
  21. INI_DOUBLE,
  22. INI_STRING,
  23. INI_BOOL,
  24. };
  25. typedef struct _ParseOptions {
  26. int m_nFieldOffset;
  27. const char* m_pszName;
  28. unsigned m_cchName;
  29. INI_TYPE m_type;
  30. DWORD_PTR m_default;
  31. } ParseOptions;
  32. #define INI_ENTRY(_member, _name, _type, _default) \
  33. { \
  34. FIELD_OFFSET(CIniFileSettings, _member), \
  35. _name, \
  36. sizeof(_name)-1, \
  37. _type, \
  38. (DWORD_PTR) _default, \
  39. } \
  40. static const ParseOptions g_po[] = {
  41. INI_ENTRY(m_tszDataFile, "DataFile", INI_STRING, _TEXT("??")),
  42. INI_ENTRY(m_nMaxKeys, "MaxKeys", INI_DWORD, MAXKEYS),
  43. INI_ENTRY(m_nHighLoad, "MaxLoadFactor", INI_DWORD, LK_DFLT_MAXLOAD),
  44. INI_ENTRY(m_nInitSize, "InitSize", INI_DWORD, LK_DFLT_INITSIZE),
  45. INI_ENTRY(m_nSubTables, "NumSubTables", INI_DWORD,LK_DFLT_NUM_SUBTBLS),
  46. INI_ENTRY(m_nLookupFreq, "LookupFrequency",INI_DWORD, 5),
  47. INI_ENTRY(m_nMinThreads, "MinThreads", INI_DWORD, 1),
  48. INI_ENTRY(m_nMaxThreads, "MaxThreads", INI_DWORD, 4),
  49. INI_ENTRY(m_nRounds, "NumRounds", INI_DWORD, 1),
  50. INI_ENTRY(m_nSeed, "RandomSeed", INI_DWORD, 1234),
  51. INI_ENTRY(m_fCaseInsensitive,"CaseInsensitive",INI_BOOL, FALSE),
  52. INI_ENTRY(m_fMemCmp, "MemCmp", INI_BOOL, FALSE),
  53. INI_ENTRY(m_nLastChars, "NumLastChars", INI_DWORD, 0),
  54. INI_ENTRY(m_wTableSpin, "TableLockSpinCount",INI_WORD, LOCK_DEFAULT_SPINS),
  55. INI_ENTRY(m_wBucketSpin, "BucketLockSpinCount",INI_WORD,LOCK_DEFAULT_SPINS),
  56. INI_ENTRY(m_dblSpinAdjFctr,"SpinAdjustmentFactor",INI_DOUBLE, 1),
  57. INI_ENTRY(m_fTestIterators,"TestIterators", INI_BOOL, FALSE),
  58. INI_ENTRY(m_nInsertIfNotFound, "InsertIfNotFound",INI_DWORD, 0),
  59. INI_ENTRY(m_nFindKeyCopy, "FindKeyCopy", INI_DWORD, 0),
  60. INI_ENTRY(m_fNonPagedAllocs,"NonPagedAllocs", INI_BOOL, TRUE),
  61. INI_ENTRY(m_fDebugSpew, "DebugSpew", INI_BOOL, FALSE),
  62. INI_ENTRY(m_fRefTrace, "RefTrace", INI_BOOL, FALSE),
  63. INI_ENTRY(m_fMultiKeys, "MultiKeys", INI_BOOL, FALSE),
  64. INI_ENTRY(m_fUseLocks, "UseLocks", INI_BOOL, TRUE),
  65. {-1} // last entry
  66. };
  67. void
  68. CIniFileSettings::Dump(
  69. LPCTSTR ptszProlog,
  70. LPCTSTR ptszEpilog) const
  71. {
  72. TCHAR tsz[50];
  73. _tprintf(_TEXT("%s\n"), ptszProlog);
  74. _tprintf(_TEXT("IniFile=\"%s\"\n"),
  75. m_tszIniFile);
  76. _tprintf(_TEXT("DataFile=\"%s\". %s keys.\n"),
  77. m_tszDataFile, CommaNumber(m_nMaxKeys, tsz));
  78. _tprintf(_TEXT("Max load = %u, initsize = %d, %d subtables.\n"),
  79. m_nHighLoad, m_nInitSize, m_nSubTables);
  80. _tprintf(_TEXT("Lookup freq = %d, %d-%d threads, %d round%s.\n"),
  81. m_nLookupFreq, m_nMinThreads, m_nMaxThreads,
  82. m_nRounds, (m_nRounds==1 ? "" : "s"));
  83. _tprintf(_TEXT("Seed=%d, CaseInsensitive=%d, MemCmp=%d, LastChars=%d\n"),
  84. m_nSeed, m_fCaseInsensitive, m_fMemCmp, m_nLastChars);
  85. _tprintf(_TEXT("Spin Count: Table = %hd, Bucket = %hd, AdjFactor=%.1f\n"),
  86. m_wTableSpin, m_wBucketSpin, m_dblSpinAdjFctr);
  87. _tprintf(_TEXT("TestIterators=%d, InsertIfNotFound=%d, FindKeyCopy=%d\n"),
  88. m_fTestIterators, m_nInsertIfNotFound, m_nFindKeyCopy);
  89. _tprintf(_TEXT("NonPagedAllocs=%d, DebugSpew=%d, RefTrace=%d, ")
  90. _TEXT("MultiKeys=%d, UseLocks=%d\n"),
  91. m_fNonPagedAllocs, m_fDebugSpew, m_fRefTrace,
  92. m_fMultiKeys, m_fUseLocks);
  93. _tprintf(_TEXT("%s\n"), ptszEpilog);
  94. }
  95. #if defined(IRTLDEBUG)
  96. # define DUMP_INIFILE(pifs, Pro, Epi) pifs->Dump(Pro, Epi)
  97. #else
  98. # define DUMP_INIFILE(pifs, Pro, Epi) ((void) 0)
  99. #endif
  100. DWORD
  101. ReadFileIntoBuffer(
  102. LPCTSTR ptszFile,
  103. PBYTE pbBuffer,
  104. DWORD cbBuffer)
  105. {
  106. #ifndef LKRHASH_KERNEL_MODE
  107. HANDLE hFile =
  108. CreateFile(
  109. ptszFile,
  110. GENERIC_READ,
  111. 0,
  112. NULL,
  113. OPEN_EXISTING,
  114. FILE_ATTRIBUTE_NORMAL,
  115. NULL);
  116. if (hFile == INVALID_HANDLE_VALUE)
  117. return 0;
  118. DWORD cbRead = 0, cbFileSizeLow, cbFileSizeHigh;
  119. cbFileSizeLow = GetFileSize(hFile, &cbFileSizeHigh);
  120. bool fBadFile =
  121. (cbFileSizeHigh != 0
  122. || cbFileSizeLow > cbBuffer
  123. || !ReadFile(hFile, pbBuffer, cbFileSizeLow, &cbRead, NULL));
  124. CloseHandle(hFile);
  125. return fBadFile ? 0 : cbRead;
  126. #else
  127. return 0;
  128. #endif // !LKRHASH_KERNEL_MODE
  129. }
  130. // Do a case-insensitive match of first `cchStr' chars of ptszBuffer
  131. // against ptszStr. Strings assumed to be alphanumeric
  132. bool
  133. StrMatch(
  134. LPCSTR pszBuffer,
  135. LPCSTR pszStr,
  136. unsigned cchStr)
  137. {
  138. LPCSTR psz1 = pszBuffer;
  139. LPCSTR psz2 = pszStr;
  140. unsigned i, j;
  141. bool fMatch = true;
  142. for (i = 0; i < cchStr; ++i)
  143. {
  144. IRTLASSERT(isalnum(*psz1) && isalnum(*psz2));
  145. if (((*psz1++ ^ *psz2++) & 0xDF) != 0)
  146. {
  147. fMatch = false;
  148. break;
  149. }
  150. }
  151. IRTLTRACE0("\tStrMatch: \"");
  152. for (j = 0; j < i + !fMatch; ++j)
  153. IRTLTRACE1("%hc", pszBuffer[j]);
  154. IRTLTRACE0(fMatch ? "\" == \"" : "\" != \"");
  155. for (j = 0; j < i + !fMatch; ++j)
  156. IRTLTRACE1("%hc", pszStr[j]);
  157. IRTLTRACE0("\"\n");
  158. return fMatch;
  159. }
  160. bool
  161. GetNum(
  162. char*& rpch,
  163. int& rn)
  164. {
  165. int fNegative = ('-' == *rpch);
  166. rn = 0;
  167. if (fNegative)
  168. ++rpch;
  169. else if (!('0' <= *rpch && *rpch <= '9'))
  170. return false;
  171. while ('0' <= *rpch && *rpch <= '9')
  172. rn = rn * 10 + (*rpch++ - '0');
  173. if (fNegative)
  174. rn = -rn;
  175. return true;
  176. }
  177. bool
  178. GetDouble(
  179. char*& rpch,
  180. double& rdbl)
  181. {
  182. rdbl = 0;
  183. IRTLTRACE1("GetDouble(\"%s\")\n", rpch);
  184. int n;
  185. bool fValidInt = GetNum(rpch, n);
  186. if (fValidInt)
  187. {
  188. rdbl = n;
  189. if ('.' == *rpch)
  190. {
  191. char* pchFrac = ++rpch;
  192. fValidInt = GetNum(rpch, n);
  193. if (fValidInt)
  194. {
  195. double scale = 1.;
  196. int nDigits = rpch - pchFrac;
  197. while (--nDigits >= 0)
  198. scale *= 10.;
  199. rdbl = (scale * rdbl + n) / scale;
  200. }
  201. }
  202. }
  203. return fValidInt;
  204. }
  205. bool
  206. GetString(
  207. char*& rpch,
  208. char* pszOutput,
  209. unsigned cchOutput)
  210. {
  211. // TODO: handle quoted strings and trailing blanks
  212. bool fGotChars = false;
  213. while ('\0' != *rpch && '\r' != *rpch && '\n' != *rpch )
  214. {
  215. fGotChars = true;
  216. if (cchOutput-- > 0)
  217. *pszOutput++ = *rpch++;
  218. else
  219. ++rpch;
  220. }
  221. if (cchOutput > 0)
  222. *pszOutput = '\0';
  223. return fGotChars;
  224. }
  225. // TODO: break the dependency upon g_po.
  226. int
  227. CIniFileSettings::ParseIniFile(
  228. LPCSTR pszIniFile)
  229. {
  230. strncpy(m_tszIniFile, pszIniFile, _MAX_PATH);
  231. int i, iMaxIndex = -1;
  232. int cMembers = 0;
  233. for (i = 0; ; ++i)
  234. {
  235. if (g_po[i].m_nFieldOffset < 0)
  236. {
  237. iMaxIndex = i;
  238. break;
  239. }
  240. PBYTE pbMember = g_po[i].m_nFieldOffset + ((BYTE*) this);
  241. // Initialize the members of `this' with their default values
  242. switch (g_po[i].m_type)
  243. {
  244. case INI_WORD:
  245. * (WORD*) pbMember = (WORD) g_po[i].m_default;
  246. break;
  247. case INI_DWORD:
  248. * (DWORD*) pbMember = (DWORD) g_po[i].m_default;
  249. break;
  250. case INI_DOUBLE:
  251. * (double*) pbMember = (float) g_po[i].m_default;
  252. break;
  253. case INI_STRING:
  254. strcpy((char*) pbMember, (const char*) g_po[i].m_default);
  255. break;
  256. case INI_BOOL:
  257. * (bool*) pbMember = (bool) (g_po[i].m_default != 0);
  258. break;
  259. default:
  260. IRTLASSERT(! "invalid INI_TYPE");
  261. }
  262. }
  263. DUMP_INIFILE(this, "Before", "");
  264. BYTE abBuffer[2049];
  265. DWORD cbRead = ReadFileIntoBuffer(m_tszIniFile, abBuffer,
  266. sizeof(abBuffer)-1);
  267. if (cbRead == 0)
  268. {
  269. _tprintf(_TEXT("Can't open IniFile `%s'.\n"), m_tszIniFile) ;
  270. return 0;
  271. }
  272. abBuffer[cbRead] = '\0';
  273. bool fInSection = false, fSkipLine = false;
  274. const char szSectionName[] = "HashTest";
  275. unsigned cchSectionName = strlen(szSectionName);
  276. char* pch = (char*) abBuffer;
  277. char* pszEOB = (char*) (abBuffer + cbRead);
  278. // parse the in-memory buffer
  279. while ('\0' != *pch)
  280. {
  281. while (' ' == *pch || '\r' == *pch
  282. || '\n' == *pch || '\t' == *pch)
  283. ++pch;
  284. if ('\0' == *pch)
  285. break;
  286. IRTLTRACE(_TEXT("Line starts with '%hc%hc%hc%hc'\n"),
  287. pch[0], pch[1], pch[2], pch[3]);
  288. // Is this a section name?
  289. if ('[' == *pch)
  290. {
  291. fInSection = false;
  292. ++pch;
  293. while (' ' == *pch || '\t' == *pch)
  294. ++pch;
  295. if (pch + cchSectionName < pszEOB
  296. && StrMatch(pch, szSectionName, cchSectionName))
  297. {
  298. pch += cchSectionName;
  299. while (' ' == *pch || '\t' == *pch)
  300. ++pch;
  301. if (']' == *pch)
  302. {
  303. ++pch;
  304. fInSection = true;
  305. }
  306. }
  307. else
  308. fSkipLine = true;
  309. continue;
  310. }
  311. // skip comments and entire lines if we're not in the right section
  312. if (fSkipLine || ';' == *pch || !fInSection)
  313. {
  314. // skip to end of line
  315. while ('\0' != *pch && '\r' != *pch && '\n' != *pch)
  316. {
  317. IRTLTRACE1("%hc", *pch);
  318. ++pch;
  319. }
  320. IRTLTRACE0("\n");
  321. fSkipLine = false;
  322. continue;
  323. }
  324. fSkipLine = true;
  325. // try to match name=value
  326. for (i = 0; i < iMaxIndex; ++i)
  327. {
  328. IRTLASSERT(isalnum(*pch));
  329. if (pch + g_po[i].m_cchName >= pszEOB
  330. || !StrMatch(pch, g_po[i].m_pszName, g_po[i].m_cchName))
  331. continue;
  332. pch += g_po[i].m_cchName;
  333. while (' ' == *pch || '\t' == *pch)
  334. ++pch;
  335. if ('=' != *pch)
  336. {
  337. IRTLTRACE1("'=' not seen after <%hs>\n", g_po[i].m_pszName);
  338. break;
  339. }
  340. ++pch;
  341. while (' ' == *pch || '\t' == *pch)
  342. ++pch;
  343. PBYTE pbMember = g_po[i].m_nFieldOffset + ((BYTE*) this);
  344. int n;
  345. char sz[_MAX_PATH];
  346. double dbl;
  347. IRTLTRACE1("<%hs>=", g_po[i].m_pszName);
  348. switch (g_po[i].m_type)
  349. {
  350. case INI_WORD:
  351. if (GetNum(pch, n))
  352. {
  353. IRTLTRACE1("%hu\n", (WORD) n);
  354. * (WORD*) pbMember = (WORD) n;
  355. }
  356. else
  357. IRTLTRACE("bad word\n");
  358. break;
  359. case INI_DWORD:
  360. if (GetNum(pch, n))
  361. {
  362. IRTLTRACE1("%u\n", (DWORD) n);
  363. * (DWORD*) pbMember = (DWORD) n;
  364. }
  365. else
  366. IRTLTRACE("bad dword\n");
  367. break;
  368. case INI_DOUBLE:
  369. if (GetDouble(pch, dbl))
  370. {
  371. IRTLTRACE1("%.1f\n", dbl);
  372. * (double*) pbMember = dbl;
  373. }
  374. else
  375. IRTLTRACE("bad double\n");
  376. break;
  377. case INI_STRING:
  378. if (GetString(pch, sz, sizeof(sz)/sizeof(sz[0])))
  379. {
  380. IRTLTRACE1("%hs\n", sz);
  381. strcpy((char*) pbMember, sz);
  382. }
  383. else
  384. IRTLTRACE("bad string\n");
  385. break;
  386. case INI_BOOL:
  387. if (GetNum(pch, n))
  388. {
  389. IRTLTRACE1("%d\n", n);
  390. * (bool*) pbMember = (n != 0);
  391. }
  392. else
  393. IRTLTRACE("bad bool\n");
  394. break;
  395. default:
  396. IRTLASSERT(! "invalid INI_TYPE");
  397. }
  398. ++cMembers;
  399. fSkipLine = false;
  400. break;
  401. }
  402. }
  403. DUMP_INIFILE(this, "Parsed", "---");
  404. return cMembers;
  405. }
  406. void
  407. CIniFileSettings::ReadIniFile(
  408. LPCTSTR ptszIniFile)
  409. {
  410. // IrtlSetDebugOutput(1);
  411. ParseIniFile(ptszIniFile);
  412. m_nMaxKeys = min(max(1, m_nMaxKeys), MAXKEYS);
  413. m_nHighLoad = max(1, m_nHighLoad);
  414. m_nMinThreads = max(1, m_nMinThreads);
  415. m_nMaxThreads = min(MAX_THREADS, max(1, m_nMaxThreads));
  416. // If we're not using a real lock, then we're not threadsafe
  417. if (CWordHash::TableLock::LockType() == LOCK_FAKELOCK
  418. || CWordHash::BucketLock::LockType() == LOCK_FAKELOCK)
  419. m_nMinThreads = m_nMaxThreads = 1;
  420. m_nRounds = max(1, m_nRounds);
  421. CWordHash::sm_fCaseInsensitive = m_fCaseInsensitive;
  422. CWordHash::sm_fMemCmp = m_fMemCmp;
  423. CWordHash::sm_nLastChars = m_nLastChars;
  424. CWordHash::sm_fNonPagedAllocs = m_fNonPagedAllocs;
  425. CWordHash::sm_fRefTrace = m_fRefTrace;
  426. CWordHash::sm_fMultiKeys = m_fMultiKeys;
  427. CWordHash::sm_fUseLocks = m_fUseLocks;
  428. #ifdef LOCK_DEFAULT_SPIN_IMPLEMENTATION
  429. # ifdef LKRHASH_GLOBAL_LOCK
  430. CWordHash::GlobalLock::SetDefaultSpinAdjustmentFactor(m_dblSpinAdjFctr);
  431. # endif
  432. CWordHash::TableLock::SetDefaultSpinAdjustmentFactor(m_dblSpinAdjFctr);
  433. CWordHash::BucketLock::SetDefaultSpinAdjustmentFactor(m_dblSpinAdjFctr);
  434. #endif // LOCK_DEFAULT_SPIN_IMPLEMENTATION
  435. if (CWordHash::TableLock::Recursion() != LOCK_RECURSIVE)
  436. {
  437. IRTLTRACE1("TableLock %s is not recursive. No InsertIfNotFound\n",
  438. CWordHash::TableLock::ClassName());
  439. m_nInsertIfNotFound = 0;
  440. }
  441. if (!CWordHash::sm_fUseLocks)
  442. {
  443. IRTLTRACE0("Not using locks. One thread only.\n");
  444. m_nMinThreads = m_nMaxThreads = 1;
  445. }
  446. }