threadMain.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161
  1. #ident "ldclt @(#)threadMain.c 1.40 01/05/04"
  2. /** BEGIN COPYRIGHT BLOCK
  3. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  4. * Copyright (C) 2006 Red Hat, Inc.
  5. * All rights reserved.
  6. *
  7. * License: GPL (version 3 or any later version).
  8. * See LICENSE for details.
  9. * END COPYRIGHT BLOCK **/
  10. #ifdef HAVE_CONFIG_H
  11. # include <config.h>
  12. #endif
  13. /*
  14. FILE : threadMain.c
  15. AUTHOR : Jean-Luc SCHWING
  16. VERSION : 1.0
  17. DATE : 04 December 1998
  18. DESCRIPTION :
  19. This file implements the main/core part of the
  20. threads. The ldap part is in another source file.
  21. LOCAL : None.
  22. HISTORY :
  23. ---------+--------------+------------------------------------------------------
  24. dd/mm/yy | Author | Comments
  25. ---------+--------------+------------------------------------------------------
  26. 04/12/98 | JL Schwing | Creation
  27. ---------+--------------+------------------------------------------------------
  28. 10/12/98 | JL Schwing | 1.2 : Add nb of errors statistics.
  29. ---------+--------------+------------------------------------------------------
  30. 10/12/98 | JL Schwing | 1.3 : Implement asynchronous mode.
  31. ---------+--------------+------------------------------------------------------
  32. 11/12/98 | JL Schwing | 1.4 : Implement max errors threshold.
  33. | fflush(stdout) after each printf.
  34. ---------+--------------+------------------------------------------------------
  35. 14/12/98 | JL Schwing | 1.5 : Implement "-e close".
  36. | Add "thread is dead" message.
  37. ---------+--------------+------------------------------------------------------
  38. 16/12/98 | JL Schwing | 1.6 : Implement "-e add" and "-e delete".
  39. ---------+--------------+------------------------------------------------------
  40. 23/12/98 | JL Schwing | 1.7 : bug fix - crash in msgIdDel().
  41. ---------+--------------+------------------------------------------------------
  42. 28/12/98 | JL Schwing | 1.8 : Add tag asyncHit.
  43. ---------+--------------+------------------------------------------------------
  44. 13/01/99 | JL Schwing | 1.9 : Implement "-e string".
  45. ---------+--------------+------------------------------------------------------
  46. 18/01/99 | JL Schwing | 1.10: Implement "-e randombase".
  47. ---------+--------------+------------------------------------------------------
  48. 21/01/99 | JL Schwing | 1.11: Implement "-e ascii".
  49. ---------+--------------+------------------------------------------------------
  50. 26/02/99 | JL Schwing | 1.12: Improve strict ascii: reject more characters.
  51. ---------+--------------+------------------------------------------------------
  52. 26/02/99 | JL Schwing | 1.13: Quote (aka \) characters rather than reject.
  53. ---------+--------------+------------------------------------------------------
  54. 04/05/99 | JL Schwing | 1.14: Modify msgId*() to memorize attribs as well.
  55. ---------+--------------+------------------------------------------------------
  56. 19/05/99 | JL Schwing | 1.15: Implement "-e rename".
  57. | Exit the thread if status==DEAD
  58. ---------+--------------+------------------------------------------------------
  59. 28/05/99 | JL Schwing | 1.16: Add new option -W (wait).
  60. ---------+--------------+------------------------------------------------------
  61. 06/03/00 | JL Schwing | 1.17: Test malloc() return value.
  62. ---------+--------------+------------------------------------------------------
  63. 18/08/00 | JL Schwing | 1.18: Print begin and end dates.
  64. ---------+--------------+------------------------------------------------------
  65. 25/08/00 | JL Schwing | 1.19: Implement consistent exit status...
  66. | Fix some old legacy code.
  67. ---------+--------------+------------------------------------------------------
  68. 14/11/00 | JL Schwing | 1.20: Will now use utils.c functions.
  69. ---------+--------------+------------------------------------------------------
  70. 17/11/00 | JL Schwing | 1.21: Implement "-e smoothshutdown".
  71. | Add new functions setThreadStatus() getThreadStatus().
  72. ---------+--------------+------------------------------------------------------
  73. 21/11/00 | JL Schwing | 1.22: Implement "-e attreplace=name:mask"
  74. ---------+--------------+------------------------------------------------------
  75. 29/11/00 | JL Schwing | 1.23: Port on NT 4.
  76. ---------+--------------+------------------------------------------------------
  77. 01/12/00 | JL Schwing | 1.24: Port on Linux.
  78. ---------+--------------+------------------------------------------------------
  79. 15/12/00 | JL Schwing | 1.25: Add more trace in VERY_VERBOSE mode.
  80. ---------+--------------+------------------------------------------------------
  81. 18/12/00 | JL Schwing | 1.26: Add new exit status EXIT_INIT.
  82. ---------+--------------+------------------------------------------------------
  83. 05/01/01 | JL Schwing | 1.27: Implement "-e randombinddn" and associated
  84. | "-e randombinddnlow/high"
  85. ---------+--------------+------------------------------------------------------
  86. 08/01/01 | JL Schwing | 1.28: Implement "-e scalab01".
  87. ---------+--------------+------------------------------------------------------
  88. 12/01/01 | JL Schwing | 1.29: Include scalab01.h
  89. ---------+--------------+------------------------------------------------------
  90. 05/03/01 | JL Schwing | 1.30: Bug fix - crash SIGSEGV if no binDN provided.
  91. ---------+--------------+------------------------------------------------------
  92. 14/03/01 | JL Schwing | 1.31: Implement "-e commoncounter"
  93. | Add new function incrementCommonCounter().
  94. ---------+--------------+------------------------------------------------------
  95. 14/03/01 | JL Schwing | 1.32: Implement "-e dontsleeponserverdown".
  96. ---------+--------------+------------------------------------------------------
  97. 15/03/01 | JL Schwing | 1.33: Implement "-e randomattrlist=name:name:name"
  98. | Add new function selectRandomAttrList().
  99. ---------+--------------+------------------------------------------------------
  100. 19/03/01 | JL Schwing | 1.34: Implement "-e genldif=filename"
  101. ---------+--------------+------------------------------------------------------
  102. 23/03/01 | JL Schwing | 1.35: Implements "-e rdn=value".
  103. ---------+--------------+------------------------------------------------------
  104. 28/03/01 | JL Schwing | 1.36: Support -e commoncounter with -e rdn/object
  105. | Add new function incrementCommonCounterObject().
  106. ---------+--------------+------------------------------------------------------
  107. 02/04/01 | JL Schwing | 1.37: Bug fix : large files support for -e genldif.
  108. ---------+--------------+------------------------------------------------------
  109. 11/04/01 | JL Schwing | 1.38: Implement [INCRFROMFILE<NOLOOP>(myfile)]
  110. ---------+--------------+------------------------------------------------------
  111. 03/05/01 | JL Schwing | 1.39: Implement -e randombinddnfromfile=filename.
  112. ---------+--------------+------------------------------------------------------
  113. 04/05/01 | JL Schwing | 1.40: Implement -e bindonly.
  114. ---------+--------------+------------------------------------------------------
  115. */
  116. #include <stdio.h> /* printf(), etc... */
  117. #include <string.h> /* strerror(), etc... */
  118. #include <stdlib.h> /* exit(), etc... */
  119. #include <ctype.h> /* isascii(), etc... */
  120. #include <errno.h> /* errno, etc... */ /*JLS 06-03-00*/
  121. #include <lber.h> /* ldap C-API BER declarations */
  122. #include <ldap.h> /* ldap C-API declarations */
  123. #include <unistd.h> /* close(), etc... */
  124. #include <pthread.h> /* pthreads(), etc... */
  125. #include <signal.h> /* sigfillset(), etc... */
  126. #include "port.h" /* Portability definitions */ /*JLS 29-11-00*/
  127. #include "ldclt.h" /* This tool's include file */
  128. #include "utils.h" /* Utilities functions */ /*JLS 14-11-00*/
  129. #include "scalab01.h" /* Scalab01 specific */ /*JLS 12-01-01*/
  130. /* ****************************************************************************
  131. FUNCTION : selectRandomAttrList
  132. PURPOSE : Select a random attr list.
  133. INPUT : tttctx = this thread context
  134. OUTPUT : None.
  135. RETURN : The random list.
  136. DESCRIPTION :
  137. *****************************************************************************/
  138. char **
  139. selectRandomAttrList (
  140. thread_context *tttctx)
  141. {
  142. tttctx->attrlist[0] = mctx.attrlist[rndlim(0,mctx.attrlistNb-1)];
  143. return (tttctx->attrlist);
  144. }
  145. /* ****************************************************************************
  146. FUNCTION : randomString
  147. PURPOSE : Return a random string, of length nbDigits.
  148. The string is returned in tttctx->buf2.
  149. INPUT : tttctx = thread context.
  150. nbDigits = number of digits required.
  151. OUTPUT : None.
  152. RETURN : -1 if error, 0 else.
  153. DESCRIPTION :
  154. *****************************************************************************/
  155. int
  156. randomString (
  157. thread_context *tttctx,
  158. int nbDigits)
  159. {
  160. rndstr (tttctx->buf2, nbDigits); /*JLS 14-11-00*/
  161. return (0);
  162. }
  163. /* ****************************************************************************
  164. FUNCTION : incrementCommonCounterObject
  165. PURPOSE : Purpose of the fct
  166. INPUT : tttctx = thread context
  167. field = field to process
  168. OUTPUT : None.
  169. RETURN : -1 if error or end of loop (no_loop), new value else.
  170. DESCRIPTION :
  171. *****************************************************************************/
  172. int
  173. incrementCommonCounterObject (
  174. thread_context *tttctx,
  175. vers_field *field)
  176. {
  177. int ret; /* Return value */
  178. int val; /* New value */
  179. /*
  180. * Get mutex
  181. */
  182. if ((ret = ldclt_mutex_lock (&(field->cnt_mutex))) != 0)
  183. {
  184. fprintf (stderr, "ldclt[%d]: %s: cannot mutex_lock(field->cnt_mutex), error=%d (%s)\n",
  185. mctx.pid, tttctx->thrdId, ret, strerror (ret));
  186. fflush (stderr);
  187. return (-1);
  188. }
  189. /*
  190. * Compute next value
  191. */
  192. switch (field->how)
  193. {
  194. case HOW_INCR_FROM_FILE:
  195. case HOW_INCR_NB:
  196. if (field->cnt <= field->high) /* Limit not reached */
  197. {
  198. val = field->cnt;
  199. field->cnt++;
  200. }
  201. else
  202. {
  203. val = field->low;
  204. field->cnt = field->low + 1;
  205. }
  206. break;
  207. case HOW_INCR_FROM_FILE_NL:
  208. case HOW_INCR_NB_NOLOOP:
  209. if (field->cnt <= field->high) /* Limit not reached */
  210. {
  211. val = field->cnt;
  212. field->cnt++;
  213. }
  214. else
  215. val = -1; /* Exit thread */
  216. break;
  217. default:
  218. printf ("ldclt[%d]: %s: Illegal how=%d in incrementCommonCounterObject()\n",
  219. mctx.pid, tttctx->thrdId, field->how);
  220. val = -1;
  221. break;
  222. }
  223. /*
  224. * Free mutex
  225. */
  226. if ((ret = ldclt_mutex_unlock (&(field->cnt_mutex))) != 0)
  227. {
  228. fprintf(stderr,"ldclt[%d]: %s: cannot mutex_unlock(field->cnt_mutex), error=%d (%s)\n",
  229. mctx.pid, tttctx->thrdId, ret, strerror (ret));
  230. fflush (stderr);
  231. return (-1);
  232. }
  233. /*
  234. * Maybe a message to print ?
  235. */
  236. if (val < 0)
  237. printf ("ldclt[%d]: %s: Hit top incrementeal value\n", mctx.pid, tttctx->thrdId);
  238. return (val);
  239. }
  240. /* ****************************************************************************
  241. FUNCTION : incrementCommonCounter
  242. PURPOSE : Purpose of the fct
  243. INPUT : tttctx = thread context
  244. OUTPUT : None.
  245. RETURN : -1 if error or end of loop (no_loop), new value else.
  246. DESCRIPTION :
  247. *****************************************************************************/
  248. int
  249. incrementCommonCounter (
  250. thread_context *tttctx)
  251. {
  252. int ret; /* Return value */
  253. int val; /* New value */
  254. /*
  255. * Get mutex
  256. */
  257. if ((ret = ldclt_mutex_lock (&(mctx.lastVal_mutex))) != 0)
  258. {
  259. fprintf (stderr, "ldclt[%d]: T%03d: cannot mutex_lock(lastVal_mutex), error=%d (%s)\n",
  260. mctx.pid, tttctx->thrdNum, ret, strerror (ret));
  261. fflush (stderr);
  262. return (-1);
  263. }
  264. /*
  265. * Compute next value
  266. */
  267. if ((mctx.mode & NOLOOP) && ((mctx.lastVal + mctx.incr) > mctx.randomHigh))
  268. {
  269. val = -1; /* out of range - cannot continue since not looping */
  270. }
  271. else
  272. {
  273. val = mctx.lastVal = incr_and_wrap(mctx.lastVal, mctx.randomLow, mctx.randomHigh, mctx.incr);
  274. }
  275. /*
  276. * Free mutex
  277. */
  278. if ((ret = ldclt_mutex_unlock (&(mctx.lastVal_mutex))) != 0)
  279. {
  280. fprintf(stderr,"ldclt[%d]: T%03d: cannot mutex_unlock(lastVal_mutex), error=%d (%s)\n",
  281. mctx.pid, tttctx->thrdNum, ret, strerror (ret));
  282. fflush (stderr);
  283. return (-1);
  284. }
  285. /*
  286. * Maybe a message to print ?
  287. */
  288. if (val < 0)
  289. printf ("ldclt[%d]: T%03d: Hit top incremental value\n", mctx.pid, tttctx->thrdNum);
  290. return (val);
  291. }
  292. /* ****************************************************************************
  293. FUNCTION : incrementNbOpers
  294. PURPOSE : Increment the counters tttctx->nbOpers and
  295. tttctx->totOpers of the given thread.
  296. INPUT : tttctx = thread context.
  297. OUTPUT : None.
  298. RETURN : -1 if error, 0 else.
  299. DESCRIPTION :
  300. *****************************************************************************/
  301. int
  302. incrementNbOpers (
  303. thread_context *tttctx)
  304. {
  305. int ret; /* Return value */
  306. /*
  307. * Get mutex
  308. */
  309. if ((ret = ldclt_mutex_lock (&(tttctx->nbOpers_mutex))) != 0)
  310. {
  311. fprintf (stderr, "ldclt[%d]: T%03d: cannot mutex_lock(), error=%d (%s)\n",
  312. mctx.pid, tttctx->thrdNum, ret, strerror (ret));
  313. fflush (stderr);
  314. return (-1);
  315. }
  316. /*
  317. * Increment counter
  318. */
  319. tttctx->nbOpers++;
  320. /*
  321. * Free mutex
  322. */
  323. if ((ret = ldclt_mutex_unlock (&(tttctx->nbOpers_mutex))) != 0)
  324. {
  325. fprintf (stderr, "ldclt[%d]: T%03d: cannot mutex_unlock(), error=%d (%s)\n",
  326. mctx.pid, tttctx->thrdNum, ret, strerror (ret));
  327. fflush (stderr);
  328. return (-1);
  329. }
  330. /*
  331. * Increment total and check if max value reached
  332. */
  333. tttctx->totOpers++;
  334. if(tttctx->totalReq > -1) {
  335. if (tttctx->totOpers >= tttctx->totalReq) {
  336. if (setThreadStatus(tttctx, MUST_SHUTDOWN) < 0) {
  337. tttctx->status = DEAD; /* Force thread to die! */
  338. }
  339. }
  340. }
  341. return (0);
  342. }
  343. /* ****************************************************************************
  344. FUNCTION : ignoreError
  345. PURPOSE : Returns true or false depending on the given error
  346. should be ignored or not (option -I).
  347. We will sleep() if an error about server down is to be
  348. ignored.
  349. INPUT : err = error number
  350. OUTPUT : None.
  351. RETURN : 1 if should be ignored, 0 else.
  352. DESCRIPTION :
  353. *****************************************************************************/
  354. int
  355. ignoreError (
  356. int err)
  357. {
  358. int i;
  359. for (i=0 ; i<mctx.ignErrNb ; i++)
  360. if (mctx.ignErr[i] == err)
  361. { /*JLS 14-03-01*/
  362. if ((!(mctx.mode & DONT_SLEEP_DOWN)) && /*JLS 14-03-01*/
  363. ((err == LDAP_SERVER_DOWN) || /*JLS 14-03-01*/
  364. (err == LDAP_CONNECT_ERROR))) /*JLS 14-03-01*/
  365. ldclt_sleep (1); /*JLS 14-03-01*/
  366. return (1);
  367. } /*JLS 14-03-01*/
  368. return (0);
  369. }
  370. /* ****************************************************************************
  371. FUNCTION : addErrorStat
  372. PURPOSE : Add the given error number to the statistics.
  373. INPUT : err = error number
  374. OUTPUT : None.
  375. RETURN : -1 if error, 0 else.
  376. DESCRIPTION :
  377. *****************************************************************************/
  378. int
  379. addErrorStat (
  380. int err)
  381. {
  382. int ret; /* Return value */
  383. /*
  384. * Get mutex
  385. */
  386. if ((ret = ldclt_mutex_lock (&(mctx.errors_mutex))) != 0)
  387. {
  388. fprintf (stderr,
  389. "ldclt[%d]: Cannot mutex_lock(errors_mutex), error=%d (%s)\n",
  390. mctx.pid, ret, strerror (ret));
  391. fflush (stderr);
  392. return (-1);
  393. }
  394. /*
  395. * Update the counters
  396. */
  397. #if defined(USE_OPENLDAP)
  398. if ((err <= NEGATIVE_MAX_ERROR_NB) || (err >= MAX_ERROR_NB))
  399. #else
  400. if ((err <= 0) || (err >= MAX_ERROR_NB))
  401. #endif
  402. {
  403. fprintf (stderr, "ldclt[%d]: Illegal error number %d\n", mctx.pid, err);
  404. fflush (stderr);
  405. mctx.errorsBad++;
  406. }
  407. #if defined(USE_OPENLDAP)
  408. else if (err < 0)
  409. {
  410. mctx.negativeErrors[abs(err)]++;
  411. }
  412. #endif
  413. else
  414. {
  415. mctx.errors[err]++;
  416. }
  417. /*
  418. * Release the mutex
  419. */
  420. if ((ret = ldclt_mutex_unlock (&(mctx.errors_mutex))) != 0)
  421. {
  422. fprintf (stderr,
  423. "ldclt[%d]: Cannot mutex_unlock(errors_mutex), error=%d (%s)\n",
  424. mctx.pid, ret, strerror (ret));
  425. fflush (stderr);
  426. return (-1);
  427. }
  428. /*
  429. * Maybe we should ignore this error ?
  430. */
  431. if (!(ignoreError (err)))
  432. {
  433. /*
  434. * Ok, we should not ignore this error...
  435. * Maybe the limit is reached ?
  436. */
  437. #if defined(USE_OPENLDAP)
  438. if ((err <= NEGATIVE_MAX_ERROR_NB) || (err >= MAX_ERROR_NB))
  439. #else
  440. if ((err <= 0) || (err >= MAX_ERROR_NB))
  441. #endif
  442. {
  443. if (mctx.errorsBad > mctx.maxErrors) {
  444. printf ("ldclt[%d]: Max error limit reached - exiting.\n", mctx.pid);
  445. (void) printGlobalStatistics(); /*JLS 25-08-00*/
  446. fflush (stdout);
  447. ldclt_sleep (5);
  448. ldcltExit (EXIT_MAX_ERRORS); /*JLS 25-08-00*/
  449. }
  450. }
  451. #if defined(USE_OPENLDAP)
  452. else if (err < 0)
  453. {
  454. if (mctx.negativeErrors[abs(err)] > mctx.maxErrors) {
  455. printf ("ldclt[%d]: Max error limit reached - exiting.\n", mctx.pid);
  456. (void) printGlobalStatistics(); /*JLS 25-08-00*/
  457. fflush (stdout);
  458. ldclt_sleep (5);
  459. ldcltExit (EXIT_MAX_ERRORS); /*JLS 25-08-00*/
  460. }
  461. }
  462. #endif
  463. else
  464. {
  465. if (mctx.errors[err] > mctx.maxErrors) {
  466. printf ("ldclt[%d]: Max error limit reached - exiting.\n", mctx.pid);
  467. (void) printGlobalStatistics(); /*JLS 25-08-00*/
  468. fflush (stdout);
  469. ldclt_sleep (5);
  470. ldcltExit (EXIT_MAX_ERRORS); /*JLS 25-08-00*/
  471. }
  472. }
  473. }
  474. /*
  475. * Normal end
  476. */
  477. return (0);
  478. }
  479. /* ****************************************************************************
  480. FUNCTION : msgIdAdd
  481. PURPOSE : Add a new message id to the pending ones.
  482. INPUT : tttctx = thread's context.
  483. msgid = message id.
  484. str = free string.
  485. dn = dn of the entry
  486. attribs = attributes
  487. OUTPUT : None.
  488. RETURN : -1 if error, 0 else.
  489. DESCRIPTION :
  490. *****************************************************************************/
  491. int
  492. msgIdAdd (
  493. thread_context *tttctx,
  494. int msgid,
  495. char *str,
  496. char *dn,
  497. LDAPMod **attribs)
  498. {
  499. if (mctx.mode & VERY_VERBOSE)
  500. printf ("ldclt[%d]: T%03d: msgIdAdd (%d, %s)\n", mctx.pid, tttctx->thrdNum, msgid, str);
  501. /*
  502. * Add the new cell
  503. */
  504. if (tttctx->firstMsgId == NULL)
  505. {
  506. tttctx->firstMsgId = (msgid_cell *) malloc (sizeof (msgid_cell));
  507. if (tttctx->firstMsgId == NULL) /*JLS 06-03-00*/
  508. { /*JLS 06-03-00*/
  509. printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->firstMsgId), error=%d (%s)\n",
  510. mctx.pid, tttctx->thrdNum, errno, strerror (errno));
  511. return (-1); /*JLS 06-03-00*/
  512. } /*JLS 06-03-00*/
  513. tttctx->lastMsgId = tttctx->firstMsgId;
  514. }
  515. else
  516. {
  517. tttctx->lastMsgId->next = (msgid_cell *) malloc (sizeof (msgid_cell));
  518. if (tttctx->lastMsgId->next == NULL) /*JLS 06-03-00*/
  519. { /*JLS 06-03-00*/
  520. printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->lastMsgId->next), error=%d (%s)\n",
  521. mctx.pid, tttctx->thrdNum, errno, strerror (errno));
  522. return (-1); /*JLS 06-03-00*/
  523. } /*JLS 06-03-00*/
  524. tttctx->lastMsgId = tttctx->lastMsgId->next;
  525. }
  526. /*
  527. * Memorize the information
  528. */
  529. tttctx->lastMsgId->next = NULL;
  530. tttctx->lastMsgId->msgid = msgid;
  531. strncpy (tttctx->lastMsgId->str, str, sizeof(tttctx->lastMsgId->str));
  532. tttctx->lastMsgId->str[sizeof(tttctx->lastMsgId->str)-1] = '\0';
  533. strncpy (tttctx->lastMsgId->dn, dn, sizeof(tttctx->lastMsgId->dn));
  534. tttctx->lastMsgId->dn[sizeof(tttctx->lastMsgId->dn)-1] = '\0';
  535. tttctx->lastMsgId->attribs = attribs;
  536. return (0);
  537. }
  538. /* ****************************************************************************
  539. FUNCTION : msgIdAttribs
  540. PURPOSE : Found the requested message id in the pending list.
  541. INPUT : tttctx = thread's context
  542. msgid = message id
  543. OUTPUT : None
  544. RETURN : The associated attributes, or NULL.
  545. DESCRIPTION :
  546. *****************************************************************************/
  547. LDAPMod **
  548. msgIdAttribs (
  549. thread_context *tttctx,
  550. int msgid)
  551. {
  552. msgid_cell *pt;
  553. if (mctx.mode & VERY_VERBOSE)
  554. printf ("ldclt[%d]: T%03d: msgIdAttribs (%d)\n", mctx.pid, tttctx->thrdNum, msgid);
  555. for (pt = tttctx->firstMsgId ; pt != NULL ; pt = pt->next)
  556. if (pt->msgid == msgid)
  557. return (pt->attribs);
  558. return (NULL);
  559. }
  560. /* ****************************************************************************
  561. FUNCTION : msgIdDN
  562. PURPOSE : Found the requested message id in the pending list.
  563. INPUT : tttctx = thread's context
  564. msgid = message id
  565. OUTPUT : None
  566. RETURN : The associated DN, or NULL.
  567. DESCRIPTION :
  568. *****************************************************************************/
  569. char *
  570. msgIdDN (
  571. thread_context *tttctx,
  572. int msgid)
  573. {
  574. msgid_cell *pt;
  575. if (mctx.mode & VERY_VERBOSE)
  576. printf ("ldclt[%d]: T%03d: msgIdDN (%d)\n", mctx.pid, tttctx->thrdNum, msgid);
  577. for (pt = tttctx->firstMsgId ; pt != NULL ; pt = pt->next)
  578. if (pt->msgid == msgid)
  579. return (pt->dn);
  580. return (NULL);
  581. }
  582. /* ****************************************************************************
  583. FUNCTION : msgIdStr
  584. PURPOSE : Found the requested message id in the pending list.
  585. INPUT : tttctx = thread's context
  586. msgid = message id
  587. OUTPUT : None
  588. RETURN : The associated str, or an error message string.
  589. DESCRIPTION :
  590. *****************************************************************************/
  591. char *
  592. msgIdStr (
  593. thread_context *tttctx,
  594. int msgid)
  595. {
  596. msgid_cell *pt;
  597. if (mctx.mode & VERY_VERBOSE)
  598. printf ("ldclt[%d]: T%03d: msgIdStr (%d)\n", mctx.pid, tttctx->thrdNum, msgid);
  599. for (pt = tttctx->firstMsgId ; pt != NULL ; pt = pt->next)
  600. if (pt->msgid == msgid)
  601. return (pt->str);
  602. return ("Error: msgid not found");
  603. }
  604. /* ****************************************************************************
  605. FUNCTION : msgIdDel
  606. PURPOSE : Delete a message id from the pending ones.
  607. INPUT : tttctx = thread's context
  608. msgid = message id.
  609. freeAttr= true or false depending on freing the attribs
  610. OUTPUT : None.
  611. RETURN : -1 if not found, 0 else.
  612. DESCRIPTION :
  613. *****************************************************************************/
  614. int
  615. msgIdDel (
  616. thread_context *tttctx,
  617. int msgid,
  618. int freeAttr)
  619. {
  620. msgid_cell *pt; /* For the loop */
  621. msgid_cell *ptToFree; /* The cell to free */
  622. if (mctx.mode & VERY_VERBOSE)
  623. printf ("ldclt[%d]: T%03d: msgIdDel (%d)\n", mctx.pid, tttctx->thrdNum, msgid);
  624. /*
  625. * Make sure there is a list !
  626. */
  627. if (tttctx->firstMsgId != NULL)
  628. {
  629. /*
  630. * Maybe it is the first one ?
  631. */
  632. if (tttctx->firstMsgId->msgid == msgid)
  633. {
  634. ptToFree = tttctx->firstMsgId;
  635. tttctx->firstMsgId = tttctx->firstMsgId->next;
  636. if (tttctx->firstMsgId == NULL)
  637. tttctx->lastMsgId = NULL;
  638. free (ptToFree);
  639. return (0);
  640. }
  641. /*
  642. * Let's go through the whole list
  643. */
  644. for (pt = tttctx->firstMsgId ; pt->next != NULL ; pt = pt->next)
  645. if (pt->next->msgid == msgid)
  646. {
  647. /*
  648. * Be carrefull if it is the last element of the list
  649. */
  650. if (pt->next->next == NULL)
  651. tttctx->lastMsgId = pt;
  652. ptToFree = pt->next;
  653. pt->next = ptToFree->next;
  654. if (freeAttr)
  655. if (freeAttrib (ptToFree->attribs) < 0)
  656. return (-1);
  657. /*
  658. * Free the pointer itself
  659. */
  660. free (ptToFree);
  661. return (0);
  662. }
  663. }
  664. /*
  665. * Not found
  666. */
  667. printf ("ldclt[%d]: T%03d: message %d not found.\n", mctx.pid, tttctx->thrdNum, msgid);
  668. fflush (stdout);
  669. return (-1);
  670. }
  671. /* ****************************************************************************
  672. FUNCTION : getThreadStatus
  673. PURPOSE : Get the value of a given thread's status.
  674. INPUT : tttctx = thread context
  675. OUTPUT : status = the thread's status
  676. RETURN : -1 if error, 0 else.
  677. DESCRIPTION :
  678. *****************************************************************************/
  679. int
  680. getThreadStatus (
  681. thread_context *tttctx,
  682. int *status)
  683. {
  684. int ret; /* Return code */
  685. if ((ret = ldclt_mutex_lock (&(tttctx->status_mutex))) != 0)
  686. {
  687. fprintf (stderr,
  688. "ldclt[%d]: Cannot mutex_lock(T%03d), error=%d (%s)\n",
  689. mctx.pid, tttctx->thrdNum, ret, strerror (ret));
  690. fprintf (stderr, "ldclt[%d]: Problem in getThreadStatus()\n", mctx.pid);
  691. fflush (stderr);
  692. return (-1);
  693. }
  694. *status = tttctx->status;
  695. if ((ret = ldclt_mutex_unlock (&(tttctx->status_mutex))) != 0)
  696. {
  697. fprintf (stderr,
  698. "ldclt[%d]: Cannot mutex_unlock(T%03d), error=%d (%s)\n",
  699. mctx.pid, tttctx->thrdNum, ret, strerror (ret));
  700. fprintf (stderr, "ldclt[%d]: Problem in getThreadStatus()\n", mctx.pid);
  701. fflush (stderr);
  702. return (-1);
  703. }
  704. return (0);
  705. }
  706. /* ****************************************************************************
  707. FUNCTION : setThreadStatus
  708. PURPOSE : Set the value of a given thread's status.
  709. INPUT : tttctx = thread context
  710. status = new status
  711. OUTPUT : None.
  712. RETURN : -1 if error, 0 else.
  713. DESCRIPTION :
  714. *****************************************************************************/
  715. int
  716. setThreadStatus (
  717. thread_context *tttctx,
  718. int status)
  719. {
  720. int ret; /* Return code */
  721. if ((ret = ldclt_mutex_lock (&(tttctx->status_mutex))) != 0)
  722. {
  723. fprintf (stderr,
  724. "ldclt[%d]: Cannot mutex_lock(T%03d), error=%d (%s)\n",
  725. mctx.pid, tttctx->thrdNum, ret, strerror (ret));
  726. fprintf (stderr, "ldclt[%d]: Problem in setThreadStatus()\n", mctx.pid);
  727. fflush (stderr);
  728. return (-1);
  729. }
  730. tttctx->status = status;
  731. if ((ret = ldclt_mutex_unlock (&(tttctx->status_mutex))) != 0)
  732. {
  733. fprintf (stderr,
  734. "ldclt[%d]: Cannot mutex_unlock(T%03d), error=%d (%s)\n",
  735. mctx.pid, tttctx->thrdNum, ret, strerror (ret));
  736. fprintf (stderr, "ldclt[%d]: Problem in setThreadStatus()\n", mctx.pid);
  737. fflush (stderr);
  738. return (-1);
  739. }
  740. return (0);
  741. }
  742. /* ****************************************************************************
  743. FUNCTION : threadMain
  744. PURPOSE : This function is the main function of the client threads
  745. part of this tool.
  746. INPUT : arg = this thread's thread_context
  747. OUTPUT : None.
  748. RETURN : None.
  749. DESCRIPTION :
  750. *****************************************************************************/
  751. void *
  752. threadMain (
  753. void *arg)
  754. {
  755. thread_context *tttctx; /* This thread's context */
  756. int go = 1; /* Thread must continue */
  757. int status; /* Thread's status */ /*JLS 17-11-00*/
  758. /*
  759. * Initialization
  760. */
  761. tttctx = (thread_context *) arg;
  762. if (setThreadStatus (tttctx, CREATED) < 0) /*JLS 17-11-00*/
  763. { /*JLS 17-11-00*/
  764. tttctx->status = DEAD; /*JLS 17-11-00*/
  765. return NULL; /*JLS 17-11-00*/
  766. } /*JLS 17-11-00*/
  767. tttctx->asyncHit = 0;
  768. tttctx->binded = 0;
  769. tttctx->fd = -1;
  770. tttctx->lastVal = mctx.randomLow-1;
  771. tttctx->ldapCtx = NULL;
  772. tttctx->matcheddnp = NULL; /*JLS 15-12-00*/
  773. tttctx->nbOpers = 0;
  774. tttctx->totOpers = 0;
  775. tttctx->pendingNb = 0;
  776. tttctx->firstMsgId = NULL;
  777. tttctx->lastMsgId = NULL;
  778. /*
  779. * Don't forget the buffers !!
  780. * This should save time while redoing random values
  781. */
  782. if ((mctx.mode & NEED_FILTER) || (mctx.mod2 & (M2_GENLDIF|M2_NEED_FILTER))) /*JLS 19-03-01*/
  783. {
  784. if (mctx.mod2 & M2_RDN_VALUE) /*JLS 23-03-01*/
  785. tttctx->bufFilter = (char *) malloc (MAX_FILTER); /*JLS 23-03-01*/
  786. else /*JLS 23-03-01*/
  787. { /*JLS 23-03-01*/
  788. /*
  789. * Variable filter ?
  790. */
  791. tttctx->bufFilter = (char *) malloc (strlen (mctx.filter) + 1);
  792. if (tttctx->bufFilter == NULL) /*JLS 06-03-00*/
  793. { /*JLS 06-03-00*/
  794. printf ("ldclt[%d]: %s: cannot malloc(tttctx->bufFilter), error=%d (%s)\n",
  795. mctx.pid, tttctx->thrdId, errno, strerror (errno));
  796. ldcltExit (EXIT_INIT); /*JLS 18-12-00*/
  797. } /*JLS 06-03-00*/
  798. if (!(mctx.mode & (RANDOM | INCREMENTAL)))
  799. strcpy (tttctx->bufFilter, mctx.filter);
  800. else
  801. {
  802. tttctx->startRandom = strlen (mctx.randomHead);
  803. strcpy (tttctx->bufFilter, mctx.randomHead);
  804. strcpy (&(tttctx->bufFilter[tttctx->startRandom+mctx.randomNbDigit]),
  805. mctx.randomTail);
  806. if (mctx.mode & VERY_VERBOSE)
  807. {
  808. printf ("ldclt[%d]: %s: startRandom = %d\n",
  809. mctx.pid, tttctx->thrdId, tttctx->startRandom);
  810. printf ("ldclt[%d]: %s: randomHead = \"%s\", randomTail = \"%s\"\n",
  811. mctx.pid, tttctx->thrdId, mctx.randomHead, mctx.randomTail);
  812. }
  813. }
  814. } /*JLS 23-03-01*/
  815. } /*JLS 05-03-01*/
  816. /*
  817. * Variable base DN ?
  818. */
  819. tttctx->bufBaseDN = (char *) malloc (strlen (mctx.baseDN) + 1);
  820. if (tttctx->bufBaseDN == NULL) /*JLS 06-03-00*/
  821. { /*JLS 06-03-00*/
  822. printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufBaseDN), error=%d (%s)\n",
  823. mctx.pid, tttctx->thrdNum, errno, strerror (errno));
  824. ldcltExit (EXIT_INIT); /*JLS 18-12-00*/
  825. } /*JLS 06-03-00*/
  826. if (!(mctx.mode & RANDOM_BASE))
  827. strcpy (tttctx->bufBaseDN, mctx.baseDN);
  828. else
  829. {
  830. tttctx->startBaseDN = strlen (mctx.baseDNHead);
  831. strcpy (tttctx->bufBaseDN, mctx.baseDNHead);
  832. strcpy (&(tttctx->bufBaseDN[tttctx->startBaseDN+mctx.baseDNNbDigit]),
  833. mctx.baseDNTail);
  834. }
  835. /*
  836. * Variable bind DN ?
  837. * Do not forget the random bind password below that is activated
  838. * at the same time as the random bind DN.
  839. */
  840. if (mctx.bindDN != NULL) /*JLS 05-03-01*/
  841. { /*JLS 05-03-01*/
  842. tttctx->bufBindDN = (char *) malloc (strlen (mctx.bindDN) + 1);
  843. if (tttctx->bufBindDN == NULL)
  844. {
  845. printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufBindDN), error=%d (%s)\n",
  846. mctx.pid, tttctx->thrdNum, errno, strerror (errno));
  847. ldcltExit (EXIT_INIT);
  848. }
  849. if (!(mctx.mode & RANDOM_BINDDN))
  850. strcpy (tttctx->bufBindDN, mctx.bindDN);
  851. else
  852. {
  853. tttctx->startBindDN = strlen (mctx.bindDNHead);
  854. strcpy (tttctx->bufBindDN, mctx.bindDNHead);
  855. strcpy (&(tttctx->bufBindDN[tttctx->startBindDN+mctx.bindDNNbDigit]),
  856. mctx.bindDNTail);
  857. }
  858. } /*JLS 05-03-01*/
  859. /*
  860. * Variable bind password ?
  861. * Remember that the random bind password feature is activated
  862. * by the same option as the random bind DN, but has here its own
  863. * code section for the ease of coding.
  864. */
  865. if (mctx.passwd != NULL) /*JLS 05-03-01*/
  866. { /*JLS 05-03-01*/
  867. tttctx->bufPasswd = (char *) malloc (strlen (mctx.passwd) + 1);
  868. if (tttctx->bufPasswd == NULL)
  869. {
  870. printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufPasswd), error=%d (%s)\n",
  871. mctx.pid, tttctx->thrdNum, errno, strerror (errno));
  872. ldcltExit (EXIT_INIT);
  873. }
  874. if (!(mctx.mode & RANDOM_BINDDN))
  875. strcpy (tttctx->bufPasswd, mctx.passwd);
  876. else
  877. {
  878. tttctx->startPasswd = strlen (mctx.passwdHead);
  879. strcpy (tttctx->bufPasswd, mctx.passwdHead);
  880. strcpy (&(tttctx->bufPasswd[tttctx->startPasswd+mctx.passwdNbDigit]),
  881. mctx.passwdTail);
  882. }
  883. }
  884. /*
  885. * Bind DN from a file ?
  886. * The trick (mctx.passwd = "foo bar"; ) is needed to
  887. * simplify the code, because in many places we check
  888. * if mctx.passwd exist before sending password.
  889. */
  890. if (mctx.mod2 & M2_RNDBINDFILE) /*JLS 03-05-01*/
  891. { /*JLS 03-05-01*/
  892. tttctx->bufBindDN = (char *) malloc (MAX_DN_LENGTH); /*JLS 03-05-01*/
  893. tttctx->bufPasswd = (char *) malloc (MAX_DN_LENGTH); /*JLS 03-05-01*/
  894. mctx.passwd = "foo bar"; /* trick... */ /*JLS 03-05-01*/
  895. } /*JLS 03-05-01*/
  896. /*
  897. * Variable Authid ?
  898. */
  899. if (mctx.sasl_authid != NULL)
  900. {
  901. tttctx->bufSaslAuthid = (char *) malloc (strlen (mctx.sasl_authid) + 1);
  902. if (tttctx->bufSaslAuthid == NULL)
  903. {
  904. printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufSaslAuthid), error=%d (%s)\n",
  905. mctx.pid, tttctx->thrdNum, errno, strerror (errno));
  906. ldcltExit (EXIT_INIT);
  907. }
  908. if (!(mctx.mod2 & M2_RANDOM_SASLAUTHID))
  909. strcpy (tttctx->bufSaslAuthid, mctx.sasl_authid);
  910. else
  911. {
  912. tttctx->startSaslAuthid = strlen (mctx.sasl_authid_head);
  913. strcpy (tttctx->bufSaslAuthid, mctx.sasl_authid_head);
  914. strcpy (&(tttctx->bufSaslAuthid[tttctx->startSaslAuthid+mctx.sasl_authid_nbdigit]),
  915. mctx.sasl_authid_tail);
  916. }
  917. }
  918. /*
  919. * Initiates the attribute replace buffers
  920. */
  921. if (mctx.mode & ATTR_REPLACE) /* New */ /*JLS 21-11-00*/
  922. {
  923. tttctx->bufAttrpl = (char *) malloc (strlen (mctx.attrpl) + 1);
  924. if (tttctx->bufAttrpl == NULL)
  925. {
  926. printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufAttrpl), error=%d (%s)\n",
  927. mctx.pid, tttctx->thrdNum, errno, strerror (errno));
  928. ldcltExit (EXIT_INIT); /*JLS 18-12-00*/
  929. }
  930. tttctx->startAttrpl = strlen (mctx.attrplHead);
  931. strcpy (tttctx->bufAttrpl, mctx.attrplHead);
  932. strcpy (&(tttctx->bufAttrpl[tttctx->startAttrpl+mctx.attrplNbDigit]),
  933. mctx.attrplTail);
  934. }
  935. /*
  936. * Initiates the attribute replace buffers attrplName
  937. */
  938. if ( mctx.mod2 & M2_ATTR_REPLACE_FILE )
  939. {
  940. /* bufAttrpl should point to the same memory location that mctx.attrplFileContent points to */
  941. tttctx->bufAttrpl = mctx.attrplFileContent;
  942. if (tttctx->bufAttrpl == NULL)
  943. {
  944. printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufAttrpl), error=%d (%s), can we read file [%s]\n", mctx.pid, tttctx->thrdNum, errno, strerror (errno), mctx.attrplFile);
  945. ldcltExit (EXIT_INIT);
  946. }
  947. }
  948. /*
  949. * We are ready to go !
  950. */
  951. status = RUNNING; /*JLS 17-11-00*/
  952. if (setThreadStatus (tttctx, RUNNING) < 0) /*JLS 17-11-00*/
  953. status = DEAD; /*JLS 17-11-00*/
  954. /*
  955. * Let's go !
  956. */
  957. while (go && (status != DEAD) && (status != MUST_SHUTDOWN)) /*JLS 17-11-00*/
  958. {
  959. if (mctx.waitSec > 0)
  960. { /*JLS 17-11-00*/
  961. ldclt_sleep (mctx.waitSec);
  962. /*
  963. * Maybe we should shutdown ?
  964. */
  965. if (getThreadStatus (tttctx, &status) < 0) /*JLS 17-11-00*/
  966. break; /*JLS 17-11-00*/
  967. if (status == MUST_SHUTDOWN) /*JLS 17-11-00*/
  968. break; /*JLS 17-11-00*/
  969. } /*JLS 17-11-00*/
  970. /*
  971. * Do a LDAP request
  972. */
  973. if (tttctx->mode & ADD_ENTRIES)
  974. if (doAddEntry (tttctx) < 0)
  975. {
  976. go = 0;
  977. continue;
  978. }
  979. if (tttctx->mode & ATTR_REPLACE) /*JLS 21-11-00*/
  980. if (doAttrReplace (tttctx) < 0) /*JLS 21-11-00*/
  981. { /*JLS 21-11-00*/
  982. go = 0; /*JLS 21-11-00*/
  983. continue; /*JLS 21-11-00*/
  984. } /*JLS 21-11-00*/
  985. if (mctx.mod2 & M2_ATTR_REPLACE_FILE )
  986. if (doAttrFileReplace (tttctx) < 0)
  987. {
  988. go = 0;
  989. continue;
  990. }
  991. if (tttctx->mode & DELETE_ENTRIES)
  992. if (doDeleteEntry (tttctx) < 0)
  993. {
  994. go = 0;
  995. continue;
  996. }
  997. if (mctx.mod2 & M2_BINDONLY) /*JLS 04-05-01*/
  998. if (doBindOnly (tttctx) < 0) /*JLS 04-05-01*/
  999. { /*JLS 04-05-01*/
  1000. go = 0; /*JLS 04-05-01*/
  1001. continue; /*JLS 04-05-01*/
  1002. } /*JLS 04-05-01*/
  1003. if (tttctx->mode & EXACT_SEARCH)
  1004. if (doExactSearch (tttctx) < 0)
  1005. {
  1006. go = 0;
  1007. continue;
  1008. }
  1009. if (tttctx->mode & RENAME_ENTRIES)
  1010. if (doRename (tttctx) < 0)
  1011. {
  1012. go = 0;
  1013. continue;
  1014. }
  1015. /*
  1016. * Maybe a specific scenario ?
  1017. */
  1018. if (tttctx->mode & SCALAB01) /*JLS 08-01-01*/
  1019. if (doScalab01 (tttctx) < 0) /*JLS 08-01-01*/
  1020. { /*JLS 08-01-01*/
  1021. go = 0; /*JLS 08-01-01*/
  1022. continue; /*JLS 08-01-01*/
  1023. } /*JLS 08-01-01*/
  1024. /*
  1025. * Maybe genldif mode ?
  1026. */
  1027. if (mctx.mod2 & M2_GENLDIF) /*JLS 19-03-01*/
  1028. if (doGenldif (tttctx) < 0) /*JLS 19-03-01*/
  1029. { /*JLS 19-03-01*/
  1030. ldclt_flush_genldif(); /*JLS 02-04-01*/
  1031. go = 0; /*JLS 19-03-01*/
  1032. continue; /*JLS 19-03-01*/
  1033. } /*JLS 19-03-01*/
  1034. if (mctx.mod2 & M2_ABANDON)
  1035. {
  1036. if (doAbandon (tttctx) < 0)
  1037. {
  1038. go = 0;
  1039. continue;
  1040. }
  1041. }
  1042. /*
  1043. * Check the thread's status
  1044. */
  1045. if (getThreadStatus (tttctx, &status) < 0) /*JLS 17-11-00*/
  1046. break; /*JLS 17-11-00*/
  1047. }
  1048. /*
  1049. * End of thread
  1050. */
  1051. /* [156984] once setting "DEAD", nothing should be done in the context */
  1052. /* moved the dead message above setThreadStatus(DEAD) */
  1053. printf ("ldclt[%d]: T%03d: thread is dead.\n", mctx.pid, tttctx->thrdNum);
  1054. fflush (stdout);
  1055. if (setThreadStatus (tttctx, DEAD) < 0) /*JLS 17-11-00*/
  1056. { /*JLS 17-11-00*/
  1057. ldclt_sleep (1); /*JLS 17-11-00*/
  1058. tttctx->status = DEAD; /* Force it !!! */ /*JLS 17-11-00*/
  1059. } /*JLS 17-11-00*/
  1060. return (arg);
  1061. }