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.

513 lines
14 KiB

  1. /*++
  2. Copyright (c) 1998-2000 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. Internet Information Server RunTime Library
  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_dblHighLoad, "MaxLoadFactor", INI_DOUBLE, 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_fRefTrace, "RefTrace", INI_BOOL, FALSE),
  62. {-1} // last entry
  63. };
  64. void
  65. CIniFileSettings::Dump(
  66. LPCTSTR ptszProlog,
  67. LPCTSTR ptszEpilog) const
  68. {
  69. TCHAR tsz[50];
  70. _tprintf(_TEXT("%s\n"), ptszProlog);
  71. _tprintf(_TEXT("IniFile=\"%s\"\n"),
  72. m_tszIniFile);
  73. _tprintf(_TEXT("DataFile=\"%s\". %s keys.\n"),
  74. m_tszDataFile, CommaNumber(m_nMaxKeys, tsz));
  75. _tprintf(_TEXT("Max load = %.1f, initsize = %d, %d subtables.\n"),
  76. m_dblHighLoad, m_nInitSize, m_nSubTables);
  77. _tprintf(_TEXT("Lookup freq = %d, %d-%d threads, %d round%s.\n"),
  78. m_nLookupFreq, m_nMinThreads, m_nMaxThreads,
  79. m_nRounds, (m_nRounds==1 ? "" : "s"));
  80. _tprintf(_TEXT("Seed=%d, CaseInsensitive=%d, MemCmp=%d, LastChars=%d\n"),
  81. m_nSeed, m_fCaseInsensitive, m_fMemCmp, m_nLastChars);
  82. _tprintf(_TEXT("Spin Count: Table = %hd, Bucket = %hd, AdjFactor=%.1f\n"),
  83. m_wTableSpin, m_wBucketSpin, m_dblSpinAdjFctr);
  84. _tprintf(_TEXT("TestIterators=%d, InsertIfNotFound=%d, FindKeyCopy=%d\n"),
  85. m_fTestIterators, m_nInsertIfNotFound, m_nFindKeyCopy);
  86. _tprintf(_TEXT("NonPagedAllocs=%d, RefTrace=%d\n"),
  87. m_fNonPagedAllocs, m_fRefTrace);
  88. _tprintf(_TEXT("%s\n"), ptszEpilog);
  89. }
  90. #if defined(IRTLDEBUG)
  91. # define DUMP_INIFILE(pifs, Pro, Epi) pifs->Dump(Pro, Epi)
  92. #else
  93. # define DUMP_INIFILE(pifs, Pro, Epi) ((void) 0)
  94. #endif
  95. DWORD
  96. ReadFileIntoBuffer(
  97. LPCTSTR ptszFile,
  98. PBYTE pbBuffer,
  99. DWORD cbBuffer)
  100. {
  101. #ifndef LKRHASH_KERNEL_MODE
  102. HANDLE hFile =
  103. CreateFile(
  104. ptszFile,
  105. GENERIC_READ,
  106. 0,
  107. NULL,
  108. OPEN_EXISTING,
  109. FILE_ATTRIBUTE_NORMAL,
  110. NULL);
  111. if (hFile == INVALID_HANDLE_VALUE)
  112. return 0;
  113. DWORD cbRead = 0, cbFileSizeLow, cbFileSizeHigh;
  114. cbFileSizeLow = GetFileSize(hFile, &cbFileSizeHigh);
  115. bool fBadFile =
  116. (cbFileSizeHigh != 0
  117. || cbFileSizeLow > cbBuffer
  118. || !ReadFile(hFile, pbBuffer, cbFileSizeLow, &cbRead, NULL));
  119. CloseHandle(hFile);
  120. return fBadFile ? 0 : cbRead;
  121. #else
  122. return 0;
  123. #endif // !LKRHASH_KERNEL_MODE
  124. }
  125. // Do a case-insensitive match of first `cchStr' chars of ptszBuffer
  126. // against ptszStr. Strings assumed to be alphanumeric
  127. bool
  128. StrMatch(
  129. LPCSTR pszBuffer,
  130. LPCSTR pszStr,
  131. unsigned cchStr)
  132. {
  133. LPCSTR psz1 = pszBuffer;
  134. LPCSTR psz2 = pszStr;
  135. unsigned i, j;
  136. bool fMatch = true;
  137. for (i = 0; i < cchStr; ++i)
  138. {
  139. IRTLASSERT(isalnum(*psz1) && isalnum(*psz2));
  140. if (((*psz1++ ^ *psz2++) & 0xDF) != 0)
  141. {
  142. fMatch = false;
  143. break;
  144. }
  145. }
  146. IRTLTRACE0("\tStrMatch: \"");
  147. for (j = 0; j < i + !fMatch; ++j)
  148. IRTLTRACE1("%hc", pszBuffer[j]);
  149. IRTLTRACE0(fMatch ? "\" == \"" : "\" != \"");
  150. for (j = 0; j < i + !fMatch; ++j)
  151. IRTLTRACE1("%hc", pszStr[j]);
  152. IRTLTRACE0("\"\n");
  153. return fMatch;
  154. }
  155. bool
  156. GetNum(
  157. char*& rpch,
  158. int& rn)
  159. {
  160. int fNegative = ('-' == *rpch);
  161. rn = 0;
  162. if (fNegative)
  163. ++rpch;
  164. else if (!('0' <= *rpch && *rpch <= '9'))
  165. return false;
  166. while ('0' <= *rpch && *rpch <= '9')
  167. rn = rn * 10 + (*rpch++ - '0');
  168. if (fNegative)
  169. rn = -rn;
  170. return true;
  171. }
  172. bool
  173. GetDouble(
  174. char*& rpch,
  175. double& rdbl)
  176. {
  177. rdbl = 0;
  178. int n;
  179. bool fValidInt = GetNum(rpch, n);
  180. if (fValidInt)
  181. {
  182. rdbl = n;
  183. // BUGBUG: ignore fractional part, if any
  184. if ('.' == *rpch)
  185. {
  186. ++rpch;
  187. GetNum(rpch, n);
  188. }
  189. }
  190. return fValidInt;
  191. }
  192. bool
  193. GetString(
  194. char*& rpch,
  195. char* pszOutput,
  196. unsigned cchOutput)
  197. {
  198. // TODO: handle quoted strings and trailing blanks
  199. bool fGotChars = false;
  200. while ('\0' != *rpch && '\r' != *rpch && '\n' != *rpch )
  201. {
  202. fGotChars = true;
  203. if (cchOutput-- > 0)
  204. *pszOutput++ = *rpch++;
  205. else
  206. ++rpch;
  207. }
  208. if (cchOutput > 0)
  209. *pszOutput = '\0';
  210. return fGotChars;
  211. }
  212. // TODO: break the dependency upon g_po.
  213. int
  214. CIniFileSettings::ParseIniFile(
  215. LPCSTR pszIniFile)
  216. {
  217. strncpy(m_tszIniFile, pszIniFile, _MAX_PATH);
  218. int i, iMaxIndex = -1;
  219. int cMembers = 0;
  220. for (i = 0; ; ++i)
  221. {
  222. if (g_po[i].m_nFieldOffset < 0)
  223. {
  224. iMaxIndex = i;
  225. break;
  226. }
  227. PBYTE pbMember = g_po[i].m_nFieldOffset + ((BYTE*) this);
  228. // Initialize the members of `this' with their default values
  229. switch (g_po[i].m_type)
  230. {
  231. case INI_WORD:
  232. * (WORD*) pbMember = (WORD) g_po[i].m_default;
  233. break;
  234. case INI_DWORD:
  235. * (DWORD*) pbMember = (DWORD) g_po[i].m_default;
  236. break;
  237. case INI_DOUBLE:
  238. * (double*) pbMember = (float) g_po[i].m_default;
  239. break;
  240. case INI_STRING:
  241. strcpy((char*) pbMember, (const char*) g_po[i].m_default);
  242. break;
  243. case INI_BOOL:
  244. * (bool*) pbMember = (bool) (g_po[i].m_default != 0);
  245. break;
  246. default:
  247. IRTLASSERT(! "invalid INI_TYPE");
  248. }
  249. }
  250. DUMP_INIFILE(this, "Before", "");
  251. BYTE abBuffer[2049];
  252. DWORD cbRead = ReadFileIntoBuffer(m_tszIniFile, abBuffer,
  253. sizeof(abBuffer)-1);
  254. if (cbRead == 0)
  255. {
  256. _tprintf(_TEXT("Can't open IniFile `%s'.\n"), m_tszIniFile) ;
  257. return 0;
  258. }
  259. abBuffer[cbRead] = '\0';
  260. bool fInSection = false, fSkipLine = false;
  261. bool fDone = false;
  262. const char szSectionName[] = "HashTest";
  263. unsigned cchSectionName = strlen(szSectionName);
  264. char* pch = (char*) abBuffer;
  265. char* pszEOB = (char*) (abBuffer + cbRead);
  266. // parse the in-memory buffer
  267. while ('\0' != *pch)
  268. {
  269. while (' ' == *pch || '\r' == *pch
  270. || '\n' == *pch || '\t' == *pch)
  271. ++pch;
  272. if ('\0' == *pch)
  273. break;
  274. IRTLTRACE(_TEXT("Line starts with '%hc%hc%hc%hc'\n"),
  275. pch[0], pch[1], pch[2], pch[3]);
  276. // Is this a section name?
  277. if ('[' == *pch)
  278. {
  279. fInSection = false;
  280. ++pch;
  281. while (' ' == *pch || '\t' == *pch)
  282. ++pch;
  283. if (pch + cchSectionName < pszEOB
  284. && StrMatch(pch, szSectionName, cchSectionName))
  285. {
  286. pch += cchSectionName;
  287. while (' ' == *pch || '\t' == *pch)
  288. ++pch;
  289. if (']' == *pch)
  290. {
  291. ++pch;
  292. fInSection = true;
  293. }
  294. }
  295. else
  296. fSkipLine = true;
  297. continue;
  298. }
  299. // skip comments and entire lines if we're not in the right section
  300. if (fSkipLine || ';' == *pch || !fInSection)
  301. {
  302. // skip to end of line
  303. while ('\0' != *pch && '\r' != *pch && '\n' != *pch)
  304. {
  305. IRTLTRACE1("%hc", *pch);
  306. ++pch;
  307. }
  308. IRTLTRACE0("\n");
  309. fSkipLine = false;
  310. continue;
  311. }
  312. fSkipLine = true;
  313. // try to match name=value
  314. for (i = 0; i < iMaxIndex; ++i)
  315. {
  316. IRTLASSERT(isalnum(*pch));
  317. if (pch + g_po[i].m_cchName >= pszEOB
  318. || !StrMatch(pch, g_po[i].m_pszName, g_po[i].m_cchName))
  319. continue;
  320. pch += g_po[i].m_cchName;
  321. while (' ' == *pch || '\t' == *pch)
  322. ++pch;
  323. if ('=' != *pch)
  324. {
  325. IRTLTRACE1("'=' not seen after <%hs>\n", g_po[i].m_pszName);
  326. break;
  327. }
  328. ++pch;
  329. while (' ' == *pch || '\t' == *pch)
  330. ++pch;
  331. PBYTE pbMember = g_po[i].m_nFieldOffset + ((BYTE*) this);
  332. int n;
  333. char sz[_MAX_PATH];
  334. double dbl;
  335. IRTLTRACE1("<%hs>=", g_po[i].m_pszName);
  336. switch (g_po[i].m_type)
  337. {
  338. case INI_WORD:
  339. if (GetNum(pch, n))
  340. {
  341. IRTLTRACE1("%hu\n", (WORD) n);
  342. * (WORD*) pbMember = (WORD) n;
  343. }
  344. else
  345. IRTLTRACE("bad word\n");
  346. break;
  347. case INI_DWORD:
  348. if (GetNum(pch, n))
  349. {
  350. IRTLTRACE1("%u\n", (DWORD) n);
  351. * (DWORD*) pbMember = (DWORD) n;
  352. }
  353. else
  354. IRTLTRACE("bad dword\n");
  355. break;
  356. case INI_DOUBLE:
  357. if (GetDouble(pch, dbl))
  358. {
  359. IRTLTRACE1("%.1f\n", dbl);
  360. * (double*) pbMember = dbl;
  361. }
  362. else
  363. IRTLTRACE("bad double\n");
  364. break;
  365. case INI_STRING:
  366. if (GetString(pch, sz, sizeof(sz)/sizeof(sz[0])))
  367. {
  368. IRTLTRACE1("%hs\n", sz);
  369. strcpy((char*) pbMember, sz);
  370. }
  371. else
  372. IRTLTRACE("bad string\n");
  373. break;
  374. case INI_BOOL:
  375. if (GetNum(pch, n))
  376. {
  377. IRTLTRACE1("%d\n", n);
  378. * (bool*) pbMember = (n != 0);
  379. }
  380. else
  381. IRTLTRACE("bad bool\n");
  382. break;
  383. default:
  384. IRTLASSERT(! "invalid INI_TYPE");
  385. }
  386. ++cMembers;
  387. fSkipLine = false;
  388. break;
  389. }
  390. }
  391. DUMP_INIFILE(this, "Parsed", "---");
  392. return cMembers;
  393. }
  394. void
  395. CIniFileSettings::ReadIniFile(
  396. LPCTSTR ptszIniFile)
  397. {
  398. ParseIniFile(ptszIniFile);
  399. m_nMaxKeys = min(max(1, m_nMaxKeys), MAXKEYS);
  400. m_dblHighLoad = max(1, m_dblHighLoad);
  401. m_nMinThreads = max(1, m_nMinThreads);
  402. m_nMaxThreads = min(MAX_THREADS, max(1, m_nMaxThreads));
  403. // If we're not using a real lock, then we're not threadsafe
  404. if (CWordHash::TableLock::LockType() == LOCK_FAKELOCK
  405. || CWordHash::BucketLock::LockType() == LOCK_FAKELOCK)
  406. m_nMinThreads = m_nMaxThreads = 1;
  407. m_nRounds = max(1, m_nRounds);
  408. CWordHash::sm_fCaseInsensitive = m_fCaseInsensitive;
  409. CWordHash::sm_fMemCmp = m_fMemCmp;
  410. CWordHash::sm_nLastChars = m_nLastChars;
  411. CWordHash::sm_fNonPagedAllocs = m_fNonPagedAllocs;
  412. CWordHash::sm_fRefTrace = m_fRefTrace;
  413. #ifdef LOCK_DEFAULT_SPIN_IMPLEMENTATION
  414. # ifdef LKRHASH_GLOBAL_LOCK
  415. CWordHash::GlobalLock::SetDefaultSpinAdjustmentFactor(m_dblSpinAdjFctr);
  416. # endif
  417. CWordHash::TableLock::SetDefaultSpinAdjustmentFactor(m_dblSpinAdjFctr);
  418. CWordHash::BucketLock::SetDefaultSpinAdjustmentFactor(m_dblSpinAdjFctr);
  419. #endif // LOCK_DEFAULT_SPIN_IMPLEMENTATION
  420. if (CWordHash::TableLock::Recursion() != LOCK_RECURSIVE
  421. || CWordHash::BucketLock::LockType() != LOCK_RECURSIVE)
  422. m_nInsertIfNotFound = 0;
  423. }