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.

531 lines
12 KiB

  1. /***
  2. * mtest.c - Multi-thread debug testing module
  3. *
  4. * Copyright (c) 1987-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * This source contains a group of routines used for multi-thread
  8. * testing. In order to use the debug flavor of these routines, you
  9. * MUST link special debug versions of multi-thread crt0dat.obj and
  10. * mlock.obj into your program.
  11. *
  12. * [NOTE: This source module is NOT included in the C runtime library;
  13. * it is used only for testing and must be explicitly linked into the
  14. * test program.]
  15. *
  16. *Revision History:
  17. * 12-??-87 JCR Module created.
  18. * 06-17-88 JCR Misc. bug fixes.
  19. * 08-03-88 JCR Use the stdio.h value of _NFILE
  20. * 10-03-88 JCR 386: Use SYS calls, not DOS calls
  21. * 10-04-88 JCR 386: Removed 'far' keyword
  22. * 10-10-88 GJF Made API names match DOSCALLS.H
  23. * 06-08-89 JCR New 386 _beginthread interface; also brought
  24. * lots of new options across from the C600 tree.
  25. * 07-11-89 JCR Added _POPEN_LOCK to _locknames[] array
  26. * 07-14-89 JCR Added _LOCKTAB_LOCK support
  27. * 07-24-90 SBM Removed '32' from API names
  28. * 09-06-94 CFW Change M_I386 to _M_IX86.
  29. *
  30. *******************************************************************************/
  31. #ifdef _M_IX86
  32. #ifdef STACKALLOC
  33. #error Can't define STACKALLOC in 386 mode
  34. #endif
  35. #endif
  36. #ifdef _M_IX86
  37. #ifdef _DOSCREATETHREAD_
  38. #error Currently can't define _DOSCREATETHREAD_ in 386 mode
  39. #endif
  40. #endif
  41. #ifdef _DOSCREATETHREAD_
  42. #ifndef STACKALLOC
  43. #error Can't define _DOSCREATETHREAD_ without STACKALLOC
  44. #endif
  45. #endif
  46. /*
  47. Multi-thread core tester module.
  48. */
  49. #include <malloc.h>
  50. #include <process.h>
  51. #include <stdio.h>
  52. #include <stdlib.h>
  53. #include <stddef.h>
  54. #include <io.h>
  55. #include <mtest.h>
  56. #ifdef DEBUG
  57. #include <mtdll.h>
  58. #include <file2.h>
  59. #endif
  60. /* Define FAR to be blank for the 386 and far otherwise. */
  61. #undef FAR
  62. #ifdef _M_IX86
  63. #define FAR
  64. #else
  65. #define FAR far
  66. #endif
  67. /* define stack size */
  68. #ifdef _M_IX86
  69. #define _STACKSIZE_ 8192
  70. #else
  71. #define _STACKSIZE_ 2048
  72. #endif
  73. /* routines */
  74. #ifdef _M_IX86
  75. unsigned _syscall DOSSLEEP (unsigned long) ;
  76. #else
  77. unsigned FAR pascal DOSSLEEP (unsigned long) ;
  78. #endif
  79. int main ( int argc , char * * argv ) ;
  80. int minit(void);
  81. void childcode ( void FAR * arg ) ;
  82. #ifdef _DOSCREATETHREAD_
  83. #ifndef _M_IX86
  84. void childcode ( void ) ;
  85. unsigned FAR pascal DOSCREATETHREAD (void FAR *, void FAR *, void FAR *);
  86. #endif
  87. #else
  88. void childcode ( void FAR * arg ) ;
  89. #endif
  90. int mterm(void);
  91. /* global data */
  92. char Result [ _THREADMAX_ ] ;
  93. unsigned Synchronize ;
  94. #ifdef DEBUG
  95. /* Array of lock names. This order must match the declarations in
  96. mtdll.h and mtdll.inc. */
  97. char *_locknames[] = {
  98. "** NO LOCK 0 ** ", /* lock values are 1-based */
  99. "_SIGNAL_LOCK ",
  100. "_IOB_SCAN_LOCK ",
  101. "_TMPNAM_LOCK ",
  102. "_INPUT_LOCK ",
  103. "_OUTPUT_LOCK ",
  104. "_CSCANF_LOCK ",
  105. "_CPRINTF_LOCK ",
  106. "_CONIO_LOCK ",
  107. "_HEAP_LOCK ",
  108. "_BHEAP_LOCK ",
  109. "_TIME_LOCK ",
  110. "_ENV_LOCK ",
  111. "_EXIT_LOCK1 ",
  112. "_EXIT_LOCK2 ",
  113. "_THREADDATA_LOCK",
  114. "_POPEN_LOCK ",
  115. "_SSCANF_LOCK ",
  116. "_SPRINTF_LOCK ",
  117. #ifdef _M_IX86
  118. "_VSPRINTF_LOCK ",
  119. "_LOCKTAB_LOCK "
  120. #else
  121. "_VSPRINTF_LOCK "
  122. #endif
  123. };
  124. /* Minimal sanity check on above array. */
  125. #ifdef _M_IX86
  126. #if ((_LOCKTAB_LOCK+1)-_STREAM_LOCKS)
  127. #error *** _locknames[] does agree with lock values ***
  128. #endif
  129. #else /* !_M_IX86 */
  130. #if ((_VSPRINTF_LOCK+1)-_STREAM_LOCKS)
  131. #error *** _locknames[] does agree with lock values ***
  132. #endif
  133. #endif /* _M_IX86 */
  134. #endif /* DEBUG */
  135. /***
  136. * main() - Main mthread testing shell
  137. *
  138. *Purpose:
  139. * Provides a general purpose shell for mthread testing.
  140. * The module does the following:
  141. *
  142. * (1) Call minit() to perform test initialization operations.
  143. *
  144. * (2) Begins one thread for each argument passed to the
  145. * program. Each thread is passed the corresponding argument.
  146. * Thread begin location is assumed to be at routine childcode();
  147. *
  148. * (3) Waits for all threads to terminate.
  149. *
  150. * (4) Calls mterm() to perform termination operations.
  151. *
  152. * Note that minit(), childcode(), and mterm() are routines that
  153. * are external to this source. Again, this source doesn't care
  154. * what their purpose or operation is.
  155. *
  156. * Also, childcode() is expected to conform to the following rules:
  157. *
  158. * (1) The childcode should not start running until
  159. * the variable 'Synchronize' becomes non-zero.
  160. *
  161. * (2) When the thread is done executing, it should set
  162. * the value Result[threadid] to a non-zero value so the
  163. * parent (i.e., this routine) knows it has completed.
  164. *
  165. *Entry:
  166. *
  167. *Exit:
  168. *
  169. *Exceptions:
  170. *
  171. *******************************************************************************/
  172. int main ( int argc , char * * argv )
  173. {
  174. int rc ;
  175. unsigned result = 0 ;
  176. long ChildCount ;
  177. int NumThreads ;
  178. int t ;
  179. int r ;
  180. int MaxThread = 0 ;
  181. long LoopCount ;
  182. #ifdef THREADLOOP
  183. char **argvsave;
  184. #endif
  185. #ifndef _M_IX86
  186. char * stackbottom ;
  187. #endif
  188. #ifdef DEBUG
  189. if ( argc > MAXTHREADID) {
  190. printf("*** ERROR: Mthread debugging only supports %u threads ***\n", MAXTHREADID);
  191. return(-1);
  192. }
  193. #endif
  194. if ( -- argc > (_THREADMAX_-1) )
  195. {
  196. printf ( "*** Error: Too many arguments***\n" ) ;
  197. return (-1) ;
  198. }
  199. /* Call the initiation routine */
  200. if (minit() != 0) {
  201. printf("*** Error: From minit() routine ***\n");
  202. return(-1);
  203. }
  204. /* Bring up the threads */
  205. printf ( "Process ID = %u, Thread ID = %d, ArgCount= %d\r\n" ,
  206. getpid ( ) , * _threadid , argc ) ;
  207. #ifndef _M_IX86
  208. #ifdef STACKALLOC
  209. printf( "(thread stacks allocated explicilty by mtest suite)\r\n");
  210. #else
  211. printf( "(thread stacks allocated implicitly via _beginthread)\r\n");
  212. #endif
  213. #endif
  214. #ifdef THREADLOOP
  215. /* Bring up all the threads several times (so tids get re-used) */
  216. argvsave=argv;
  217. for (threadloop=1;threadloop<=_THREADLOOPCNT_;threadloop++) {
  218. printf("\nThreadloop = %i\n", threadloop);
  219. argv=argvsave;
  220. #endif
  221. NumThreads = 0 ;
  222. while ( * ++ argv )
  223. {
  224. ChildCount = atol ( * argv ) ;
  225. #ifdef _M_IX86
  226. rc = _beginthread ( (void FAR *) childcode , _STACKSIZE_ ,
  227. (void FAR *) ChildCount ) ;
  228. if ( rc == -1 )
  229. #else /* !_M_IX86 */
  230. #ifdef STACKALLOC
  231. if ( ! ( stackbottom = _fmalloc ( _STACKSIZE_ ) ) )
  232. {
  233. printf ( "*** Error: Could not allocate a stack ***\n" ) ;
  234. break ;
  235. }
  236. #else
  237. stackbottom = (void FAR *) NULL;
  238. #endif
  239. #ifdef _DOSCREATETHREAD_
  240. stackbottom+=_STACKSIZE_-16; /* point to end of malloc'd block */
  241. rc1 = DOSCREATETHREAD( (void FAR *) childcode, &rc,
  242. (void FAR *) stackbottom);
  243. if (rc1 != 0)
  244. #else
  245. rc = _beginthread ( (void FAR *) childcode , (void FAR *) stackbottom ,
  246. _STACKSIZE_ , (void FAR *) ChildCount ) ;
  247. if ( rc == -1 )
  248. #endif
  249. #endif /* _M_IX86 */
  250. {
  251. printf ("*** Error: Could not Spawn %d-th Thread (argument=%ld) ***\n" ,
  252. NumThreads + 1 , ChildCount ) ;
  253. break ;
  254. }
  255. if ( rc > MaxThread )
  256. MaxThread = rc ;
  257. printf ( "Spawning %d-th Thread %d with argument=%ld\r\n" ,
  258. ++ NumThreads , rc , ChildCount ) ;
  259. }
  260. printf ( "NumThreads = %d, MaxThread = %d\r\n" ,
  261. NumThreads, MaxThread ) ;
  262. /* Let the threads begin and wait for them to term. */
  263. LoopCount = 0L ;
  264. Synchronize = 1 ;
  265. for ( t = 0 ; t < NumThreads ; ++ t )
  266. {
  267. r = 0 ;
  268. while ( ! Result [ r ] )
  269. {
  270. DOSSLEEP ( 0L ) ;
  271. if ( ++ r > MaxThread )
  272. {
  273. r = 0 ;
  274. printf ( "%ld\r" , LoopCount ++ ) ;
  275. }
  276. }
  277. printf ( "%d: Thread %d Done.\r\n" , t , r) ;
  278. Result [ r ] = '\0' ;
  279. }
  280. #ifdef THREADLOOP
  281. }
  282. #endif
  283. /* All the threads have completed. Call the term routine and return. */
  284. if (mterm() != 0) {
  285. printf("*** Error: From mterm() routine ***\n");
  286. return(-1);
  287. }
  288. printf("\nDone!\n");
  289. return 0 ;
  290. }
  291. #ifdef DEBUG
  292. /***
  293. * Debug Print Routines - Display useful mthread lock data
  294. *
  295. *Purpose:
  296. * The following routines extract information from the multi-thread
  297. * debug data bases and print them out in various formats.
  298. * In order to use these routines, you MUST link special debug
  299. * versions of multi-thread crt0dat.obj and mlock.obj into your program.
  300. *
  301. *Entry:
  302. *
  303. *Exit:
  304. * 0 = success
  305. * 0! = failure
  306. *
  307. *Exceptions:
  308. *
  309. *******************************************************************************/
  310. /*--- Print lock routine ---*/
  311. int printlock(int locknum)
  312. {
  313. int retval;
  314. #ifdef _INIT_LOCKS
  315. if (locknum >= _STREAM_LOCKS)
  316. printf("\nValidating lock #%i (%s):\n",locknum, "not a 'single lock'");
  317. else
  318. printf("\nValidating lock #%i: %s\n",locknum, _locknames[locknum]);
  319. #else
  320. printf("\nValidating lock #%i (%s, %s):\n",
  321. locknum,
  322. (locknum >= _STREAM_LOCKS ?
  323. "not a 'single' lock" : _locknames[locknum]),
  324. (_lock_exist(locknum) ?
  325. "initialized" : "NOT initialized")
  326. );
  327. #endif
  328. retval = _check_lock(locknum);
  329. printf("\tLock count = %u\r\n", _lock_cnt(locknum));
  330. printf("\tCollision count = %u\r\n", _collide_cnt(locknum));
  331. if (retval != 0)
  332. printf("\t*** ERROR: Checking lock ***\n");
  333. return(retval);
  334. }
  335. /*--- Printf single locks ---*/
  336. int print_single_locks(void)
  337. {
  338. int locknum;
  339. int retval=0;
  340. int lockval;
  341. printf("\n--- Single Locks ---\n");
  342. #ifdef _INIT_LOCKS
  343. printf("\t\t\t\tlock count\tcollide count\n");
  344. for (locknum=1;locknum<_STREAM_LOCKS;locknum++) {
  345. if (lockval = (_check_lock(locknum) != 0))
  346. retval++;
  347. printf("#%i / %s\t\t%u\t\t%u\t%s\n",
  348. locknum, _locknames[locknum], _lock_cnt(locknum),
  349. _collide_cnt(locknum), (lockval ? "*LOCK ERROR*" : "") );
  350. }
  351. #else
  352. printf("\t\t\t\tlock count\tcollide count\texists?\n");
  353. for (locknum=1;locknum<_STREAM_LOCKS;locknum++) {
  354. if (lockval = (_check_lock(locknum) != 0))
  355. retval++;
  356. printf("#%i / %s\t\t%u\t\t%u\t\t%s\t%s\n",
  357. locknum, _locknames[locknum], _lock_cnt(locknum),
  358. _collide_cnt(locknum),
  359. (_lock_exist(locknum) ? "YES" : "NO"),
  360. (lockval ? "*LOCK ERROR*" : "") );
  361. }
  362. #endif
  363. return(retval);
  364. }
  365. /*--- Print all stdio locks ---*/
  366. int print_stdio_locks(void)
  367. {
  368. int i;
  369. int locknum;
  370. int retval=0;
  371. int lockval;
  372. printf("\n--- Stdio Locks ---\n");
  373. #ifdef _INIT_LOCKS
  374. printf("stream\t\tlock count\tcollide count\n");
  375. for (i=0;i<_NFILE;i++) {
  376. locknum = _stream_locknum(i);
  377. if (lockval = (_check_lock(locknum) != 0))
  378. retval++;
  379. printf("%i\t\t%u\t\t%u\t%s\n",
  380. i, _lock_cnt(locknum), _collide_cnt(locknum),
  381. (lockval ? "*LOCK ERROR*" : "") );
  382. }
  383. #else
  384. printf("stream\t\tlock count\tcollide count\texists?\n");
  385. for (i=0;i<_NFILE;i++) {
  386. locknum = _stream_locknum(i);
  387. if (lockval = (_check_lock(locknum) != 0))
  388. retval++;
  389. printf("%i\t\t%u\t\t%u\t\t%s\t%s\n",
  390. i, _lock_cnt(locknum), _collide_cnt(locknum),
  391. (_lock_exist(locknum) ? "YES" : "NO"),
  392. (lockval ? "*LOCK ERROR*" : "") );
  393. }
  394. #endif
  395. return(retval);
  396. }
  397. /*--- Print all lowio locks ---*/
  398. int print_lowio_locks(void)
  399. {
  400. int i;
  401. int locknum;
  402. int retval=0;
  403. int lockval;
  404. printf("\n--- Lowio locks ---\n");
  405. #ifdef _INIT_LOCKS
  406. printf("fh\t\tlock count\tcollide count\n");
  407. for (i=0;i<_NFILE;i++) {
  408. locknum = _fh_locknum(i);
  409. if (lockval = (_check_lock(locknum) != 0))
  410. retval++;
  411. printf("%i\t\t%u\t\t%u\t%s\n",
  412. i, _lock_cnt(locknum), _collide_cnt(locknum),
  413. (lockval ? "*LOCK ERROR*" : "") );
  414. }
  415. #else
  416. printf("fh\t\tlock count\tcollide count\texists?\n");
  417. for (i=0;i<_NFILE;i++) {
  418. locknum = _fh_locknum(i);
  419. if (lockval = (_check_lock(locknum) != 0))
  420. retval++;
  421. printf("%i\t\t%u\t\t%u\t\t%s\t%s\n",
  422. i, _lock_cnt(locknum), _collide_cnt(locknum),
  423. (_lock_exist(locknum) ? "YES" : "NO"),
  424. (lockval ? "*LOCK ERROR*" : "") );
  425. }
  426. #endif
  427. return(retval);
  428. }
  429. /*--- Print all I/O locks ---*/
  430. int print_iolocks(void)
  431. {
  432. int retval=0;
  433. retval += print_stdio_locks();
  434. retval += print_lowio_locks();
  435. return(retval);
  436. }
  437. /*--- Print all Locks ---*/
  438. int print_locks(void)
  439. {
  440. int retval=0;
  441. retval += print_single_locks();
  442. retval += print_iolocks();
  443. return(retval);
  444. }
  445. #endif