iolib.c 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156
  1. /* Copyright (C) 2021 Free Software Foundation, Inc.
  2. Contributed by Oracle.
  3. This file is part of GNU Binutils.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3, or (at your option)
  7. any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, 51 Franklin Street - Fifth Floor, Boston,
  15. MA 02110-1301, USA. */
  16. #include "config.h"
  17. #include <dlfcn.h>
  18. #include <pthread.h>
  19. #include <errno.h>
  20. #include <fcntl.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <unistd.h>
  25. #include <sys/mman.h>
  26. #include <sys/param.h>
  27. #include <sys/stat.h>
  28. #include "gp-defs.h"
  29. #include "collector.h"
  30. #include "gp-experiment.h"
  31. #include "memmgr.h"
  32. /* TprintfT(<level>,...) definitions. Adjust per module as needed */
  33. #define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
  34. #define DBG_LT1 1 // for configuration details, warnings
  35. #define DBG_LT2 2
  36. #define DBG_LT3 3
  37. /* ------------- Data and prototypes for block management --------- */
  38. #define IO_BLK 0 /* Concurrent requests */
  39. #define IO_SEQ 1 /* All requests are sequential, f.e. JAVA_CLASSES */
  40. #define IO_TXT 2 /* Sequential requests. Text strings. */
  41. #define ST_INIT 0 /* Initial state. Not allocated */
  42. #define ST_FREE 1 /* Available */
  43. #define ST_BUSY 2 /* Not available */
  44. /* IO_BLK, IO_SEQ */
  45. #define NCHUNKS 64
  46. /* IO_TXT */
  47. #define NBUFS 64 /* Number of text buffers */
  48. #define CUR_BUSY(x) ((uint32_t) ((x)>>63)) /* bit 63 */
  49. #define CUR_INDX(x) ((uint32_t) (((x)>>57) & 0x3fULL)) /* bits 62:57 */
  50. #define CUR_FOFF(x) ((x) & 0x01ffffffffffffffULL) /* bits 56: 0 */
  51. #define CUR_MAKE(busy, indx, foff) ((((uint64_t)(busy))<<63) | (((uint64_t)(indx))<<57) | ((uint64_t)(foff)) )
  52. typedef struct Buffer
  53. {
  54. uint8_t *vaddr;
  55. uint32_t left; /* bytes left */
  56. uint32_t state; /* ST_FREE or ST_BUSY */
  57. } Buffer;
  58. typedef struct DataHandle
  59. {
  60. Pckt_type kind; /* obsolete (to be removed) */
  61. int iotype; /* IO_BLK, IO_SEQ, IO_TXT */
  62. int active;
  63. char fname[MAXPATHLEN]; /* data file name */
  64. /* IO_BLK, IO_SEQ */
  65. uint32_t nflow; /* number of data flows */
  66. uint32_t *blkstate; /* block states, nflow*NCHUNKS array */
  67. uint32_t *blkoff; /* block offset, nflow*NCHUNKS array */
  68. uint32_t nchnk; /* number of active chunks, probably small for IO_BLK */
  69. uint8_t *chunks[NCHUNKS]; /* chunks (nflow contiguous blocks in virtual memory) */
  70. uint32_t chblk[NCHUNKS]; /* number of active blocks in a chunk */
  71. uint32_t nblk; /* number of blocks in data file */
  72. int exempt; /* if exempt from experiment size limit */
  73. /* IO_TXT */
  74. Buffer *buffers; /* array of text buffers */
  75. uint64_t curpos; /* current buffer and file offset */
  76. } DataHandle;
  77. #define PROFILE_DATAHNDL_MAX 16
  78. static DataHandle data_hndls[PROFILE_DATAHNDL_MAX];
  79. static int initialized = 0;
  80. static long blksz; /* Block size. Multiple of page size. Power of two to make (x%blksz)==(x&(blksz-1)) fast. */
  81. static long log2blksz; /* log2(blksz) to make (x/blksz)==(x>>log2blksz) fast. */
  82. static uint32_t size_limit; /* Experiment size limit */
  83. static uint32_t cur_size; /* Current experiment size */
  84. static void init ();
  85. static void deleteHandle (DataHandle *hndl);
  86. static int exp_size_ck (int nblocks, char *fname);
  87. /* IO_BLK, IO_SEQ */
  88. static int allocateChunk (DataHandle *hndl, unsigned ichunk);
  89. static uint8_t *getBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk);
  90. static int remapBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk);
  91. static int newBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk);
  92. static void deleteBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk);
  93. /* IO_TXT */
  94. static int is_not_the_log_file (char *fname);
  95. static int mapBuffer (char *fname, Buffer *buf, off64_t foff);
  96. static int newBuffer (DataHandle *hndl, uint64_t pos);
  97. static void writeBuffer (Buffer *buf, int blk_off, char *src, int len);
  98. static void deleteBuffer (Buffer *buf);
  99. /*
  100. * Common buffer management routines
  101. */
  102. static void
  103. init ()
  104. {
  105. /* set the block size */
  106. long pgsz = CALL_UTIL (sysconf)(_SC_PAGESIZE);
  107. blksz = pgsz;
  108. log2blksz = 16; /* ensure a minimum size */
  109. while ((1 << log2blksz) < blksz)
  110. log2blksz += 1;
  111. blksz = 1L << log2blksz; /* ensure that blksz is a power of two */
  112. TprintfT (DBG_LT1, "iolib init: page size=%ld (0x%lx) blksz=%ld (0x%lx) log2blksz=%ld\n",
  113. pgsz, pgsz, (long) blksz, (long) blksz, (long) log2blksz);
  114. size_limit = 0;
  115. cur_size = 0;
  116. initialized = 1;
  117. }
  118. DataHandle *
  119. __collector_create_handle (char *descp)
  120. {
  121. int exempt = 0;
  122. char *desc = descp;
  123. if (desc[0] == '*')
  124. {
  125. desc++;
  126. exempt = 1;
  127. }
  128. if (!initialized)
  129. init ();
  130. /* set up header for file, file name, etc. */
  131. if (__collector_exp_dir_name == NULL)
  132. {
  133. __collector_log_write ("<event kind=\"%s\" id=\"%d\">__collector_exp_dir_name==NULL</event>\n",
  134. SP_JCMD_CERROR, COL_ERROR_EXPOPEN);
  135. return NULL;
  136. }
  137. char fname[MAXPATHLEN];
  138. CALL_UTIL (strlcpy)(fname, __collector_exp_dir_name, sizeof (fname));
  139. CALL_UTIL (strlcat)(fname, "/", sizeof (fname));
  140. Pckt_type kind = 0;
  141. int iotype = IO_BLK;
  142. if (__collector_strcmp (desc, SP_HEAPTRACE_FILE) == 0)
  143. kind = HEAP_PCKT;
  144. else if (__collector_strcmp (desc, SP_SYNCTRACE_FILE) == 0)
  145. kind = SYNC_PCKT;
  146. else if (__collector_strcmp (desc, SP_IOTRACE_FILE) == 0)
  147. kind = IOTRACE_PCKT;
  148. else if (__collector_strcmp (desc, SP_RACETRACE_FILE) == 0)
  149. kind = RACE_PCKT;
  150. else if (__collector_strcmp (desc, SP_PROFILE_FILE) == 0)
  151. kind = PROF_PCKT;
  152. else if (__collector_strcmp (desc, SP_OMPTRACE_FILE) == 0)
  153. kind = OMP_PCKT;
  154. else if (__collector_strcmp (desc, SP_HWCNTR_FILE) == 0)
  155. kind = HW_PCKT;
  156. else if (__collector_strcmp (desc, SP_DEADLOCK_FILE) == 0)
  157. kind = DEADLOCK_PCKT;
  158. else if (__collector_strcmp (desc, SP_FRINFO_FILE) == 0)
  159. CALL_UTIL (strlcat)(fname, "data.", sizeof (fname));
  160. else if (__collector_strcmp (desc, SP_LOG_FILE) == 0)
  161. iotype = IO_TXT;
  162. else if (__collector_strcmp (desc, SP_MAP_FILE) == 0)
  163. iotype = IO_TXT;
  164. else if (__collector_strcmp (desc, SP_JCLASSES_FILE) == 0)
  165. iotype = IO_SEQ;
  166. else
  167. {
  168. __collector_log_write ("<event kind=\"%s\" id=\"%d\">iolib unknown file desc %s</event>\n",
  169. SP_JCMD_CERROR, COL_ERROR_EXPOPEN, desc);
  170. return NULL;
  171. }
  172. CALL_UTIL (strlcat)(fname, desc, sizeof (fname));
  173. TprintfT (DBG_LT1, "createHandle calling open on fname = `%s', desc = `%s' %s\n",
  174. fname, desc, (exempt == 0 ? "non-exempt" : "exempt"));
  175. /* allocate a handle -- not mt-safe */
  176. DataHandle *hndl = NULL;
  177. for (int i = 0; i < PROFILE_DATAHNDL_MAX; ++i)
  178. if (data_hndls[i].active == 0)
  179. {
  180. hndl = &data_hndls[i];
  181. break;
  182. }
  183. /* out of handles? */
  184. if (hndl == NULL)
  185. {
  186. __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
  187. SP_JCMD_CERROR, COL_ERROR_NOHNDL, fname);
  188. return NULL;
  189. }
  190. hndl->kind = kind;
  191. hndl->nblk = 0;
  192. hndl->exempt = exempt;
  193. CALL_UTIL (strlcpy)(hndl->fname, fname, sizeof (hndl->fname));
  194. int fd = CALL_UTIL (open)(hndl->fname,
  195. O_RDWR | O_CREAT | O_TRUNC | O_EXCL,
  196. S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  197. if (fd < 0)
  198. {
  199. TprintfT (0, "createHandle open failed -- hndl->fname = `%s', SP_LOG_FILE = `%s': %s\n",
  200. hndl->fname, SP_LOG_FILE, CALL_UTIL (strerror)(errno));
  201. if (is_not_the_log_file (hndl->fname) == 0)
  202. {
  203. char errbuf[4096];
  204. /* If we are trying to create the handle for the log file, write to stderr, not the experiment */
  205. CALL_UTIL (snprintf)(errbuf, sizeof (errbuf),
  206. "create_handle: COL_ERROR_LOG_OPEN %s: %s\n", hndl->fname, CALL_UTIL (strerror)(errno));
  207. CALL_UTIL (write)(2, errbuf, CALL_UTIL (strlen)(errbuf));
  208. }
  209. else
  210. __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: create_handle</event>\n",
  211. SP_JCMD_CERROR, COL_ERROR_FILEOPN, errno, hndl->fname);
  212. return NULL;
  213. }
  214. CALL_UTIL (close)(fd);
  215. hndl->iotype = iotype;
  216. if (hndl->iotype == IO_TXT)
  217. {
  218. /* allocate our buffers in virtual memory */
  219. /* later, we will remap buffers individually to the file */
  220. uint8_t *memory = (uint8_t*) CALL_UTIL (mmap64)(0,
  221. (size_t) (NBUFS * blksz),
  222. PROT_READ | PROT_WRITE,
  223. #if ARCH(SPARC)
  224. MAP_SHARED | MAP_ANON,
  225. #else
  226. MAP_PRIVATE | MAP_ANON,
  227. #endif
  228. -1,
  229. (off64_t) 0);
  230. if (memory == MAP_FAILED)
  231. {
  232. TprintfT (0, "create_handle: can't mmap MAP_ANON (for %s): %s\n", hndl->fname, CALL_UTIL (strerror)(errno));
  233. /* see if this is the log file */
  234. if (is_not_the_log_file (hndl->fname) == 0)
  235. {
  236. /* If we are trying to map the log file, write to stderr, not to the experiment */
  237. char errbuf[4096];
  238. CALL_UTIL (snprintf)(errbuf, sizeof (errbuf),
  239. "create_handle: can't mmap MAP_ANON (for %s): %s\n", hndl->fname, CALL_UTIL (strerror)(errno));
  240. CALL_UTIL (write)(2, errbuf, CALL_UTIL (strlen)(errbuf));
  241. }
  242. else /* write the error message into the experiment */
  243. __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">MAP_ANON (for %s); create_handle</event>\n",
  244. SP_JCMD_CERROR, COL_ERROR_FILEMAP, errno, hndl->fname);
  245. return NULL;
  246. }
  247. TprintfT (DBG_LT2, " create_handle IO_TXT data buffer length=%ld (0x%lx) file='%s' memory=%p -- %p\n",
  248. (long) (NBUFS * blksz), (long) (NBUFS * blksz), hndl->fname,
  249. memory, memory + (NBUFS * blksz) - 1);
  250. /* set up an array of buffers, pointing them to the virtual addresses */
  251. TprintfT (DBG_LT2, "create_handle IO_TXT Buffer structures fname = `%s', NBUFS= %d, size = %ld (0x%lx)\n", fname,
  252. NBUFS, (long) NBUFS * sizeof (Buffer), (long) NBUFS * sizeof (Buffer));
  253. hndl->buffers = (Buffer*) __collector_allocCSize (__collector_heap, NBUFS * sizeof (Buffer), 1);
  254. if (hndl->buffers == NULL)
  255. {
  256. TprintfT (0, "create_handle allocCSize for hndl->buffers failed\n");
  257. CALL_UTIL (munmap)(memory, NBUFS * blksz);
  258. return NULL;
  259. }
  260. for (int i = 0; i < NBUFS; i++)
  261. {
  262. Buffer *buf = &hndl->buffers[i];
  263. buf->vaddr = memory + i * blksz;
  264. buf->state = ST_FREE;
  265. }
  266. /* set the file pointer to the beginning of the file */
  267. hndl->curpos = CUR_MAKE (0, 0, 0);
  268. }
  269. else
  270. {
  271. if (hndl->iotype == IO_BLK)
  272. {
  273. long nflow = CALL_UTIL (sysconf)(_SC_NPROCESSORS_ONLN);
  274. if (nflow < 16)
  275. nflow = 16;
  276. hndl->nflow = (uint32_t) nflow;
  277. }
  278. else if (hndl->iotype == IO_SEQ)
  279. hndl->nflow = 1;
  280. TprintfT (DBG_LT2, "create_handle calling allocCSize blkstate fname=`%s' nflow=%d NCHUNKS=%d size=%ld (0x%lx)\n",
  281. fname, hndl->nflow, NCHUNKS,
  282. (long) (hndl->nflow * NCHUNKS * sizeof (uint32_t)),
  283. (long) (hndl->nflow * NCHUNKS * sizeof (uint32_t)));
  284. uint32_t *blkstate = (uint32_t*) __collector_allocCSize (__collector_heap, hndl->nflow * NCHUNKS * sizeof (uint32_t), 1);
  285. if (blkstate == NULL)
  286. return NULL;
  287. for (int j = 0; j < hndl->nflow * NCHUNKS; ++j)
  288. blkstate[j] = ST_INIT;
  289. hndl->blkstate = blkstate;
  290. TprintfT (DBG_LT2, "create_handle calling allocCSize blkoff fname=`%s' nflow=%d NCHUNKS=%d size=%ld (0x%lx)\n",
  291. fname, hndl->nflow, NCHUNKS,
  292. (long) (hndl->nflow * NCHUNKS * sizeof (uint32_t)),
  293. (long) (hndl->nflow * NCHUNKS * sizeof (uint32_t)));
  294. hndl->blkoff = (uint32_t*) __collector_allocCSize (__collector_heap, hndl->nflow * NCHUNKS * sizeof (uint32_t), 1);
  295. if (hndl->blkoff == NULL)
  296. return NULL;
  297. hndl->nchnk = 0;
  298. for (int j = 0; j < NCHUNKS; ++j)
  299. {
  300. hndl->chunks[j] = NULL;
  301. hndl->chblk[j] = 0;
  302. }
  303. }
  304. hndl->active = 1;
  305. return hndl;
  306. }
  307. static void
  308. deleteHandle (DataHandle *hndl)
  309. {
  310. if (hndl->active == 0)
  311. return;
  312. hndl->active = 0;
  313. if (hndl->iotype == IO_BLK || hndl->iotype == IO_SEQ)
  314. {
  315. /* Delete all blocks. */
  316. /* Since access to hndl->active is not synchronized it's still
  317. * possible that we leave some blocks undeleted.
  318. */
  319. for (int j = 0; j < hndl->nflow * NCHUNKS; ++j)
  320. {
  321. uint32_t oldstate = hndl->blkstate[j];
  322. if (oldstate != ST_FREE)
  323. continue;
  324. /* Mark as busy */
  325. uint32_t state = __collector_cas_32 (hndl->blkstate + j, oldstate, ST_BUSY);
  326. if (state != oldstate)
  327. continue;
  328. deleteBlock (hndl, j / NCHUNKS, j % NCHUNKS);
  329. }
  330. }
  331. else if (hndl->iotype == IO_TXT)
  332. {
  333. /*
  334. * First, make sure that buffers are in some "coherent" state:
  335. *
  336. * At this point, the handle is no longer active. But some threads
  337. * might already have passed the active-handle check and are now
  338. * trying to schedule writes. So, set the handle pointer to "busy".
  339. * This will prevent new writes from being scheduled. Threads that
  340. * polling will time out.
  341. */
  342. hrtime_t timeout = __collector_gethrtime () + 10 * ((hrtime_t) 1000000000);
  343. volatile uint32_t busy = 0;
  344. while (1)
  345. {
  346. uint32_t indx;
  347. uint64_t opos, npos, foff;
  348. int blk_off;
  349. /* read the current pointer */
  350. opos = hndl->curpos;
  351. busy = CUR_BUSY (opos);
  352. indx = CUR_INDX (opos);
  353. foff = CUR_FOFF (opos);
  354. if (busy == 1)
  355. {
  356. if (__collector_gethrtime () > timeout)
  357. {
  358. TprintfT (0, "deleteHandle ERROR: timeout cleaning up handle for %s\n", hndl->fname);
  359. return;
  360. }
  361. continue;
  362. }
  363. blk_off = foff & (blksz - 1);
  364. if (blk_off > 0)
  365. foff += blksz - blk_off;
  366. npos = CUR_MAKE (1, indx, foff);
  367. /* try to update the handle position atomically */
  368. if (__collector_cas_64p (&hndl->curpos, &opos, &npos) != opos)
  369. continue;
  370. /*
  371. * If the last buffer won't be filled, account for
  372. * the white space at the end so that the buffer will
  373. * be deleted properly.
  374. */
  375. if (blk_off > 0)
  376. {
  377. Buffer *buf = &hndl->buffers[indx];
  378. if (__collector_subget_32 (&buf->left, blksz - blk_off) == 0)
  379. deleteBuffer (buf);
  380. }
  381. break;
  382. }
  383. /* wait for buffers to be deleted */
  384. timeout = __collector_gethrtime () + 10 * ((hrtime_t) 1000000000);
  385. for (int i = 0; i < NBUFS; i++)
  386. {
  387. Buffer *buf = &hndl->buffers[i];
  388. while (__collector_cas_32 (&buf->state, ST_FREE, ST_INIT) != ST_FREE)
  389. {
  390. if (__collector_gethrtime () > timeout)
  391. {
  392. TprintfT (0, "deleteHandle ERROR: timeout waiting for buffer %d for %s\n", i, hndl->fname);
  393. return;
  394. }
  395. }
  396. CALL_UTIL (munmap)(buf->vaddr, blksz);
  397. }
  398. /* free buffer array */
  399. __collector_freeCSize (__collector_heap, hndl->buffers, NBUFS * sizeof (Buffer));
  400. }
  401. }
  402. void
  403. __collector_delete_handle (DataHandle *hndl)
  404. {
  405. if (hndl == NULL)
  406. return;
  407. deleteHandle (hndl);
  408. }
  409. static int
  410. exp_size_ck (int nblocks, char *fname)
  411. {
  412. if (size_limit == 0)
  413. return 0;
  414. /* do an atomic add to the cur_size */
  415. uint32_t old_size = cur_size;
  416. uint32_t new_size;
  417. for (;;)
  418. {
  419. new_size = __collector_cas_32 (&cur_size, old_size, old_size + nblocks);
  420. if (new_size == old_size)
  421. {
  422. new_size = old_size + nblocks;
  423. break;
  424. }
  425. old_size = new_size;
  426. }
  427. TprintfT (DBG_LT2, "exp_size_ck() adding %d block(s); new_size = %d, limit = %d blocks; fname = %s\n",
  428. nblocks, new_size, size_limit, fname);
  429. /* pause the entire collector if we have exceeded the limit */
  430. if (old_size < size_limit && new_size >= size_limit)
  431. {
  432. TprintfT (0, "exp_size_ck() experiment size limit exceeded; new_size = %ld, limit = %ld blocks; fname = %s\n",
  433. (long) new_size, (long) size_limit, fname);
  434. (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%ld blocks (each %ld bytes)</event>\n",
  435. SP_JCMD_CWARN, COL_ERROR_SIZELIM, (long) size_limit, (long) blksz);
  436. __collector_pause_m ("size-limit");
  437. __collector_terminate_expt ();
  438. return -1;
  439. }
  440. return 0;
  441. }
  442. int
  443. __collector_set_size_limit (char *par)
  444. {
  445. if (!initialized)
  446. init ();
  447. int lim = CALL_UTIL (strtol)(par, &par, 0);
  448. size_limit = (uint32_t) ((uint64_t) lim * 1024 * 1024 / blksz);
  449. TprintfT (DBG_LT0, "collector_size_limit set to %d MB. = %d blocks\n",
  450. lim, size_limit);
  451. (void) __collector_log_write ("<setting limit=\"%d\"/>\n", lim);
  452. return COL_ERROR_NONE;
  453. }
  454. /*
  455. * IO_BLK and IO_SEQ files
  456. */
  457. /*
  458. * Allocate a chunk (nflow blocks) contiguously in virtual memory.
  459. * Its blocks will be mmapped to the file individually.
  460. */
  461. static int
  462. allocateChunk (DataHandle *hndl, unsigned ichunk)
  463. {
  464. /*
  465. * hndl->chunks[ichunk] is one of:
  466. * - NULL (initial value)
  467. * - CHUNK_BUSY (transition state when allocating the chunk)
  468. * - some address (the allocated chunk)
  469. */
  470. uint8_t *CHUNK_BUSY = (uint8_t *) 1;
  471. hrtime_t timeout = 0;
  472. while (1)
  473. {
  474. if (hndl->chunks[ichunk] > CHUNK_BUSY)
  475. return 0; /* the chunk has already been allocated */
  476. /* try to allocate the chunk (change: NULL => CHUNK_BUSY) */
  477. if (__collector_cas_ptr (&hndl->chunks[ichunk], NULL, CHUNK_BUSY) == NULL)
  478. {
  479. /* allocate virtual memory */
  480. uint8_t *newchunk = (uint8_t*) CALL_UTIL (mmap64)(0,
  481. (size_t) (blksz * hndl->nflow),
  482. PROT_READ | PROT_WRITE,
  483. #if ARCH(SPARC)
  484. MAP_SHARED | MAP_ANON,
  485. #else
  486. MAP_PRIVATE | MAP_ANON,
  487. #endif
  488. -1, (off64_t) 0);
  489. if (newchunk == MAP_FAILED)
  490. {
  491. deleteHandle (hndl);
  492. TprintfT (DBG_LT1, " allocateChunk mmap: start=0x%x length=%ld (0x%lx), offset=%d ret=%p\n",
  493. 0, (long) (blksz * hndl->nflow),
  494. (long) (blksz * hndl->nflow), 0, newchunk);
  495. TprintfT (0, "allocateChunk: can't mmap MAP_ANON (for %s): %s\n", hndl->fname, CALL_UTIL (strerror) (errno));
  496. __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">MAP_ANON (for %s)</event>\n",
  497. SP_JCMD_CERROR, COL_ERROR_FILEMAP, errno, hndl->fname);
  498. return 1;
  499. }
  500. /* assign allocated address to our chunk */
  501. if (__collector_cas_ptr (&hndl->chunks[ichunk], CHUNK_BUSY, newchunk) != CHUNK_BUSY)
  502. {
  503. TprintfT (0, "allocateChunk: can't release chunk CAS lock for %s\n", hndl->fname);
  504. __collector_log_write ("<event kind=\"%s\" id=\"%d\">couldn't release chunk CAS lock (%s)</event>\n",
  505. SP_JCMD_CERROR, COL_ERROR_GENERAL, hndl->fname);
  506. }
  507. __collector_inc_32 (&hndl->nchnk);
  508. return 0;
  509. }
  510. /* check for time out */
  511. if (timeout == 0)
  512. timeout = __collector_gethrtime () + 10 * ((hrtime_t) 1000000000);
  513. if (__collector_gethrtime () > timeout)
  514. {
  515. TprintfT (0, "allocateChunk: timeout for %s\n", hndl->fname);
  516. __collector_log_write ("<event kind=\"%s\" id=\"%d\">timeout allocating chunk for %s</event>\n",
  517. SP_JCMD_CERROR, COL_ERROR_GENERAL, hndl->fname);
  518. return 1;
  519. }
  520. }
  521. }
  522. /*
  523. * Get the address for block (iflow,ichunk).
  524. */
  525. static uint8_t *
  526. getBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk)
  527. {
  528. return hndl->chunks[ichunk] + iflow * blksz;
  529. }
  530. /*
  531. * Map block (iflow,ichunk) to the next part of the file.
  532. */
  533. static int
  534. remapBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk)
  535. {
  536. int rc = 0;
  537. int fd;
  538. /* Get the old file nblk and increment it atomically. */
  539. uint32_t oldblk = hndl->nblk;
  540. for (;;)
  541. {
  542. uint32_t newblk = __collector_cas_32 (&hndl->nblk, oldblk, oldblk + 1);
  543. if (newblk == oldblk)
  544. break;
  545. oldblk = newblk;
  546. }
  547. off64_t offset = (off64_t) oldblk * blksz;
  548. /* 6618470: disable thread cancellation */
  549. int old_cstate;
  550. pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &old_cstate);
  551. /* Open the file. */
  552. int iter = 0;
  553. hrtime_t tso = __collector_gethrtime ();
  554. for (;;)
  555. {
  556. fd = CALL_UTIL (open)(hndl->fname, O_RDWR, 0);
  557. if (fd < 0)
  558. {
  559. if (errno == EMFILE)
  560. {
  561. /* too many open files */
  562. iter++;
  563. if (iter > 1000)
  564. {
  565. /* we've tried 1000 times; kick error back to caller */
  566. char errmsg[MAXPATHLEN + 50];
  567. hrtime_t teo = __collector_gethrtime ();
  568. double deltato = (double) (teo - tso) / 1000000.;
  569. (void) CALL_UTIL (snprintf) (errmsg, sizeof (errmsg), " t=%d, %s: open-retries-failed = %d, %3.6f ms.; remap",
  570. __collector_thr_self (), hndl->fname, iter, deltato);
  571. __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
  572. SP_JCMD_COMMENT, COL_COMMENT_NONE, errmsg);
  573. rc = 1;
  574. goto exit;
  575. }
  576. /* keep trying */
  577. continue;
  578. }
  579. deleteHandle (hndl);
  580. TprintfT (0, "remapBlock: can't open file: %s: %s\n", hndl->fname, STR (CALL_UTIL (strerror)(errno)));
  581. __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">t=%llu, %s: remap </event>\n",
  582. SP_JCMD_CERROR, COL_ERROR_FILEOPN, errno,
  583. (unsigned long long) __collector_thr_self (),
  584. hndl->fname);
  585. rc = 1;
  586. goto exit;
  587. }
  588. else
  589. break;
  590. }
  591. /* report number of retries of the open due to too many open fd's */
  592. if (iter > 0)
  593. {
  594. char errmsg[MAXPATHLEN + 50];
  595. hrtime_t teo = __collector_gethrtime ();
  596. double deltato = (double) (teo - tso) / 1000000.;
  597. (void) CALL_UTIL (snprintf) (errmsg, sizeof (errmsg), " t=%d, %s: open-retries = %d, %3.6f ms.; remap",
  598. __collector_thr_self (), hndl->fname, iter, deltato);
  599. __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
  600. SP_JCMD_COMMENT, COL_COMMENT_NONE, errmsg);
  601. }
  602. /* Ensure disk space is allocated and the block offset is 0 */
  603. uint32_t zero = 0;
  604. int n = CALL_UTIL (pwrite64)(fd, &zero, sizeof (zero), (off64_t) (offset + blksz - sizeof (zero)));
  605. if (n <= 0)
  606. {
  607. deleteHandle (hndl);
  608. TprintfT (0, "remapBlock: can't pwrite file: %s : errno=%d\n", hndl->fname, errno);
  609. __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: remap</event>\n",
  610. SP_JCMD_CERROR, COL_ERROR_NOSPACE, errno, hndl->fname);
  611. CALL_UTIL (close)(fd);
  612. rc = 1;
  613. goto exit;
  614. }
  615. hndl->blkoff[iflow * NCHUNKS + ichunk] = 0;
  616. /* Map block to file */
  617. uint8_t *bptr = getBlock (hndl, iflow, ichunk);
  618. uint8_t *vaddr = (uint8_t *) CALL_UTIL (mmap64)(
  619. (void*) bptr,
  620. (size_t) blksz,
  621. PROT_READ | PROT_WRITE,
  622. MAP_SHARED | MAP_FIXED,
  623. fd,
  624. offset);
  625. if (vaddr != bptr)
  626. {
  627. deleteHandle (hndl);
  628. TprintfT (DBG_LT1, " remapBlock mmap: start=%p length=%ld (0x%lx) offset=0x%llx ret=%p\n",
  629. bptr, (long) blksz, (long) blksz, (long long) offset, vaddr);
  630. TprintfT (0, "remapBlock: can't mmap file: %s : errno=%d\n", hndl->fname, errno);
  631. (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: remap</event>\n",
  632. SP_JCMD_CERROR, COL_ERROR_FILEMAP, errno, hndl->fname);
  633. CALL_UTIL (close)(fd);
  634. rc = 1;
  635. goto exit;
  636. }
  637. CALL_UTIL (close)(fd);
  638. if (hndl->exempt == 0)
  639. exp_size_ck (1, hndl->fname);
  640. else
  641. Tprintf (DBG_LT1, "exp_size_ck() bypassed for %d block(s); exempt fname = %s\n",
  642. 1, hndl->fname);
  643. exit:
  644. /* Restore the previous cancellation state */
  645. pthread_setcancelstate (old_cstate, NULL);
  646. return rc;
  647. }
  648. static int
  649. newBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk)
  650. {
  651. if (allocateChunk (hndl, ichunk) != 0)
  652. return 1;
  653. if (remapBlock (hndl, iflow, ichunk) != 0)
  654. return 1;
  655. /* Update the number of active blocks */
  656. __collector_inc_32 (hndl->chblk + ichunk);
  657. return 0;
  658. }
  659. static void
  660. deleteBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk)
  661. {
  662. uint8_t *bptr = getBlock (hndl, iflow, ichunk);
  663. CALL_UTIL (munmap)((void*) bptr, blksz);
  664. hndl->blkstate[iflow * NCHUNKS + ichunk] = ST_INIT;
  665. /* Update the number of active blocks */
  666. __collector_dec_32 (hndl->chblk + ichunk);
  667. }
  668. int
  669. __collector_write_record (DataHandle *hndl, Common_packet *pckt)
  670. {
  671. if (hndl == NULL || !hndl->active)
  672. return 1;
  673. /* fill in the fields of the common packet structure */
  674. if (pckt->type == 0)
  675. pckt->type = hndl->kind;
  676. if (pckt->tstamp == 0)
  677. pckt->tstamp = __collector_gethrtime ();
  678. if (pckt->lwp_id == 0)
  679. pckt->lwp_id = __collector_lwp_self ();
  680. if (pckt->thr_id == 0)
  681. pckt->thr_id = __collector_thr_self ();
  682. if (pckt->cpu_id == 0)
  683. pckt->cpu_id = CALL_UTIL (getcpuid)();
  684. if (pckt->tsize == 0)
  685. pckt->tsize = sizeof (Common_packet);
  686. TprintfT (DBG_LT3, "collector_write_record to %s, type:%d tsize:%d\n",
  687. hndl->fname, pckt->type, pckt->tsize);
  688. return __collector_write_packet (hndl, (CM_Packet*) pckt);
  689. }
  690. int
  691. __collector_write_packet (DataHandle *hndl, CM_Packet *pckt)
  692. {
  693. if (hndl == NULL || !hndl->active)
  694. return 1;
  695. /* if the experiment is not open, there should be no writes */
  696. if (__collector_expstate != EXP_OPEN)
  697. {
  698. #ifdef DEBUG
  699. char *xstate;
  700. switch (__collector_expstate)
  701. {
  702. case EXP_INIT:
  703. xstate = "EXP_INIT";
  704. break;
  705. case EXP_OPEN:
  706. xstate = "EXP_OPEN";
  707. break;
  708. case EXP_PAUSED:
  709. xstate = "EXP_PAUSED";
  710. break;
  711. case EXP_CLOSED:
  712. xstate = "EXP_CLOSED";
  713. break;
  714. default:
  715. xstate = "Unknown";
  716. break;
  717. }
  718. TprintfT (0, "collector_write_packet: write to %s while experiment state is %s\n",
  719. hndl->fname, xstate);
  720. #endif
  721. return 1;
  722. }
  723. int recsz = pckt->tsize;
  724. if (recsz > blksz)
  725. {
  726. TprintfT (0, "collector_write_packet: packet too long: %d (max %ld)\n", recsz, blksz);
  727. return 1;
  728. }
  729. unsigned tid = (__collector_no_threads ? __collector_lwp_self () : __collector_thr_self ());
  730. unsigned iflow = tid % hndl->nflow;
  731. /* Acquire block */
  732. uint32_t *sptr = &hndl->blkstate[iflow * NCHUNKS];
  733. uint32_t state = ST_BUSY;
  734. unsigned ichunk;
  735. for (ichunk = 0; ichunk < NCHUNKS; ++ichunk)
  736. {
  737. uint32_t oldstate = sptr[ichunk];
  738. if (oldstate == ST_BUSY)
  739. continue;
  740. /* Mark as busy */
  741. state = __collector_cas_32 (sptr + ichunk, oldstate, ST_BUSY);
  742. if (state == oldstate)
  743. break;
  744. if (state == ST_BUSY)
  745. continue;
  746. /* It's possible the state changed from ST_INIT to ST_FREE */
  747. oldstate = state;
  748. state = __collector_cas_32 (sptr + ichunk, oldstate, ST_BUSY);
  749. if (state == oldstate)
  750. break;
  751. }
  752. if (state == ST_BUSY || ichunk == NCHUNKS)
  753. {
  754. /* We are out of blocks for this data flow.
  755. * We might switch to another flow but for now report and return.
  756. */
  757. TprintfT (0, "collector_write_packet: all %d blocks on flow %d for %s are busy\n",
  758. NCHUNKS, iflow, hndl->fname);
  759. return 1;
  760. }
  761. if (state == ST_INIT && newBlock (hndl, iflow, ichunk) != 0)
  762. return 1;
  763. uint8_t *bptr = getBlock (hndl, iflow, ichunk);
  764. uint32_t blkoff = hndl->blkoff[iflow * NCHUNKS + ichunk];
  765. if (blkoff + recsz > blksz)
  766. {
  767. /* The record doesn't fit. Close the block */
  768. if (blkoff < blksz)
  769. {
  770. Common_packet *closed = (Common_packet *) (bptr + blkoff);
  771. closed->type = CLOSED_PCKT;
  772. closed->tsize = blksz - blkoff; /* redundant */
  773. }
  774. if (remapBlock (hndl, iflow, ichunk) != 0)
  775. return 1;
  776. blkoff = hndl->blkoff[iflow * NCHUNKS + ichunk];
  777. }
  778. if (blkoff + recsz < blksz)
  779. {
  780. /* Set the empty padding */
  781. Common_packet *empty = (Common_packet *) (bptr + blkoff + recsz);
  782. empty->type = EMPTY_PCKT;
  783. empty->tsize = blksz - blkoff - recsz;
  784. }
  785. __collector_memcpy (bptr + blkoff, pckt, recsz);
  786. /* Release block */
  787. if (hndl->active == 0)
  788. {
  789. deleteBlock (hndl, iflow, ichunk);
  790. return 0;
  791. }
  792. hndl->blkoff[iflow * NCHUNKS + ichunk] += recsz;
  793. sptr[ichunk] = ST_FREE;
  794. return 0;
  795. }
  796. /*
  797. * IO_TXT files
  798. *
  799. * IO_TXT covers the case where many threads are trying to write text messages
  800. * sequentially (atomically) to a file. Examples include SP_LOG_FILE and SP_MAP_FILE.
  801. *
  802. * The file is not written directly, but by writing to mmapped virtual memory.
  803. * The granularity of the mapping is a "Buffer". There may be as many as
  804. * NBUFS buffers at any one time.
  805. *
  806. * The current position of the file is handled via hndl->curpos.
  807. *
  808. * * It is accessed atomically with 64-bit CAS instructions.
  809. *
  810. * * This 64-bit word encapsulates:
  811. * - busy: a bit to lock access to hndl->curpos
  812. * - indx: an index indicating which Buffer to use for the current position
  813. * - foff: the file offset
  814. *
  815. * * The contents are accessed with:
  816. * - unpack macros: CUR_BUSY CUR_INDX CUR_FOFF
  817. * - pack macro : CUR_MAKE
  818. *
  819. * Conceptually, what happens when a thread wants to write a message is:
  820. * - acquire the hndl->curpos "busy" lock
  821. * . acquire and map new Buffers if needed to complete the message
  822. * . update the file offset
  823. * . release the lock
  824. * - write to the corresponding buffers
  825. *
  826. * Each Buffer has a buf->left field that tracks how many more bytes
  827. * need to be written to the Buffer. After a thread writes to a Buffer,
  828. * it decrements buf->left atomically. When buf->left reaches 0, the
  829. * Buffer (mapping) is deleted, freeing the Buffer for a new mapping.
  830. *
  831. * The actual implementation has some twists:
  832. *
  833. * * If the entire text message fits into the current Buffer -- that is,
  834. * no new Buffers are needed -- the thread does not acquire the lock.
  835. * It simply updates hndl->curpos atomically to the new file offset.
  836. *
  837. * * There are various timeouts to prevent hangs in case of abnormalities.
  838. */
  839. static int
  840. is_not_the_log_file (char *fname)
  841. {
  842. if (CALL_UTIL (strstr)(fname, SP_LOG_FILE) == NULL)
  843. return 1;
  844. return 0;
  845. }
  846. static int
  847. mapBuffer (char *fname, Buffer *buf, off64_t foff)
  848. {
  849. int rc = 0;
  850. /* open fname */
  851. int fd = CALL_UTIL (open)(fname, O_RDWR, 0);
  852. if (fd < 0)
  853. {
  854. TprintfT (0, "mapBuffer ERROR: can't open file: %s\n", fname);
  855. if (is_not_the_log_file (fname))
  856. __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: mapBuffer</event>\n",
  857. SP_JCMD_CERROR, COL_ERROR_FILEOPN, errno, fname);
  858. return 1;
  859. }
  860. TprintfT (DBG_LT2, "mapBuffer pwrite file %s at 0x%llx\n", fname, (long long) foff);
  861. /* ensure disk space is allocated */
  862. char nl = '\n';
  863. int n = CALL_UTIL (pwrite64)(fd, &nl, sizeof (nl), (off64_t) (foff + blksz - sizeof (nl)));
  864. if (n <= 0)
  865. {
  866. TprintfT (0, "mapBuffer ERROR: can't pwrite file %s at 0x%llx\n", fname,
  867. (long long) (foff + blksz - sizeof (nl)));
  868. if (is_not_the_log_file (fname))
  869. __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: mapBuffer</event>\n",
  870. SP_JCMD_CERROR, COL_ERROR_FILETRNC, errno, fname);
  871. rc = 1;
  872. goto exit;
  873. }
  874. /* mmap buf->vaddr to fname at foff */
  875. uint8_t *vaddr = CALL_UTIL (mmap64)(buf->vaddr, (size_t) blksz,
  876. PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, foff);
  877. if (vaddr != buf->vaddr)
  878. {
  879. TprintfT (DBG_LT1, " mapBuffer mmap: start=%p length=%ld (0x%lx) offset=0x%llx ret=%p\n",
  880. buf->vaddr, blksz, blksz, (long long) foff, vaddr);
  881. TprintfT (0, "mapBuffer ERROR: can't mmap %s: vaddr=%p size=%ld (0x%lx) ret=%p off=0x%llx errno=%d\n",
  882. fname, buf->vaddr, blksz, blksz, vaddr, (long long) foff, errno);
  883. if (is_not_the_log_file (fname))
  884. __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: mapBuffer</event>\n",
  885. SP_JCMD_CERROR, COL_ERROR_FILEMAP, errno, fname);
  886. rc = 1;
  887. }
  888. else
  889. buf->left = blksz;
  890. exit:
  891. CALL_UTIL (close)(fd);
  892. /* Should we check buffer size? Let's not since:
  893. * - IO_TXT is typically not going to be that big
  894. * - we want log.xml to be treated specially
  895. */
  896. /* exp_size_ck( 1, fname ); */
  897. return rc;
  898. }
  899. static int
  900. newBuffer (DataHandle *hndl, uint64_t foff)
  901. {
  902. /* find a ST_FREE buffer and mark it ST_BUSY */
  903. int ibuf;
  904. for (ibuf = 0; ibuf < NBUFS; ibuf++)
  905. if (__collector_cas_32 (&hndl->buffers[ibuf].state, ST_FREE, ST_BUSY) == ST_FREE)
  906. break;
  907. if (ibuf >= NBUFS)
  908. {
  909. TprintfT (0, "newBuffer ERROR: all buffers busy for %s\n", hndl->fname);
  910. return -1;
  911. }
  912. Buffer *nbuf = hndl->buffers + ibuf;
  913. /* map buffer */
  914. if (mapBuffer (hndl->fname, nbuf, foff) != 0)
  915. {
  916. nbuf->state = ST_FREE;
  917. ibuf = -1;
  918. goto exit;
  919. }
  920. exit:
  921. return ibuf;
  922. }
  923. static void
  924. writeBuffer (Buffer *buf, int blk_off, char *src, int len)
  925. {
  926. __collector_memcpy (buf->vaddr + blk_off, src, len);
  927. if (__collector_subget_32 (&buf->left, len) == 0)
  928. deleteBuffer (buf);
  929. }
  930. static void
  931. deleteBuffer (Buffer *buf)
  932. {
  933. buf->state = ST_FREE;
  934. }
  935. int
  936. __collector_write_string (DataHandle *hndl, char *src, int len)
  937. {
  938. if (hndl == NULL || !hndl->active)
  939. return 1;
  940. if (len <= 0)
  941. return 0;
  942. hrtime_t timeout = __collector_gethrtime () + 20 * ((hrtime_t) 1000000000);
  943. volatile uint32_t busy = 0;
  944. while (1)
  945. {
  946. uint32_t indx;
  947. uint64_t opos, foff, base;
  948. int blk_off, buf_indices[NBUFS], ibuf, nbufs;
  949. /* read and decode the current pointer */
  950. opos = hndl->curpos;
  951. busy = CUR_BUSY (opos);
  952. indx = CUR_INDX (opos);
  953. foff = CUR_FOFF (opos);
  954. if (busy == 1)
  955. {
  956. if (__collector_gethrtime () > timeout)
  957. {
  958. /*
  959. * E.g., if another thread deleted the handle
  960. * after we checked hndl->active.
  961. */
  962. TprintfT (0, "__collector_write_string ERROR: timeout writing length=%d to text file: %s\n", len, hndl->fname);
  963. return 1;
  964. }
  965. continue;
  966. }
  967. /* initial block offset */
  968. blk_off = foff & (blksz - 1);
  969. /* number of new buffers to map */
  970. int lastbuf = ((foff + len - 1) >> log2blksz); /* last block file index we will write */
  971. int firstbuf = ((foff - 1) >> log2blksz); /* last block file index we have written */
  972. nbufs = lastbuf - firstbuf;
  973. TprintfT (DBG_LT2, "__collector_write_string firstbuf = %d, lastbuf = %d, nbufs = %d, log2blksz = %ld\n",
  974. firstbuf, lastbuf, nbufs, log2blksz);
  975. if (nbufs >= NBUFS)
  976. {
  977. Tprintf (0, "__collector_write_string ERROR: string of length %d too long to be written to text file: %s\n", len, hndl->fname);
  978. return 1;
  979. }
  980. /* things are simple if we don't need new buffers */
  981. if (nbufs == 0)
  982. {
  983. /* try to update the handle position atomically */
  984. uint64_t npos = CUR_MAKE (0, indx, foff + len);
  985. if (__collector_cas_64p (&hndl->curpos, &opos, &npos) != opos)
  986. continue;
  987. /* success! copy our string and we're done */
  988. TprintfT (DBG_LT2, "__collector_write_string writeBuffer[%d]: vaddr = %p, len = %d, foff = %lld, '%s'\n",
  989. indx, hndl->buffers[indx].vaddr, len, (long long) foff, src);
  990. writeBuffer (&hndl->buffers[indx], foff & (blksz - 1), src, len);
  991. break;
  992. }
  993. /* initialize the new signal mask */
  994. sigset_t new_mask;
  995. sigset_t old_mask;
  996. CALL_UTIL (sigfillset)(&new_mask);
  997. /* 6618470: disable thread cancellation */
  998. int old_cstate;
  999. pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &old_cstate);
  1000. /* block all signals */
  1001. CALL_UTIL (sigprocmask)(SIG_SETMASK, &new_mask, &old_mask);
  1002. /* but if we need new buffers, "lock" the handle pointer */
  1003. uint64_t lpos = CUR_MAKE (1, indx, foff);
  1004. if (__collector_cas_64p (&hndl->curpos, &opos, &lpos) != opos)
  1005. {
  1006. /* restore signal mask */
  1007. CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
  1008. /* Restore the previous cancellation state */
  1009. pthread_setcancelstate (old_cstate, NULL);
  1010. continue;
  1011. }
  1012. /* map new buffers */
  1013. base = ((foff - 1) & ~(blksz - 1)); /* last buffer to have been mapped */
  1014. for (ibuf = 0; ibuf < nbufs; ibuf++)
  1015. {
  1016. base += blksz;
  1017. buf_indices[ibuf] = newBuffer (hndl, base);
  1018. if (buf_indices[ibuf] < 0)
  1019. break;
  1020. }
  1021. /* "unlock" the handle pointer */
  1022. uint64_t npos = CUR_MAKE (0, indx, foff);
  1023. if (ibuf == nbufs)
  1024. npos = CUR_MAKE (0, buf_indices[nbufs - 1], foff + len);
  1025. if (__collector_cas_64p (&hndl->curpos, &lpos, &npos) != lpos)
  1026. {
  1027. TprintfT (0, "__collector_write_string ERROR: file handle corrupted: %s\n", hndl->fname);
  1028. /*
  1029. * At this point, the handle is apparently corrupted and
  1030. * presumably locked. No telling what's going on. Still
  1031. * let's proceed and write our data and let a later thread
  1032. * raise an error if it encounters one.
  1033. */
  1034. }
  1035. /* restore signal mask */
  1036. CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
  1037. /* Restore the previous cancellation state */
  1038. pthread_setcancelstate (old_cstate, NULL);
  1039. /* if we couldn't map all the buffers we needed, don't write any part of the string */
  1040. if (ibuf < nbufs)
  1041. {
  1042. TprintfT (0, "__collector_write_string ERROR: can't map new buffer: %s\n", hndl->fname);
  1043. return 1;
  1044. }
  1045. /* write any data to the old block */
  1046. if (blk_off > 0)
  1047. {
  1048. TprintfT (DBG_LT2, "__collector_write_string partial writeBuffer[%d]: len=%ld, foff = %d '%s'\n",
  1049. indx, blksz - blk_off, blk_off, src);
  1050. writeBuffer (&hndl->buffers[indx], blk_off, src, blksz - blk_off);
  1051. src += blksz - blk_off;
  1052. len -= blksz - blk_off;
  1053. }
  1054. /* write data to the new blocks */
  1055. for (ibuf = 0; ibuf < nbufs; ibuf++)
  1056. {
  1057. int clen = blksz;
  1058. if (clen > len)
  1059. clen = len;
  1060. TprintfT (DBG_LT2, "__collector_write_string continue writeBuffer[%d]: len= %d, %s",
  1061. ibuf, clen, src);
  1062. writeBuffer (&hndl->buffers[buf_indices[ibuf]], 0, src, clen);
  1063. src += clen;
  1064. len -= clen;
  1065. }
  1066. break;
  1067. }
  1068. return 0;
  1069. }