threadMain.c 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147
  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. } else {
  451. if (mctx.errors[err] + mctx.negativeErrors[abs(err)] > mctx.maxErrors) {
  452. printf ("ldclt[%d]: Max error limit reached - exiting.\n", mctx.pid);
  453. (void) printGlobalStatistics(); /*JLS 25-08-00*/
  454. fflush (stdout);
  455. ldclt_sleep (5);
  456. ldcltExit (EXIT_MAX_ERRORS); /*JLS 25-08-00*/
  457. }
  458. }
  459. }
  460. /*
  461. * Normal end
  462. */
  463. return (0);
  464. }
  465. /* ****************************************************************************
  466. FUNCTION : msgIdAdd
  467. PURPOSE : Add a new message id to the pending ones.
  468. INPUT : tttctx = thread's context.
  469. msgid = message id.
  470. str = free string.
  471. dn = dn of the entry
  472. attribs = attributes
  473. OUTPUT : None.
  474. RETURN : -1 if error, 0 else.
  475. DESCRIPTION :
  476. *****************************************************************************/
  477. int
  478. msgIdAdd (
  479. thread_context *tttctx,
  480. int msgid,
  481. char *str,
  482. char *dn,
  483. LDAPMod **attribs)
  484. {
  485. if (mctx.mode & VERY_VERBOSE)
  486. printf ("ldclt[%d]: T%03d: msgIdAdd (%d, %s)\n", mctx.pid, tttctx->thrdNum, msgid, str);
  487. /*
  488. * Add the new cell
  489. */
  490. if (tttctx->firstMsgId == NULL)
  491. {
  492. tttctx->firstMsgId = (msgid_cell *) malloc (sizeof (msgid_cell));
  493. if (tttctx->firstMsgId == NULL) /*JLS 06-03-00*/
  494. { /*JLS 06-03-00*/
  495. printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->firstMsgId), error=%d (%s)\n",
  496. mctx.pid, tttctx->thrdNum, errno, strerror (errno));
  497. return (-1); /*JLS 06-03-00*/
  498. } /*JLS 06-03-00*/
  499. tttctx->lastMsgId = tttctx->firstMsgId;
  500. }
  501. else
  502. {
  503. tttctx->lastMsgId->next = (msgid_cell *) malloc (sizeof (msgid_cell));
  504. if (tttctx->lastMsgId->next == NULL) /*JLS 06-03-00*/
  505. { /*JLS 06-03-00*/
  506. printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->lastMsgId->next), error=%d (%s)\n",
  507. mctx.pid, tttctx->thrdNum, errno, strerror (errno));
  508. return (-1); /*JLS 06-03-00*/
  509. } /*JLS 06-03-00*/
  510. tttctx->lastMsgId = tttctx->lastMsgId->next;
  511. }
  512. /*
  513. * Memorize the information
  514. */
  515. tttctx->lastMsgId->next = NULL;
  516. tttctx->lastMsgId->msgid = msgid;
  517. strncpy (tttctx->lastMsgId->str, str, sizeof(tttctx->lastMsgId->str));
  518. tttctx->lastMsgId->str[sizeof(tttctx->lastMsgId->str)-1] = '\0';
  519. strncpy (tttctx->lastMsgId->dn, dn, sizeof(tttctx->lastMsgId->dn));
  520. tttctx->lastMsgId->dn[sizeof(tttctx->lastMsgId->dn)-1] = '\0';
  521. tttctx->lastMsgId->attribs = attribs;
  522. return (0);
  523. }
  524. /* ****************************************************************************
  525. FUNCTION : msgIdAttribs
  526. PURPOSE : Found the requested message id in the pending list.
  527. INPUT : tttctx = thread's context
  528. msgid = message id
  529. OUTPUT : None
  530. RETURN : The associated attributes, or NULL.
  531. DESCRIPTION :
  532. *****************************************************************************/
  533. LDAPMod **
  534. msgIdAttribs (
  535. thread_context *tttctx,
  536. int msgid)
  537. {
  538. msgid_cell *pt;
  539. if (mctx.mode & VERY_VERBOSE)
  540. printf ("ldclt[%d]: T%03d: msgIdAttribs (%d)\n", mctx.pid, tttctx->thrdNum, msgid);
  541. for (pt = tttctx->firstMsgId ; pt != NULL ; pt = pt->next)
  542. if (pt->msgid == msgid)
  543. return (pt->attribs);
  544. return (NULL);
  545. }
  546. /* ****************************************************************************
  547. FUNCTION : msgIdDN
  548. PURPOSE : Found the requested message id in the pending list.
  549. INPUT : tttctx = thread's context
  550. msgid = message id
  551. OUTPUT : None
  552. RETURN : The associated DN, or NULL.
  553. DESCRIPTION :
  554. *****************************************************************************/
  555. char *
  556. msgIdDN (
  557. thread_context *tttctx,
  558. int msgid)
  559. {
  560. msgid_cell *pt;
  561. if (mctx.mode & VERY_VERBOSE)
  562. printf ("ldclt[%d]: T%03d: msgIdDN (%d)\n", mctx.pid, tttctx->thrdNum, msgid);
  563. for (pt = tttctx->firstMsgId ; pt != NULL ; pt = pt->next)
  564. if (pt->msgid == msgid)
  565. return (pt->dn);
  566. return (NULL);
  567. }
  568. /* ****************************************************************************
  569. FUNCTION : msgIdStr
  570. PURPOSE : Found the requested message id in the pending list.
  571. INPUT : tttctx = thread's context
  572. msgid = message id
  573. OUTPUT : None
  574. RETURN : The associated str, or an error message string.
  575. DESCRIPTION :
  576. *****************************************************************************/
  577. char *
  578. msgIdStr (
  579. thread_context *tttctx,
  580. int msgid)
  581. {
  582. msgid_cell *pt;
  583. if (mctx.mode & VERY_VERBOSE)
  584. printf ("ldclt[%d]: T%03d: msgIdStr (%d)\n", mctx.pid, tttctx->thrdNum, msgid);
  585. for (pt = tttctx->firstMsgId ; pt != NULL ; pt = pt->next)
  586. if (pt->msgid == msgid)
  587. return (pt->str);
  588. return ("Error: msgid not found");
  589. }
  590. /* ****************************************************************************
  591. FUNCTION : msgIdDel
  592. PURPOSE : Delete a message id from the pending ones.
  593. INPUT : tttctx = thread's context
  594. msgid = message id.
  595. freeAttr= true or false depending on freing the attribs
  596. OUTPUT : None.
  597. RETURN : -1 if not found, 0 else.
  598. DESCRIPTION :
  599. *****************************************************************************/
  600. int
  601. msgIdDel (
  602. thread_context *tttctx,
  603. int msgid,
  604. int freeAttr)
  605. {
  606. msgid_cell *pt; /* For the loop */
  607. msgid_cell *ptToFree; /* The cell to free */
  608. if (mctx.mode & VERY_VERBOSE)
  609. printf ("ldclt[%d]: T%03d: msgIdDel (%d)\n", mctx.pid, tttctx->thrdNum, msgid);
  610. /*
  611. * Make sure there is a list !
  612. */
  613. if (tttctx->firstMsgId != NULL)
  614. {
  615. /*
  616. * Maybe it is the first one ?
  617. */
  618. if (tttctx->firstMsgId->msgid == msgid)
  619. {
  620. ptToFree = tttctx->firstMsgId;
  621. tttctx->firstMsgId = tttctx->firstMsgId->next;
  622. if (tttctx->firstMsgId == NULL)
  623. tttctx->lastMsgId = NULL;
  624. free (ptToFree);
  625. return (0);
  626. }
  627. /*
  628. * Let's go through the whole list
  629. */
  630. for (pt = tttctx->firstMsgId ; pt->next != NULL ; pt = pt->next)
  631. if (pt->next->msgid == msgid)
  632. {
  633. /*
  634. * Be carrefull if it is the last element of the list
  635. */
  636. if (pt->next->next == NULL)
  637. tttctx->lastMsgId = pt;
  638. ptToFree = pt->next;
  639. pt->next = ptToFree->next;
  640. if (freeAttr)
  641. if (freeAttrib (ptToFree->attribs) < 0)
  642. return (-1);
  643. /*
  644. * Free the pointer itself
  645. */
  646. free (ptToFree);
  647. return (0);
  648. }
  649. }
  650. /*
  651. * Not found
  652. */
  653. printf ("ldclt[%d]: T%03d: message %d not found.\n", mctx.pid, tttctx->thrdNum, msgid);
  654. fflush (stdout);
  655. return (-1);
  656. }
  657. /* ****************************************************************************
  658. FUNCTION : getThreadStatus
  659. PURPOSE : Get the value of a given thread's status.
  660. INPUT : tttctx = thread context
  661. OUTPUT : status = the thread's status
  662. RETURN : -1 if error, 0 else.
  663. DESCRIPTION :
  664. *****************************************************************************/
  665. int
  666. getThreadStatus (
  667. thread_context *tttctx,
  668. int *status)
  669. {
  670. int ret; /* Return code */
  671. if ((ret = ldclt_mutex_lock (&(tttctx->status_mutex))) != 0)
  672. {
  673. fprintf (stderr,
  674. "ldclt[%d]: Cannot mutex_lock(T%03d), error=%d (%s)\n",
  675. mctx.pid, tttctx->thrdNum, ret, strerror (ret));
  676. fprintf (stderr, "ldclt[%d]: Problem in getThreadStatus()\n", mctx.pid);
  677. fflush (stderr);
  678. return (-1);
  679. }
  680. *status = tttctx->status;
  681. if ((ret = ldclt_mutex_unlock (&(tttctx->status_mutex))) != 0)
  682. {
  683. fprintf (stderr,
  684. "ldclt[%d]: Cannot mutex_unlock(T%03d), error=%d (%s)\n",
  685. mctx.pid, tttctx->thrdNum, ret, strerror (ret));
  686. fprintf (stderr, "ldclt[%d]: Problem in getThreadStatus()\n", mctx.pid);
  687. fflush (stderr);
  688. return (-1);
  689. }
  690. return (0);
  691. }
  692. /* ****************************************************************************
  693. FUNCTION : setThreadStatus
  694. PURPOSE : Set the value of a given thread's status.
  695. INPUT : tttctx = thread context
  696. status = new status
  697. OUTPUT : None.
  698. RETURN : -1 if error, 0 else.
  699. DESCRIPTION :
  700. *****************************************************************************/
  701. int
  702. setThreadStatus (
  703. thread_context *tttctx,
  704. int status)
  705. {
  706. int ret; /* Return code */
  707. if ((ret = ldclt_mutex_lock (&(tttctx->status_mutex))) != 0)
  708. {
  709. fprintf (stderr,
  710. "ldclt[%d]: Cannot mutex_lock(T%03d), error=%d (%s)\n",
  711. mctx.pid, tttctx->thrdNum, ret, strerror (ret));
  712. fprintf (stderr, "ldclt[%d]: Problem in setThreadStatus()\n", mctx.pid);
  713. fflush (stderr);
  714. return (-1);
  715. }
  716. tttctx->status = status;
  717. if ((ret = ldclt_mutex_unlock (&(tttctx->status_mutex))) != 0)
  718. {
  719. fprintf (stderr,
  720. "ldclt[%d]: Cannot mutex_unlock(T%03d), error=%d (%s)\n",
  721. mctx.pid, tttctx->thrdNum, ret, strerror (ret));
  722. fprintf (stderr, "ldclt[%d]: Problem in setThreadStatus()\n", mctx.pid);
  723. fflush (stderr);
  724. return (-1);
  725. }
  726. return (0);
  727. }
  728. /* ****************************************************************************
  729. FUNCTION : threadMain
  730. PURPOSE : This function is the main function of the client threads
  731. part of this tool.
  732. INPUT : arg = this thread's thread_context
  733. OUTPUT : None.
  734. RETURN : None.
  735. DESCRIPTION :
  736. *****************************************************************************/
  737. void *
  738. threadMain (
  739. void *arg)
  740. {
  741. thread_context *tttctx; /* This thread's context */
  742. int go = 1; /* Thread must continue */
  743. int status; /* Thread's status */ /*JLS 17-11-00*/
  744. /*
  745. * Initialization
  746. */
  747. tttctx = (thread_context *) arg;
  748. if (setThreadStatus (tttctx, CREATED) < 0) /*JLS 17-11-00*/
  749. { /*JLS 17-11-00*/
  750. tttctx->status = DEAD; /*JLS 17-11-00*/
  751. return NULL; /*JLS 17-11-00*/
  752. } /*JLS 17-11-00*/
  753. tttctx->asyncHit = 0;
  754. tttctx->binded = 0;
  755. tttctx->fd = -1;
  756. tttctx->lastVal = mctx.randomLow-1;
  757. tttctx->ldapCtx = NULL;
  758. tttctx->matcheddnp = NULL; /*JLS 15-12-00*/
  759. tttctx->nbOpers = 0;
  760. tttctx->totOpers = 0;
  761. tttctx->pendingNb = 0;
  762. tttctx->firstMsgId = NULL;
  763. tttctx->lastMsgId = NULL;
  764. /*
  765. * Don't forget the buffers !!
  766. * This should save time while redoing random values
  767. */
  768. if ((mctx.mode & NEED_FILTER) || (mctx.mod2 & (M2_GENLDIF|M2_NEED_FILTER))) /*JLS 19-03-01*/
  769. {
  770. if (mctx.mod2 & M2_RDN_VALUE) /*JLS 23-03-01*/
  771. tttctx->bufFilter = (char *) malloc (MAX_FILTER); /*JLS 23-03-01*/
  772. else /*JLS 23-03-01*/
  773. { /*JLS 23-03-01*/
  774. /*
  775. * Variable filter ?
  776. */
  777. tttctx->bufFilter = (char *) malloc (strlen (mctx.filter) + 1);
  778. if (tttctx->bufFilter == NULL) /*JLS 06-03-00*/
  779. { /*JLS 06-03-00*/
  780. printf ("ldclt[%d]: %s: cannot malloc(tttctx->bufFilter), error=%d (%s)\n",
  781. mctx.pid, tttctx->thrdId, errno, strerror (errno));
  782. ldcltExit (EXIT_INIT); /*JLS 18-12-00*/
  783. } /*JLS 06-03-00*/
  784. if (!(mctx.mode & (RANDOM | INCREMENTAL)))
  785. strcpy (tttctx->bufFilter, mctx.filter);
  786. else
  787. {
  788. tttctx->startRandom = strlen (mctx.randomHead);
  789. strcpy (tttctx->bufFilter, mctx.randomHead);
  790. strcpy (&(tttctx->bufFilter[tttctx->startRandom+mctx.randomNbDigit]),
  791. mctx.randomTail);
  792. if (mctx.mode & VERY_VERBOSE)
  793. {
  794. printf ("ldclt[%d]: %s: startRandom = %d\n",
  795. mctx.pid, tttctx->thrdId, tttctx->startRandom);
  796. printf ("ldclt[%d]: %s: randomHead = \"%s\", randomTail = \"%s\"\n",
  797. mctx.pid, tttctx->thrdId, mctx.randomHead, mctx.randomTail);
  798. }
  799. }
  800. } /*JLS 23-03-01*/
  801. /*
  802. * Variable base DN ?
  803. */
  804. tttctx->bufBaseDN = (char *) malloc (strlen (mctx.baseDN) + 1);
  805. if (tttctx->bufBaseDN == NULL) /*JLS 06-03-00*/
  806. { /*JLS 06-03-00*/
  807. printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufBaseDN), error=%d (%s)\n",
  808. mctx.pid, tttctx->thrdNum, errno, strerror (errno));
  809. ldcltExit (EXIT_INIT); /*JLS 18-12-00*/
  810. } /*JLS 06-03-00*/
  811. if (!(mctx.mode & RANDOM_BASE))
  812. strcpy (tttctx->bufBaseDN, mctx.baseDN);
  813. else
  814. {
  815. tttctx->startBaseDN = strlen (mctx.baseDNHead);
  816. strcpy (tttctx->bufBaseDN, mctx.baseDNHead);
  817. strcpy (&(tttctx->bufBaseDN[tttctx->startBaseDN+mctx.baseDNNbDigit]),
  818. mctx.baseDNTail);
  819. }
  820. /*
  821. * Variable bind DN ?
  822. * Do not forget the random bind password below that is activated
  823. * at the same time as the random bind DN.
  824. */
  825. if (mctx.bindDN != NULL) /*JLS 05-03-01*/
  826. { /*JLS 05-03-01*/
  827. tttctx->bufBindDN = (char *) malloc (strlen (mctx.bindDN) + 1);
  828. if (tttctx->bufBindDN == NULL)
  829. {
  830. printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufBindDN), error=%d (%s)\n",
  831. mctx.pid, tttctx->thrdNum, errno, strerror (errno));
  832. ldcltExit (EXIT_INIT);
  833. }
  834. if (!(mctx.mode & RANDOM_BINDDN))
  835. strcpy (tttctx->bufBindDN, mctx.bindDN);
  836. else
  837. {
  838. tttctx->startBindDN = strlen (mctx.bindDNHead);
  839. strcpy (tttctx->bufBindDN, mctx.bindDNHead);
  840. strcpy (&(tttctx->bufBindDN[tttctx->startBindDN+mctx.bindDNNbDigit]),
  841. mctx.bindDNTail);
  842. }
  843. } /*JLS 05-03-01*/
  844. /*
  845. * Variable bind password ?
  846. * Remember that the random bind password feature is activated
  847. * by the same option as the random bind DN, but has here its own
  848. * code section for the ease of coding.
  849. */
  850. if (mctx.passwd != NULL) /*JLS 05-03-01*/
  851. { /*JLS 05-03-01*/
  852. tttctx->bufPasswd = (char *) malloc (strlen (mctx.passwd) + 1);
  853. if (tttctx->bufPasswd == NULL)
  854. {
  855. printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufPasswd), error=%d (%s)\n",
  856. mctx.pid, tttctx->thrdNum, errno, strerror (errno));
  857. ldcltExit (EXIT_INIT);
  858. }
  859. if (!(mctx.mode & RANDOM_BINDDN))
  860. strcpy (tttctx->bufPasswd, mctx.passwd);
  861. else
  862. {
  863. tttctx->startPasswd = strlen (mctx.passwdHead);
  864. strcpy (tttctx->bufPasswd, mctx.passwdHead);
  865. strcpy (&(tttctx->bufPasswd[tttctx->startPasswd+mctx.passwdNbDigit]),
  866. mctx.passwdTail);
  867. }
  868. }
  869. } /*JLS 05-03-01*/
  870. /*
  871. * Bind DN from a file ?
  872. * The trick (mctx.passwd = "foo bar"; ) is needed to
  873. * simplify the code, because in many places we check
  874. * if mctx.passwd exist before sending password.
  875. */
  876. if (mctx.mod2 & M2_RNDBINDFILE) /*JLS 03-05-01*/
  877. { /*JLS 03-05-01*/
  878. tttctx->bufBindDN = (char *) malloc (MAX_DN_LENGTH); /*JLS 03-05-01*/
  879. tttctx->bufPasswd = (char *) malloc (MAX_DN_LENGTH); /*JLS 03-05-01*/
  880. mctx.passwd = "foo bar"; /* trick... */ /*JLS 03-05-01*/
  881. } /*JLS 03-05-01*/
  882. /*
  883. * Variable Authid ?
  884. */
  885. if (mctx.sasl_authid != NULL)
  886. {
  887. tttctx->bufSaslAuthid = (char *) malloc (strlen (mctx.sasl_authid) + 1);
  888. if (tttctx->bufSaslAuthid == NULL)
  889. {
  890. printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufSaslAuthid), error=%d (%s)\n",
  891. mctx.pid, tttctx->thrdNum, errno, strerror (errno));
  892. ldcltExit (EXIT_INIT);
  893. }
  894. if (!(mctx.mod2 & M2_RANDOM_SASLAUTHID))
  895. strcpy (tttctx->bufSaslAuthid, mctx.sasl_authid);
  896. else
  897. {
  898. tttctx->startSaslAuthid = strlen (mctx.sasl_authid_head);
  899. strcpy (tttctx->bufSaslAuthid, mctx.sasl_authid_head);
  900. strcpy (&(tttctx->bufSaslAuthid[tttctx->startSaslAuthid+mctx.sasl_authid_nbdigit]),
  901. mctx.sasl_authid_tail);
  902. }
  903. }
  904. /*
  905. * Initiates the attribute replace buffers
  906. */
  907. if (mctx.mode & ATTR_REPLACE) /* New */ /*JLS 21-11-00*/
  908. {
  909. tttctx->bufAttrpl = (char *) malloc (strlen (mctx.attrpl) + 1);
  910. if (tttctx->bufAttrpl == NULL)
  911. {
  912. printf ("ldclt[%d]: T%03d: cannot malloc(tttctx->bufAttrpl), error=%d (%s)\n",
  913. mctx.pid, tttctx->thrdNum, errno, strerror (errno));
  914. ldcltExit (EXIT_INIT); /*JLS 18-12-00*/
  915. }
  916. tttctx->startAttrpl = strlen (mctx.attrplHead);
  917. strcpy (tttctx->bufAttrpl, mctx.attrplHead);
  918. strcpy (&(tttctx->bufAttrpl[tttctx->startAttrpl+mctx.attrplNbDigit]),
  919. mctx.attrplTail);
  920. }
  921. /*
  922. * Initiates the attribute replace buffers attrplName
  923. */
  924. if ( mctx.mod2 & M2_ATTR_REPLACE_FILE )
  925. {
  926. /* bufAttrpl should point to the same memory location that mctx.attrplFileContent points to */
  927. tttctx->bufAttrpl = mctx.attrplFileContent;
  928. if (tttctx->bufAttrpl == NULL)
  929. {
  930. 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);
  931. ldcltExit (EXIT_INIT);
  932. }
  933. }
  934. /*
  935. * We are ready to go !
  936. */
  937. status = RUNNING; /*JLS 17-11-00*/
  938. if (setThreadStatus (tttctx, RUNNING) < 0) /*JLS 17-11-00*/
  939. status = DEAD; /*JLS 17-11-00*/
  940. /*
  941. * Let's go !
  942. */
  943. while (go && (status != DEAD) && (status != MUST_SHUTDOWN)) /*JLS 17-11-00*/
  944. {
  945. if (mctx.waitSec > 0)
  946. { /*JLS 17-11-00*/
  947. ldclt_sleep (mctx.waitSec);
  948. /*
  949. * Maybe we should shutdown ?
  950. */
  951. if (getThreadStatus (tttctx, &status) < 0) /*JLS 17-11-00*/
  952. break; /*JLS 17-11-00*/
  953. if (status == MUST_SHUTDOWN) /*JLS 17-11-00*/
  954. break; /*JLS 17-11-00*/
  955. } /*JLS 17-11-00*/
  956. /*
  957. * Do a LDAP request
  958. */
  959. if (tttctx->mode & ADD_ENTRIES)
  960. if (doAddEntry (tttctx) < 0)
  961. {
  962. go = 0;
  963. continue;
  964. }
  965. if (tttctx->mode & ATTR_REPLACE) /*JLS 21-11-00*/
  966. if (doAttrReplace (tttctx) < 0) /*JLS 21-11-00*/
  967. { /*JLS 21-11-00*/
  968. go = 0; /*JLS 21-11-00*/
  969. continue; /*JLS 21-11-00*/
  970. } /*JLS 21-11-00*/
  971. if (mctx.mod2 & M2_ATTR_REPLACE_FILE )
  972. if (doAttrFileReplace (tttctx) < 0)
  973. {
  974. go = 0;
  975. continue;
  976. }
  977. if (tttctx->mode & DELETE_ENTRIES)
  978. if (doDeleteEntry (tttctx) < 0)
  979. {
  980. go = 0;
  981. continue;
  982. }
  983. if (mctx.mod2 & M2_BINDONLY) /*JLS 04-05-01*/
  984. if (doBindOnly (tttctx) < 0) /*JLS 04-05-01*/
  985. { /*JLS 04-05-01*/
  986. go = 0; /*JLS 04-05-01*/
  987. continue; /*JLS 04-05-01*/
  988. } /*JLS 04-05-01*/
  989. if (tttctx->mode & EXACT_SEARCH)
  990. if (doExactSearch (tttctx) < 0)
  991. {
  992. go = 0;
  993. continue;
  994. }
  995. if (tttctx->mode & RENAME_ENTRIES)
  996. if (doRename (tttctx) < 0)
  997. {
  998. go = 0;
  999. continue;
  1000. }
  1001. /*
  1002. * Maybe a specific scenario ?
  1003. */
  1004. if (tttctx->mode & SCALAB01) /*JLS 08-01-01*/
  1005. if (doScalab01 (tttctx) < 0) /*JLS 08-01-01*/
  1006. { /*JLS 08-01-01*/
  1007. go = 0; /*JLS 08-01-01*/
  1008. continue; /*JLS 08-01-01*/
  1009. } /*JLS 08-01-01*/
  1010. /*
  1011. * Maybe genldif mode ?
  1012. */
  1013. if (mctx.mod2 & M2_GENLDIF) /*JLS 19-03-01*/
  1014. if (doGenldif (tttctx) < 0) /*JLS 19-03-01*/
  1015. { /*JLS 19-03-01*/
  1016. ldclt_flush_genldif(); /*JLS 02-04-01*/
  1017. go = 0; /*JLS 19-03-01*/
  1018. continue; /*JLS 19-03-01*/
  1019. } /*JLS 19-03-01*/
  1020. if (mctx.mod2 & M2_ABANDON)
  1021. {
  1022. if (doAbandon (tttctx) < 0)
  1023. {
  1024. go = 0;
  1025. continue;
  1026. }
  1027. }
  1028. /*
  1029. * Check the thread's status
  1030. */
  1031. if (getThreadStatus (tttctx, &status) < 0) /*JLS 17-11-00*/
  1032. break; /*JLS 17-11-00*/
  1033. }
  1034. /*
  1035. * End of thread
  1036. */
  1037. /* [156984] once setting "DEAD", nothing should be done in the context */
  1038. /* moved the dead message above setThreadStatus(DEAD) */
  1039. printf ("ldclt[%d]: T%03d: thread is dead.\n", mctx.pid, tttctx->thrdNum);
  1040. fflush (stdout);
  1041. if (setThreadStatus (tttctx, DEAD) < 0) /*JLS 17-11-00*/
  1042. { /*JLS 17-11-00*/
  1043. ldclt_sleep (1); /*JLS 17-11-00*/
  1044. tttctx->status = DEAD; /* Force it !!! */ /*JLS 17-11-00*/
  1045. } /*JLS 17-11-00*/
  1046. return (arg);
  1047. }