Windows NT 4.0 source code leak
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.

530 lines
11 KiB

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