/src/pdsh/cbuf.c

https://code.google.com/ · C · 1814 lines · 1338 code · 226 blank · 250 comment · 377 complexity · fa029cf4f962d7f512a04d537f042e85 MD5 · raw file

  1. /*****************************************************************************
  2. * $Id$
  3. *****************************************************************************
  4. * Copyright (C) 2002-2003 The Regents of the University of California.
  5. * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  6. * Written by Chris Dunlap <cdunlap@llnl.gov>.
  7. *
  8. * This file is from LSD-Tools, the LLNL Software Development Toolbox.
  9. *
  10. * LSD-Tools is free software; you can redistribute it and/or modify it under
  11. * the terms of the GNU General Public License as published by the Free
  12. * Software Foundation; either version 2 of the License, or (at your option)
  13. * any later version.
  14. *
  15. * LSD-Tools is distributed in the hope that it will be useful, but WITHOUT
  16. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  17. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  18. * more details.
  19. *
  20. * You should have received a copy of the GNU General Public License along
  21. * with LSD-Tools; if not, write to the Free Software Foundation, Inc.,
  22. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  23. *****************************************************************************
  24. * Refer to "cbuf.h" for documentation on public functions.
  25. *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif /* HAVE_CONFIG_H */
  29. #ifdef WITH_PTHREADS
  30. # include <pthread.h>
  31. #endif /* WITH_PTHREADS */
  32. #include <assert.h>
  33. #include <errno.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <unistd.h>
  37. #include "cbuf.h"
  38. /*********************
  39. * lsd_fatal_error *
  40. *********************/
  41. #ifdef WITH_LSD_FATAL_ERROR_FUNC
  42. # undef lsd_fatal_error
  43. extern void lsd_fatal_error(char *file, int line, char *mesg);
  44. #else /* !WITH_LSD_FATAL_ERROR_FUNC */
  45. # ifndef lsd_fatal_error
  46. # include <errno.h>
  47. # include <stdio.h>
  48. # include <string.h>
  49. # define lsd_fatal_error(file, line, mesg) \
  50. do { \
  51. fprintf(stderr, "ERROR: [%s:%d] %s: %s\n", \
  52. file, line, mesg, strerror(errno)); \
  53. } while (0)
  54. # endif /* !lsd_fatal_error */
  55. #endif /* !WITH_LSD_FATAL_ERROR_FUNC */
  56. /*********************
  57. * lsd_nomem_error *
  58. *********************/
  59. #ifdef WITH_LSD_NOMEM_ERROR_FUNC
  60. # undef lsd_nomem_error
  61. extern void * lsd_nomem_error(char *file, int line, char *mesg);
  62. #else /* !WITH_LSD_NOMEM_ERROR_FUNC */
  63. # ifndef lsd_nomem_error
  64. # define lsd_nomem_error(file, line, mesg) (NULL)
  65. # endif /* !lsd_nomem_error */
  66. #endif /* !WITH_LSD_NOMEM_ERROR_FUNC */
  67. /***************
  68. * Constants *
  69. ***************/
  70. #define CBUF_CHUNK 1000
  71. #define CBUF_MAGIC 0xDEADBEEF
  72. #define CBUF_MAGIC_LEN (sizeof(unsigned long))
  73. /****************
  74. * Data Types *
  75. ****************/
  76. struct cbuf {
  77. #ifndef NDEBUG
  78. unsigned long magic; /* cookie for asserting validity */
  79. #endif /* !NDEBUG */
  80. #ifdef WITH_PTHREADS
  81. pthread_mutex_t mutex; /* mutex to protect access to cbuf */
  82. #endif /* WITH_PTHREADS */
  83. int alloc; /* num bytes malloc'd/realloc'd */
  84. int minsize; /* min bytes of data to allocate */
  85. int maxsize; /* max bytes of data to allocate */
  86. int size; /* num bytes of data allocated */
  87. int used; /* num bytes of unread data */
  88. cbuf_overwrite_t overwrite; /* overwrite option behavior */
  89. int got_wrap; /* true if data has wrapped */
  90. int i_in; /* index to where data is written in */
  91. int i_out; /* index to where data is read out */
  92. int i_rep; /* index to where data is replayable */
  93. unsigned char *data; /* ptr to circular buffer of data */
  94. };
  95. typedef int (*cbuf_iof) (void *cbuf_data, void *arg, int len);
  96. /****************
  97. * Prototypes *
  98. ****************/
  99. static int cbuf_find_replay_line (cbuf_t cb, int chars, int *nlines, int *nl);
  100. static int cbuf_find_unread_line (cbuf_t cb, int chars, int *nlines);
  101. static int cbuf_get_fd (void *dstbuf, int *psrcfd, int len);
  102. static int cbuf_get_mem (void *dstbuf, unsigned char **psrcbuf, int len);
  103. static int cbuf_put_fd (void *srcbuf, int *pdstfd, int len);
  104. static int cbuf_put_mem (void *srcbuf, unsigned char **pdstbuf, int len);
  105. static int cbuf_copier (cbuf_t src, cbuf_t dst, int len, int *ndropped);
  106. static int cbuf_dropper (cbuf_t cb, int len);
  107. static int cbuf_reader (cbuf_t src, int len, cbuf_iof putf, void *dst);
  108. static int cbuf_replayer (cbuf_t src, int len, cbuf_iof putf, void *dst);
  109. static int cbuf_writer (cbuf_t dst, int len, cbuf_iof getf, void *src,
  110. int *ndropped);
  111. static int cbuf_grow (cbuf_t cb, int n);
  112. static int cbuf_shrink (cbuf_t cb);
  113. #ifndef NDEBUG
  114. static int cbuf_is_valid (cbuf_t cb);
  115. #endif /* !NDEBUG */
  116. /************
  117. * Macros *
  118. ************/
  119. #ifndef MAX
  120. # define MAX(x,y) (((x) >= (y)) ? (x) : (y))
  121. #endif /* !MAX */
  122. #ifndef MIN
  123. # define MIN(x,y) (((x) <= (y)) ? (x) : (y))
  124. #endif /* !MIN */
  125. #ifdef WITH_PTHREADS
  126. # define cbuf_mutex_init(cb) \
  127. do { \
  128. int e = pthread_mutex_init(&cb->mutex, NULL); \
  129. if (e) { \
  130. errno = e; \
  131. lsd_fatal_error(__FILE__, __LINE__, "cbuf mutex init"); \
  132. abort(); \
  133. } \
  134. } while (0)
  135. # define cbuf_mutex_lock(cb) \
  136. do { \
  137. int e = pthread_mutex_lock(&cb->mutex); \
  138. if (e) { \
  139. errno = e; \
  140. lsd_fatal_error(__FILE__, __LINE__, "cbuf mutex lock"); \
  141. abort(); \
  142. } \
  143. } while (0)
  144. # define cbuf_mutex_unlock(cb) \
  145. do { \
  146. int e = pthread_mutex_unlock(&cb->mutex); \
  147. if (e) { \
  148. errno = e; \
  149. lsd_fatal_error(__FILE__, __LINE__, "cbuf mutex unlock"); \
  150. abort(); \
  151. } \
  152. } while (0)
  153. # define cbuf_mutex_destroy(cb) \
  154. do { \
  155. int e = pthread_mutex_destroy(&cb->mutex); \
  156. if (e) { \
  157. errno = e; \
  158. lsd_fatal_error(__FILE__, __LINE__, "cbuf mutex destroy"); \
  159. abort(); \
  160. } \
  161. } while (0)
  162. # ifndef NDEBUG
  163. static int cbuf_mutex_is_locked (cbuf_t cb);
  164. # endif /* !NDEBUG */
  165. #else /* !WITH_PTHREADS */
  166. # define cbuf_mutex_init(cb)
  167. # define cbuf_mutex_lock(cb)
  168. # define cbuf_mutex_unlock(cb)
  169. # define cbuf_mutex_destroy(cb)
  170. # define cbuf_mutex_is_locked(cb) (1)
  171. #endif /* !WITH_PTHREADS */
  172. /***************
  173. * Functions *
  174. ***************/
  175. cbuf_t
  176. cbuf_create (int minsize, int maxsize)
  177. {
  178. cbuf_t cb;
  179. if (minsize <= 0) {
  180. errno = EINVAL;
  181. return(NULL);
  182. }
  183. if (!(cb = malloc(sizeof(struct cbuf)))) {
  184. errno = ENOMEM;
  185. return(lsd_nomem_error(__FILE__, __LINE__, "cbuf struct"));
  186. }
  187. /* Circular buffer is empty when (i_in == i_out),
  188. * so reserve 1 byte for this sentinel.
  189. */
  190. cb->alloc = minsize + 1;
  191. #ifndef NDEBUG
  192. /* Reserve space for the magic cookies used to protect the
  193. * cbuf data[] array from underflow and overflow.
  194. */
  195. cb->alloc += 2 * CBUF_MAGIC_LEN;
  196. #endif /* !NDEBUG */
  197. if (!(cb->data = malloc(cb->alloc))) {
  198. free(cb);
  199. errno = ENOMEM;
  200. return(lsd_nomem_error(__FILE__, __LINE__, "cbuf data"));
  201. }
  202. cbuf_mutex_init(cb);
  203. cb->minsize = minsize;
  204. cb->maxsize = (maxsize > minsize) ? maxsize : minsize;
  205. cb->size = minsize;
  206. cb->used = 0;
  207. cb->overwrite = CBUF_WRAP_MANY;
  208. cb->got_wrap = 0;
  209. cb->i_in = cb->i_out = cb->i_rep = 0;
  210. #ifndef NDEBUG
  211. /* C is for cookie, that's good enough for me, yeah!
  212. * The magic cookies are only defined during DEBUG code.
  213. * The first "magic" cookie is at the top of the structure.
  214. * Magic cookies are also placed at the top & bottom of the
  215. * cbuf data[] array to catch buffer underflow & overflow errors.
  216. */
  217. cb->data += CBUF_MAGIC_LEN; /* jump forward past underflow magic */
  218. cb->magic = CBUF_MAGIC;
  219. /*
  220. * Must use memcpy since overflow cookie may not be word-aligned.
  221. */
  222. memcpy(cb->data - CBUF_MAGIC_LEN, (void *) &cb->magic, CBUF_MAGIC_LEN);
  223. memcpy(cb->data + cb->size + 1, (void *) &cb->magic, CBUF_MAGIC_LEN);
  224. cbuf_mutex_lock(cb);
  225. assert(cbuf_is_valid(cb));
  226. cbuf_mutex_unlock(cb);
  227. #endif /* !NDEBUG */
  228. return(cb);
  229. }
  230. void
  231. cbuf_destroy (cbuf_t cb)
  232. {
  233. assert(cb != NULL);
  234. cbuf_mutex_lock(cb);
  235. assert(cbuf_is_valid(cb));
  236. #ifndef NDEBUG
  237. /* The moon sometimes looks like a C, but you can't eat that.
  238. * Munch the magic cookies before freeing memory.
  239. */
  240. cb->magic = ~CBUF_MAGIC; /* the anti-cookie! */
  241. memcpy(cb->data - CBUF_MAGIC_LEN, (void *) &cb->magic, CBUF_MAGIC_LEN);
  242. memcpy(cb->data + cb->size + 1, (void *) &cb->magic, CBUF_MAGIC_LEN);
  243. cb->data -= CBUF_MAGIC_LEN; /* jump back to what malloc returned */
  244. #endif /* !NDEBUG */
  245. free(cb->data);
  246. cbuf_mutex_unlock(cb);
  247. cbuf_mutex_destroy(cb);
  248. free(cb);
  249. return;
  250. }
  251. void
  252. cbuf_flush (cbuf_t cb)
  253. {
  254. assert(cb != NULL);
  255. cbuf_mutex_lock(cb);
  256. assert(cbuf_is_valid(cb));
  257. /*
  258. * FIXME: Shrink buffer back to minimum size.
  259. */
  260. cb->used = 0;
  261. cb->got_wrap = 0;
  262. cb->i_in = cb->i_out = cb->i_rep = 0;
  263. assert(cbuf_is_valid(cb));
  264. cbuf_mutex_unlock(cb);
  265. return;
  266. }
  267. int
  268. cbuf_size (cbuf_t cb)
  269. {
  270. int size;
  271. assert(cb != NULL);
  272. cbuf_mutex_lock(cb);
  273. assert(cbuf_is_valid(cb));
  274. size = cb->size;
  275. cbuf_mutex_unlock(cb);
  276. return(size);
  277. }
  278. int
  279. cbuf_free (cbuf_t cb)
  280. {
  281. int nfree;
  282. assert(cb != NULL);
  283. cbuf_mutex_lock(cb);
  284. assert(cbuf_is_valid(cb));
  285. nfree = cb->size - cb->used;
  286. cbuf_mutex_unlock(cb);
  287. return(nfree);
  288. }
  289. int
  290. cbuf_used (cbuf_t cb)
  291. {
  292. int used;
  293. assert(cb != NULL);
  294. cbuf_mutex_lock(cb);
  295. assert(cbuf_is_valid(cb));
  296. used = cb->used;
  297. cbuf_mutex_unlock(cb);
  298. return(used);
  299. }
  300. int
  301. cbuf_lines_used (cbuf_t cb)
  302. {
  303. int lines = -1;
  304. assert(cb != NULL);
  305. cbuf_mutex_lock(cb);
  306. assert(cbuf_is_valid(cb));
  307. cbuf_find_unread_line(cb, cb->size, &lines);
  308. cbuf_mutex_unlock(cb);
  309. return(lines);
  310. }
  311. int
  312. cbuf_reused (cbuf_t cb)
  313. {
  314. int reused;
  315. assert(cb != NULL);
  316. cbuf_mutex_lock(cb);
  317. assert(cbuf_is_valid(cb));
  318. reused = (cb->i_out - cb->i_rep + (cb->size + 1)) % (cb->size + 1);
  319. cbuf_mutex_unlock(cb);
  320. return(reused);
  321. }
  322. int
  323. cbuf_lines_reused (cbuf_t cb)
  324. {
  325. int lines = -1;
  326. assert(cb != NULL);
  327. cbuf_mutex_lock(cb);
  328. assert(cbuf_is_valid(cb));
  329. cbuf_find_replay_line(cb, cb->size, &lines, NULL);
  330. cbuf_mutex_unlock(cb);
  331. return(lines);
  332. }
  333. int
  334. cbuf_is_empty (cbuf_t cb)
  335. {
  336. int used;
  337. assert(cb != NULL);
  338. cbuf_mutex_lock(cb);
  339. assert(cbuf_is_valid(cb));
  340. used = cb->used;
  341. cbuf_mutex_unlock(cb);
  342. return(used == 0);
  343. }
  344. int
  345. cbuf_opt_get (cbuf_t cb, cbuf_opt_t name, int *value)
  346. {
  347. int rc = 0;
  348. assert(cb != NULL);
  349. if (value == NULL) {
  350. errno = EINVAL;
  351. return(-1);
  352. }
  353. cbuf_mutex_lock(cb);
  354. assert(cbuf_is_valid(cb));
  355. if (name == CBUF_OPT_OVERWRITE) {
  356. *value = cb->overwrite;
  357. }
  358. else {
  359. errno = EINVAL;
  360. rc = -1;
  361. }
  362. cbuf_mutex_unlock(cb);
  363. return(rc);
  364. }
  365. int
  366. cbuf_opt_set (cbuf_t cb, cbuf_opt_t name, int value)
  367. {
  368. int rc = 0;
  369. assert(cb != NULL);
  370. cbuf_mutex_lock(cb);
  371. assert(cbuf_is_valid(cb));
  372. if (name == CBUF_OPT_OVERWRITE) {
  373. if ( (value == CBUF_NO_DROP)
  374. || (value == CBUF_WRAP_ONCE)
  375. || (value == CBUF_WRAP_MANY) ) {
  376. cb->overwrite = value;
  377. }
  378. else {
  379. errno = EINVAL;
  380. rc = -1;
  381. }
  382. }
  383. else {
  384. errno = EINVAL;
  385. rc = -1;
  386. }
  387. assert(cbuf_is_valid(cb));
  388. cbuf_mutex_unlock(cb);
  389. return(rc);
  390. }
  391. int
  392. cbuf_drop (cbuf_t src, int len)
  393. {
  394. assert(src != NULL);
  395. if (len < -1) {
  396. errno = EINVAL;
  397. return(-1);
  398. }
  399. if (len == 0) {
  400. return(0);
  401. }
  402. cbuf_mutex_lock(src);
  403. assert(cbuf_is_valid(src));
  404. if (len == -1) {
  405. len = src->used;
  406. }
  407. else {
  408. len = MIN(len, src->used);
  409. }
  410. if (len > 0) {
  411. cbuf_dropper(src, len);
  412. }
  413. assert(cbuf_is_valid(src));
  414. cbuf_mutex_unlock(src);
  415. return(len);
  416. }
  417. int
  418. cbuf_peek (cbuf_t src, void *dstbuf, int len)
  419. {
  420. int n;
  421. assert(src != NULL);
  422. if ((dstbuf == NULL) || (len < 0)) {
  423. errno = EINVAL;
  424. return(-1);
  425. }
  426. if (len == 0) {
  427. return(0);
  428. }
  429. cbuf_mutex_lock(src);
  430. assert(cbuf_is_valid(src));
  431. n = cbuf_reader(src, len, (cbuf_iof) cbuf_put_mem, &dstbuf);
  432. assert(cbuf_is_valid(src));
  433. cbuf_mutex_unlock(src);
  434. return(n);
  435. }
  436. int
  437. cbuf_read (cbuf_t src, void *dstbuf, int len)
  438. {
  439. int n;
  440. assert(src != NULL);
  441. if ((dstbuf == NULL) || (len < 0)) {
  442. errno = EINVAL;
  443. return(-1);
  444. }
  445. if (len == 0) {
  446. return(0);
  447. }
  448. cbuf_mutex_lock(src);
  449. assert(cbuf_is_valid(src));
  450. n = cbuf_reader(src, len, (cbuf_iof) cbuf_put_mem, &dstbuf);
  451. if (n > 0) {
  452. cbuf_dropper(src, n);
  453. }
  454. assert(cbuf_is_valid(src));
  455. cbuf_mutex_unlock(src);
  456. return(n);
  457. }
  458. int
  459. cbuf_replay (cbuf_t src, void *dstbuf, int len)
  460. {
  461. int n;
  462. assert(src != NULL);
  463. if ((dstbuf == NULL) || (len < 0)) {
  464. errno = EINVAL;
  465. return(-1);
  466. }
  467. if (len == 0) {
  468. return(0);
  469. }
  470. cbuf_mutex_lock(src);
  471. assert(cbuf_is_valid(src));
  472. n = cbuf_replayer(src, len, (cbuf_iof) cbuf_put_mem, &dstbuf);
  473. assert(cbuf_is_valid(src));
  474. cbuf_mutex_unlock(src);
  475. return(n);
  476. }
  477. int
  478. cbuf_rewind (cbuf_t src, int len)
  479. {
  480. int reused;
  481. assert(src != NULL);
  482. if (len < -1) {
  483. errno = EINVAL;
  484. return(-1);
  485. }
  486. if (len == 0) {
  487. return(0);
  488. }
  489. cbuf_mutex_lock(src);
  490. assert(cbuf_is_valid(src));
  491. reused = (src->i_out - src->i_rep + (src->size + 1)) % (src->size + 1);
  492. if (len == -1) {
  493. len = reused;
  494. }
  495. else {
  496. len = MIN(len, reused);
  497. }
  498. if (len > 0) {
  499. src->used += len;
  500. src->i_out = (src->i_out - len + (src->size + 1)) % (src->size + 1);
  501. }
  502. assert(cbuf_is_valid(src));
  503. cbuf_mutex_unlock(src);
  504. return(len);
  505. }
  506. int
  507. cbuf_write (cbuf_t dst, void *srcbuf, int len, int *ndropped)
  508. {
  509. int n;
  510. assert(dst != NULL);
  511. if (ndropped) {
  512. *ndropped = 0;
  513. }
  514. if ((srcbuf == NULL) || (len < 0)) {
  515. errno = EINVAL;
  516. return(-1);
  517. }
  518. if (len == 0) {
  519. return(0);
  520. }
  521. cbuf_mutex_lock(dst);
  522. assert(cbuf_is_valid(dst));
  523. n = cbuf_writer(dst, len, (cbuf_iof) cbuf_get_mem, &srcbuf, ndropped);
  524. assert(cbuf_is_valid(dst));
  525. cbuf_mutex_unlock(dst);
  526. return(n);
  527. }
  528. int
  529. cbuf_drop_line (cbuf_t src, int len, int lines)
  530. {
  531. int n;
  532. assert(src != NULL);
  533. if ((len < 0) || (lines < -1)) {
  534. errno = EINVAL;
  535. return(-1);
  536. }
  537. if (lines == 0) {
  538. return(0);
  539. }
  540. cbuf_mutex_lock(src);
  541. assert(cbuf_is_valid(src));
  542. n = cbuf_find_unread_line(src, len, &lines);
  543. if (n > 0) {
  544. cbuf_dropper(src, n);
  545. }
  546. assert(cbuf_is_valid(src));
  547. cbuf_mutex_unlock(src);
  548. return(n);
  549. }
  550. int
  551. cbuf_peek_line (cbuf_t src, char *dstbuf, int len, int lines)
  552. {
  553. int n, m, l;
  554. char *pdst;
  555. assert(src != NULL);
  556. if ((dstbuf == NULL) || (len < 0) || (lines < -1)) {
  557. errno = EINVAL;
  558. return(-1);
  559. }
  560. if (lines == 0) {
  561. return(0);
  562. }
  563. cbuf_mutex_lock(src);
  564. assert(cbuf_is_valid(src));
  565. n = cbuf_find_unread_line(src, len - 1, &lines);
  566. if (n > 0) {
  567. if (len > 0) {
  568. m = MIN(n, len - 1);
  569. if (m > 0) {
  570. pdst = dstbuf;
  571. l = cbuf_reader(src, m, (cbuf_iof) cbuf_put_mem, &pdst);
  572. assert(l == m);
  573. }
  574. assert(m < len);
  575. dstbuf[m] = '\0';
  576. }
  577. }
  578. assert(cbuf_is_valid(src));
  579. cbuf_mutex_unlock(src);
  580. return(n);
  581. }
  582. int
  583. cbuf_read_line (cbuf_t src, char *dstbuf, int len, int lines)
  584. {
  585. int n, m, l;
  586. char *pdst;
  587. assert(src != NULL);
  588. if ((dstbuf == NULL) || (len < 0) || (lines < -1)) {
  589. errno = EINVAL;
  590. return(-1);
  591. }
  592. if (lines == 0) {
  593. return(0);
  594. }
  595. cbuf_mutex_lock(src);
  596. assert(cbuf_is_valid(src));
  597. n = cbuf_find_unread_line(src, len - 1, &lines);
  598. if (n > 0) {
  599. if (len > 0) {
  600. m = MIN(n, len - 1);
  601. if (m > 0) {
  602. pdst = dstbuf;
  603. l = cbuf_reader(src, m, (cbuf_iof) cbuf_put_mem, &pdst);
  604. assert(l == m);
  605. }
  606. assert(m < len);
  607. dstbuf[m] = '\0';
  608. }
  609. cbuf_dropper(src, n);
  610. }
  611. assert(cbuf_is_valid(src));
  612. cbuf_mutex_unlock(src);
  613. return(n);
  614. }
  615. int
  616. cbuf_replay_line (cbuf_t src, char *dstbuf, int len, int lines)
  617. {
  618. int n, m, l;
  619. int nl;
  620. char *pdst;
  621. assert(src != NULL);
  622. if ((dstbuf == NULL) || (len < 0) || (lines < -1)) {
  623. errno = EINVAL;
  624. return(-1);
  625. }
  626. if (lines == 0) {
  627. return(0);
  628. }
  629. cbuf_mutex_lock(src);
  630. assert(cbuf_is_valid(src));
  631. n = cbuf_find_replay_line(src, len - 1, &lines, &nl);
  632. if (n > 0) {
  633. if (len > 0) {
  634. assert((nl == 0) || (nl == 1));
  635. m = MIN(n, len - 1 - nl);
  636. m = MAX(m, 0);
  637. if (m > 0) {
  638. pdst = dstbuf;
  639. l = cbuf_replayer(src, m, (cbuf_iof) cbuf_put_mem, &pdst);
  640. assert(l == m);
  641. }
  642. /* Append newline if needed and space allows.
  643. */
  644. if ((nl) && (len > 1)) {
  645. dstbuf[m++] = '\n';
  646. }
  647. assert(m < len);
  648. dstbuf[m] = '\0';
  649. n += nl;
  650. }
  651. }
  652. assert(cbuf_is_valid(src));
  653. cbuf_mutex_unlock(src);
  654. return(n);
  655. }
  656. int
  657. cbuf_rewind_line (cbuf_t src, int len, int lines)
  658. {
  659. int n;
  660. assert(src != NULL);
  661. if ((len < 0) || (lines < -1)) {
  662. errno = EINVAL;
  663. return(-1);
  664. }
  665. if (lines == 0) {
  666. return(0);
  667. }
  668. cbuf_mutex_lock(src);
  669. assert(cbuf_is_valid(src));
  670. n = cbuf_find_replay_line(src, len, &lines, NULL);
  671. if (n > 0) {
  672. src->used += n;
  673. src->i_out = (src->i_out - n + (src->size + 1)) % (src->size + 1);
  674. }
  675. assert(cbuf_is_valid(src));
  676. cbuf_mutex_unlock(src);
  677. return(n);
  678. }
  679. int
  680. cbuf_write_line (cbuf_t dst, char *srcbuf, int *ndropped)
  681. {
  682. int len;
  683. int nfree, ncopy, n;
  684. int ndrop = 0, d;
  685. char *psrc = srcbuf;
  686. char *newline = "\n";
  687. assert(dst != NULL);
  688. if (ndropped) {
  689. *ndropped = 0;
  690. }
  691. if (srcbuf == NULL) {
  692. errno = EINVAL;
  693. return(-1);
  694. }
  695. /* Compute number of bytes to effectively copy to dst cbuf.
  696. * Reserve space for the trailing newline if needed.
  697. */
  698. len = ncopy = strlen(srcbuf);
  699. if ((len == 0) || (srcbuf[len - 1] != '\n')) {
  700. len++;
  701. }
  702. cbuf_mutex_lock(dst);
  703. assert(cbuf_is_valid(dst));
  704. /*
  705. * Attempt to grow dst cbuf if necessary.
  706. */
  707. nfree = dst->size - dst->used;
  708. if ((len > nfree) && (dst->size < dst->maxsize)) {
  709. nfree += cbuf_grow(dst, len - nfree);
  710. }
  711. /* Determine if src will fit (or be made to fit) in dst cbuf.
  712. */
  713. if (dst->overwrite == CBUF_NO_DROP) {
  714. if (len > dst->size - dst->used) {
  715. errno = ENOSPC;
  716. len = -1; /* cannot return while mutex locked */
  717. }
  718. }
  719. else if (dst->overwrite == CBUF_WRAP_ONCE) {
  720. if (len > dst->size) {
  721. errno = ENOSPC;
  722. len = -1; /* cannot return while mutex locked */
  723. }
  724. }
  725. if (len > 0) {
  726. /*
  727. * Discard data that won't fit in dst cbuf.
  728. */
  729. if (len > dst->size) {
  730. ndrop += len - dst->size;
  731. ncopy -= ndrop;
  732. psrc += ndrop;
  733. }
  734. /* Copy data from src string to dst cbuf.
  735. */
  736. if (ncopy > 0) {
  737. n = cbuf_writer(dst, ncopy, (cbuf_iof) cbuf_get_mem, &psrc, &d);
  738. assert(n == ncopy);
  739. ndrop += d;
  740. }
  741. /* Append newline if needed.
  742. */
  743. if (srcbuf[len - 1] != '\n') {
  744. n = cbuf_writer(dst, 1, (cbuf_iof) cbuf_get_mem, &newline, &d);
  745. assert(n == 1);
  746. ndrop += d;
  747. }
  748. }
  749. assert(cbuf_is_valid(dst));
  750. cbuf_mutex_unlock(dst);
  751. if (ndropped) {
  752. *ndropped = ndrop;
  753. }
  754. return(len);
  755. }
  756. int
  757. cbuf_peek_to_fd (cbuf_t src, int dstfd, int len)
  758. {
  759. int n = 0;
  760. assert(src != NULL);
  761. if ((dstfd < 0) || (len < -1)) {
  762. errno = EINVAL;
  763. return(-1);
  764. }
  765. cbuf_mutex_lock(src);
  766. assert(cbuf_is_valid(src));
  767. if (len == -1) {
  768. len = src->used;
  769. }
  770. if (len > 0) {
  771. n = cbuf_reader(src, len, (cbuf_iof) cbuf_put_fd, &dstfd);
  772. }
  773. assert(cbuf_is_valid(src));
  774. cbuf_mutex_unlock(src);
  775. return(n);
  776. }
  777. int
  778. cbuf_read_to_fd (cbuf_t src, int dstfd, int len)
  779. {
  780. int n = 0;
  781. assert(src != NULL);
  782. if ((dstfd < 0) || (len < -1)) {
  783. errno = EINVAL;
  784. return(-1);
  785. }
  786. cbuf_mutex_lock(src);
  787. assert(cbuf_is_valid(src));
  788. if (len == -1) {
  789. len = src->used;
  790. }
  791. if (len > 0) {
  792. n = cbuf_reader(src, len, (cbuf_iof) cbuf_put_fd, &dstfd);
  793. if (n > 0) {
  794. cbuf_dropper(src, n);
  795. }
  796. }
  797. assert(cbuf_is_valid(src));
  798. cbuf_mutex_unlock(src);
  799. return(n);
  800. }
  801. int
  802. cbuf_replay_to_fd (cbuf_t src, int dstfd, int len)
  803. {
  804. int n = 0;
  805. assert(src != NULL);
  806. if ((dstfd < 0) || (len < -1)) {
  807. errno = EINVAL;
  808. return(-1);
  809. }
  810. cbuf_mutex_lock(src);
  811. assert(cbuf_is_valid(src));
  812. if (len == -1) {
  813. len = src->size - src->used;
  814. }
  815. if (len > 0) {
  816. n = cbuf_replayer(src, len, (cbuf_iof) cbuf_put_fd, &dstfd);
  817. }
  818. assert(cbuf_is_valid(src));
  819. cbuf_mutex_unlock(src);
  820. return(n);
  821. }
  822. int
  823. cbuf_write_from_fd (cbuf_t dst, int srcfd, int len, int *ndropped)
  824. {
  825. int n = 0;
  826. assert(dst != NULL);
  827. if (ndropped) {
  828. *ndropped = 0;
  829. }
  830. if ((srcfd < 0) || (len < -1)) {
  831. errno = EINVAL;
  832. return(-1);
  833. }
  834. cbuf_mutex_lock(dst);
  835. assert(cbuf_is_valid(dst));
  836. if (len == -1) {
  837. /*
  838. * Try to use all of the free buffer space available for writing.
  839. * If it is all in use, try to grab another chunk and limit the
  840. * amount of data being overwritten.
  841. */
  842. len = dst->size - dst->used;
  843. if (len == 0) {
  844. len = MIN(dst->size, CBUF_CHUNK);
  845. }
  846. }
  847. if (len > 0) {
  848. n = cbuf_writer(dst, len, (cbuf_iof) cbuf_get_fd, &srcfd, ndropped);
  849. }
  850. assert(cbuf_is_valid(dst));
  851. cbuf_mutex_unlock(dst);
  852. return(n);
  853. }
  854. int
  855. cbuf_copy (cbuf_t src, cbuf_t dst, int len, int *ndropped)
  856. {
  857. int n = 0;
  858. assert(src != NULL);
  859. assert(dst != NULL);
  860. if (ndropped) {
  861. *ndropped = 0;
  862. }
  863. if (src == dst) {
  864. errno = EINVAL;
  865. return(-1);
  866. }
  867. if (len < -1) {
  868. errno = EINVAL;
  869. return(-1);
  870. }
  871. if (len == 0) {
  872. return(0);
  873. }
  874. /* Lock cbufs in order of lowest memory address to prevent deadlock.
  875. */
  876. if (src < dst) {
  877. cbuf_mutex_lock(src);
  878. cbuf_mutex_lock(dst);
  879. }
  880. else {
  881. cbuf_mutex_lock(dst);
  882. cbuf_mutex_lock(src);
  883. }
  884. assert(cbuf_is_valid(src));
  885. assert(cbuf_is_valid(dst));
  886. if (len == -1) {
  887. len = src->used;
  888. }
  889. if (len > 0) {
  890. n = cbuf_copier(src, dst, len, ndropped);
  891. }
  892. assert(cbuf_is_valid(src));
  893. assert(cbuf_is_valid(dst));
  894. cbuf_mutex_unlock(src);
  895. cbuf_mutex_unlock(dst);
  896. return(n);
  897. }
  898. int
  899. cbuf_move (cbuf_t src, cbuf_t dst, int len, int *ndropped)
  900. {
  901. int n = 0;
  902. assert(src != NULL);
  903. assert(dst != NULL);
  904. if (ndropped) {
  905. *ndropped = 0;
  906. }
  907. if (src == dst) {
  908. errno = EINVAL;
  909. return(-1);
  910. }
  911. if (len < -1) {
  912. errno = EINVAL;
  913. return(-1);
  914. }
  915. if (len == 0) {
  916. return(0);
  917. }
  918. /* Lock cbufs in order of lowest memory address to prevent deadlock.
  919. */
  920. if (src < dst) {
  921. cbuf_mutex_lock(src);
  922. cbuf_mutex_lock(dst);
  923. }
  924. else {
  925. cbuf_mutex_lock(dst);
  926. cbuf_mutex_lock(src);
  927. }
  928. assert(cbuf_is_valid(src));
  929. assert(cbuf_is_valid(dst));
  930. if (len == -1) {
  931. len = src->used;
  932. }
  933. if (len > 0) {
  934. n = cbuf_copier(src, dst, len, ndropped);
  935. if (n > 0) {
  936. cbuf_dropper(src, n);
  937. }
  938. }
  939. assert(cbuf_is_valid(src));
  940. assert(cbuf_is_valid(dst));
  941. cbuf_mutex_unlock(src);
  942. cbuf_mutex_unlock(dst);
  943. return(n);
  944. }
  945. static int
  946. cbuf_find_replay_line (cbuf_t cb, int chars, int *nlines, int *nl)
  947. {
  948. /* Finds the specified number of lines from the replay region of the buffer.
  949. * If ([nlines] > 0), returns the number of bytes comprising the line count,
  950. * or 0 if this number of lines is not available (ie, all or none).
  951. * If ([nlines] == -1), returns the number of bytes comprising the maximum
  952. * line count bounded by the number of characters specified by [chars].
  953. * Only complete lines (ie, those terminated by a newline) are counted,
  954. * with once exception: the most recent line of replay data is treated
  955. * as a complete line regardless of the presence of a terminating newline.
  956. * Sets the value-result parameter [nlines] to the number of lines found.
  957. * Sets [nl] to '1' if a newline is required to terminate the replay data.
  958. */
  959. int i, n, m, l;
  960. int lines;
  961. assert(cb != NULL);
  962. assert(nlines != NULL);
  963. assert(*nlines >= -1);
  964. assert(cbuf_mutex_is_locked(cb));
  965. n = m = l = 0;
  966. lines = *nlines;
  967. *nlines = 0;
  968. if (nl) {
  969. *nl = 0; /* init in case of early return */
  970. }
  971. if ((lines == 0) || ((lines <= -1) && (chars <= 0))) {
  972. return(0);
  973. }
  974. if (cb->i_out == cb->i_rep) {
  975. return(0); /* no replay data available */
  976. }
  977. if (lines > 0) {
  978. chars = -1; /* chars parm not used if lines > 0 */
  979. }
  980. else {
  981. ++chars; /* incr to allow for preceding '\n' */
  982. }
  983. /* Since the most recent line of replay data is considered implicitly
  984. * terminated, decrement the char count to account for the newline
  985. * if one is not present, or increment the line count if one is.
  986. * Note: cb->data[(O - 1 + (S+1)) % (S+1)] is the last replayable char.
  987. */
  988. if (cb->data[(cb->i_out + cb->size) % (cb->size + 1)] != '\n') {
  989. if (nl) {
  990. *nl = 1;
  991. }
  992. --chars;
  993. }
  994. else {
  995. if (lines > 0) {
  996. ++lines;
  997. }
  998. --l;
  999. }
  1000. i = cb->i_out;
  1001. while (i != cb->i_rep) {
  1002. i = (i + cb->size) % (cb->size + 1); /* (i - 1 + (S+1)) % (S+1) */
  1003. ++n;
  1004. if (chars > 0) {
  1005. --chars;
  1006. }
  1007. /* Complete lines are identified by a preceding newline.
  1008. */
  1009. if (cb->data[i] == '\n') {
  1010. if (lines > 0) {
  1011. --lines;
  1012. }
  1013. m = n - 1; /* do not include preceding '\n' */
  1014. ++l;
  1015. }
  1016. if ((chars == 0) || (lines == 0)) {
  1017. break;
  1018. }
  1019. }
  1020. /* But the first line written in does not need a preceding newline.
  1021. */
  1022. if ((!cb->got_wrap) && ((chars > 0) || (lines > 0))) {
  1023. if (lines > 0) {
  1024. --lines;
  1025. }
  1026. m = n;
  1027. ++l;
  1028. }
  1029. if (lines > 0) {
  1030. return(0); /* all or none, and not enough found */
  1031. }
  1032. *nlines = l;
  1033. return(m);
  1034. }
  1035. static int
  1036. cbuf_find_unread_line (cbuf_t cb, int chars, int *nlines)
  1037. {
  1038. /* Finds the specified number of lines from the unread region of the buffer.
  1039. * If ([nlines] > 0), returns the number of bytes comprising the line count,
  1040. * or 0 if this number of lines is not available (ie, all or none).
  1041. * If ([nlines] == -1), returns the number of bytes comprising the maximum
  1042. * line count bounded by the number of characters specified by [chars].
  1043. * Only complete lines (ie, those terminated by a newline) are counted.
  1044. * Sets the value-result parameter [nlines] to the number of lines found.
  1045. */
  1046. int i, n, m, l;
  1047. int lines;
  1048. assert(cb != NULL);
  1049. assert(nlines != NULL);
  1050. assert(*nlines >= -1);
  1051. assert(cbuf_mutex_is_locked(cb));
  1052. n = m = l = 0;
  1053. lines = *nlines;
  1054. *nlines = 0;
  1055. if ((lines == 0) || ((lines <= -1) && (chars <= 0))) {
  1056. return(0);
  1057. }
  1058. if (cb->used == 0) {
  1059. return(0); /* no unread data available */
  1060. }
  1061. if (lines > 0) {
  1062. chars = -1; /* chars parm not used if lines > 0 */
  1063. }
  1064. i = cb->i_out;
  1065. while (i != cb->i_in) {
  1066. ++n;
  1067. if (chars > 0) {
  1068. --chars;
  1069. }
  1070. if (cb->data[i] == '\n') {
  1071. if (lines > 0) {
  1072. --lines;
  1073. }
  1074. m = n;
  1075. ++l;
  1076. }
  1077. if ((chars == 0) || (lines == 0)) {
  1078. break;
  1079. }
  1080. i = (i + 1) % (cb->size + 1);
  1081. }
  1082. if (lines > 0) {
  1083. return(0); /* all or none, and not enough found */
  1084. }
  1085. *nlines = l;
  1086. return(m);
  1087. }
  1088. static int
  1089. cbuf_get_fd (void *dstbuf, int *psrcfd, int len)
  1090. {
  1091. /* Copies data from the file referenced by the file descriptor
  1092. * pointed at by [psrcfd] into cbuf's [dstbuf].
  1093. * Returns the number of bytes read from the fd, 0 on EOF, or -1 on error.
  1094. */
  1095. int n;
  1096. assert(dstbuf != NULL);
  1097. assert(psrcfd != NULL);
  1098. assert(*psrcfd >= 0);
  1099. assert(len > 0);
  1100. do {
  1101. n = read(*psrcfd, dstbuf, len);
  1102. } while ((n < 0) && (errno == EINTR));
  1103. return(n);
  1104. }
  1105. static int
  1106. cbuf_get_mem (void *dstbuf, unsigned char **psrcbuf, int len)
  1107. {
  1108. /* Copies data from the buffer pointed at by [psrcbuf] into cbuf's [dstbuf].
  1109. * Returns the number of bytes copied.
  1110. */
  1111. assert(dstbuf != NULL);
  1112. assert(psrcbuf != NULL);
  1113. assert(*psrcbuf != NULL);
  1114. assert(len > 0);
  1115. memcpy(dstbuf, *psrcbuf, len);
  1116. *psrcbuf += len;
  1117. return(len);
  1118. }
  1119. static int
  1120. cbuf_put_fd (void *srcbuf, int *pdstfd, int len)
  1121. {
  1122. /* Copies data from cbuf's [srcbuf] into the file referenced
  1123. * by the file descriptor pointed at by [pdstfd].
  1124. * Returns the number of bytes written to the fd, or -1 on error.
  1125. */
  1126. int n;
  1127. assert(srcbuf != NULL);
  1128. assert(pdstfd != NULL);
  1129. assert(*pdstfd >= 0);
  1130. assert(len > 0);
  1131. do {
  1132. n = write(*pdstfd, srcbuf, len);
  1133. } while ((n < 0) && (errno == EINTR));
  1134. return(n);
  1135. }
  1136. static int
  1137. cbuf_put_mem (void *srcbuf, unsigned char **pdstbuf, int len)
  1138. {
  1139. /* Copies data from cbuf's [srcbuf] into the buffer pointed at by [pdstbuf].
  1140. * Returns the number of bytes copied.
  1141. */
  1142. assert(srcbuf != NULL);
  1143. assert(pdstbuf != NULL);
  1144. assert(*pdstbuf != NULL);
  1145. assert(len > 0);
  1146. memcpy(*pdstbuf, srcbuf, len);
  1147. *pdstbuf += len;
  1148. return(len);
  1149. }
  1150. static int
  1151. cbuf_copier (cbuf_t src, cbuf_t dst, int len, int *ndropped)
  1152. {
  1153. /* Copies up to [len] bytes from the [src] cbuf into the [dst] cbuf.
  1154. * Returns the number of bytes copied, or -1 on error (with errno set).
  1155. * Sets [ndropped] (if not NULL) to the number of [dst] bytes overwritten.
  1156. */
  1157. int ncopy, nfree, nleft, nrepl, n;
  1158. int i_src, i_dst;
  1159. assert(src != NULL);
  1160. assert(dst != NULL);
  1161. assert(len > 0);
  1162. assert(cbuf_mutex_is_locked(src));
  1163. assert(cbuf_mutex_is_locked(dst));
  1164. /* Bound len by the number of bytes available.
  1165. */
  1166. len = MIN(len, src->used);
  1167. if (len == 0) {
  1168. return(0);
  1169. }
  1170. /* Attempt to grow dst cbuf if necessary.
  1171. */
  1172. nfree = dst->size - dst->used;
  1173. if ((len > nfree) && (dst->size < dst->maxsize)) {
  1174. nfree += cbuf_grow(dst, len - nfree);
  1175. }
  1176. /* Compute number of bytes to effectively copy to dst cbuf.
  1177. */
  1178. if (dst->overwrite == CBUF_NO_DROP) {
  1179. len = MIN(len, dst->size - dst->used);
  1180. if (len == 0) {
  1181. errno = ENOSPC;
  1182. return(-1);
  1183. }
  1184. }
  1185. else if (dst->overwrite == CBUF_WRAP_ONCE) {
  1186. len = MIN(len, dst->size);
  1187. }
  1188. /* Compute number of bytes that will be overwritten in dst cbuf.
  1189. */
  1190. if (ndropped) {
  1191. *ndropped = MAX(0, len - dst->size + dst->used);
  1192. }
  1193. /* Compute number of bytes to physically copy to dst cbuf. This prevents
  1194. * copying data that will overwritten if the cbuf wraps multiple times.
  1195. */
  1196. ncopy = len;
  1197. i_src = src->i_out;
  1198. i_dst = dst->i_in;
  1199. if (ncopy > dst->size) {
  1200. n = ncopy - dst->size;
  1201. i_src = (i_src + n) % (src->size + 1);
  1202. ncopy -= n;
  1203. }
  1204. /* Copy data from src cbuf to dst cbuf.
  1205. */
  1206. nleft = ncopy;
  1207. while (nleft > 0) {
  1208. n = MIN(((src->size + 1) - i_src), ((dst->size + 1) - i_dst));
  1209. n = MIN(n, nleft);
  1210. memcpy(&dst->data[i_dst], &src->data[i_src], n);
  1211. i_src = (i_src + n) % (src->size + 1);
  1212. i_dst = (i_dst + n) % (dst->size + 1);
  1213. nleft -= n;
  1214. }
  1215. /* Update dst cbuf metadata.
  1216. */
  1217. if (ncopy > 0) {
  1218. nrepl = (dst->i_out - dst->i_rep + (dst->size + 1)) % (dst->size + 1);
  1219. dst->used = MIN(dst->used + ncopy, dst->size);
  1220. assert(i_dst == (dst->i_in + ncopy) % (dst->size + 1));
  1221. dst->i_in = i_dst;
  1222. if (ncopy > nfree - nrepl) {
  1223. dst->got_wrap = 1;
  1224. dst->i_rep = (dst->i_in + 1) % (dst->size + 1);
  1225. }
  1226. if (ncopy > nfree) {
  1227. dst->i_out = dst->i_rep;
  1228. }
  1229. }
  1230. return(len);
  1231. }
  1232. static int
  1233. cbuf_dropper (cbuf_t cb, int len)
  1234. {
  1235. /* Discards exactly [len] bytes of unread data from [cb].
  1236. * Returns the number of bytes dropped.
  1237. */
  1238. assert(cb != NULL);
  1239. assert(len > 0);
  1240. assert(len <= cb->used);
  1241. assert(cbuf_mutex_is_locked(cb));
  1242. cb->used -= len;
  1243. cb->i_out = (cb->i_out + len) % (cb->size + 1);
  1244. /* Attempt to shrink cbuf if possible.
  1245. */
  1246. if ((cb->size - cb->used > CBUF_CHUNK) && (cb->size > cb->minsize)) {
  1247. cbuf_shrink(cb);
  1248. }
  1249. /* Don't call me clumsy, don't call me a fool.
  1250. * When things fall down on me, I'm following the rule.
  1251. */
  1252. return(len);
  1253. }
  1254. static int
  1255. cbuf_reader (cbuf_t src, int len, cbuf_iof putf, void *dst)
  1256. {
  1257. /* Reads up to [len] bytes from [src] into the object pointed at by [dst].
  1258. * The I/O function [putf] specifies how data is written into [dst].
  1259. * Returns the number of bytes read, or -1 on error (with errno set).
  1260. * Note that [dst] is a value-result parameter and will be "moved forward"
  1261. * by the number of bytes written into it.
  1262. */
  1263. int nleft, n, m;
  1264. int i_src;
  1265. assert(src != NULL);
  1266. assert(len > 0);
  1267. assert(putf != NULL);
  1268. assert(dst != NULL);
  1269. assert(cbuf_mutex_is_locked(src));
  1270. /* Bound len by the number of bytes available.
  1271. */
  1272. len = MIN(len, src->used);
  1273. if (len == 0) {
  1274. return(0);
  1275. }
  1276. /* Copy data from src cbuf to dst obj. Do the cbuf hokey-pokey and
  1277. * wrap-around the buffer at most once. Break out if putf() returns
  1278. * either an ERR or a short count.
  1279. */
  1280. i_src = src->i_out;
  1281. nleft = len;
  1282. m = 0;
  1283. while (nleft > 0) {
  1284. n = MIN(nleft, (src->size + 1) - i_src);
  1285. m = putf(&src->data[i_src], dst, n);
  1286. if (m > 0) {
  1287. nleft -= m;
  1288. i_src = (i_src + m) % (src->size + 1);
  1289. }
  1290. if (n != m) {
  1291. break; /* got ERR or "short" putf() */
  1292. }
  1293. }
  1294. /* Compute number of bytes written to dst obj.
  1295. */
  1296. n = len - nleft;
  1297. assert((n >= 0) && (n <= len));
  1298. /*
  1299. * If no data has been written, return the ERR reported by putf().
  1300. */
  1301. if (n == 0) {
  1302. return(m);
  1303. }
  1304. return(n);
  1305. }
  1306. static int
  1307. cbuf_replayer (cbuf_t src, int len, cbuf_iof putf, void *dst)
  1308. {
  1309. /* Replays up to [len] bytes from [src] into the object pointed at by [dst].
  1310. * The I/O function [putf] specifies how data is written into [dst].
  1311. * Returns the number of bytes replayed, or -1 on error (with errno set).
  1312. * Note that [dst] is a value-result parameter and will be "moved forward"
  1313. * by the number of bytes written into it.
  1314. */
  1315. int nleft, n, m;
  1316. int i_src;
  1317. assert(src != NULL);
  1318. assert(len > 0);
  1319. assert(putf != NULL);
  1320. assert(dst != NULL);
  1321. assert(cbuf_mutex_is_locked(src));
  1322. /* Bound len by the number of bytes available.
  1323. */
  1324. n = (src->i_out - src->i_rep + (src->size + 1)) % (src->size + 1);
  1325. len = MIN(len, n);
  1326. if (len == 0) {
  1327. return(0);
  1328. }
  1329. /* Copy data from src cbuf to dst obj. Do the cbuf hokey-pokey and
  1330. * wrap-around the buffer at most once. Break out if putf() returns
  1331. * either an ERR or a short count.
  1332. */
  1333. i_src = (src->i_out - len + (src->size + 1)) % (src->size + 1);
  1334. nleft = len;
  1335. m = 0;
  1336. while (nleft > 0) {
  1337. n = MIN(nleft, (src->size + 1) - i_src);
  1338. m = putf(&src->data[i_src], dst, n);
  1339. if (m > 0) {
  1340. nleft -= m;
  1341. i_src = (i_src + m) % (src->size + 1);
  1342. }
  1343. if (n != m) {
  1344. break; /* got ERR or "short" putf() */
  1345. }
  1346. }
  1347. /* Compute number of bytes written to dst obj.
  1348. */
  1349. n = len - nleft;
  1350. assert((n >= 0) && (n <= len));
  1351. /*
  1352. * If no data has been written, return the ERR reported by putf().
  1353. */
  1354. if (n == 0) {
  1355. return(m);
  1356. }
  1357. return(n);
  1358. }
  1359. static int
  1360. cbuf_writer (cbuf_t dst, int len, cbuf_iof getf, void *src, int *ndropped)
  1361. {
  1362. /* Writes up to [len] bytes from the object pointed at by [src] into [dst].
  1363. * The I/O function [getf] specifies how data is read from [src].
  1364. * Returns the number of bytes written, or -1 on error (with errno set).
  1365. * Sets [ndropped] (if not NULL) to the number of [dst] bytes overwritten.
  1366. * Note that [src] is a value-result parameter and will be "moved forward"
  1367. * by the number of bytes read from it.
  1368. */
  1369. int nfree, nleft, nrepl, n, m;
  1370. int i_dst;
  1371. assert(dst != NULL);
  1372. assert(len > 0);
  1373. assert(getf != NULL);
  1374. assert(src != NULL);
  1375. assert(cbuf_mutex_is_locked(dst));
  1376. /* Attempt to grow dst cbuf if necessary.
  1377. */
  1378. nfree = dst->size - dst->used;
  1379. if ((len > nfree) && (dst->size < dst->maxsize)) {
  1380. nfree += cbuf_grow(dst, len - nfree);
  1381. }
  1382. /* Compute number of bytes to write to dst cbuf.
  1383. */
  1384. if (dst->overwrite == CBUF_NO_DROP) {
  1385. len = MIN(len, dst->size - dst->used);
  1386. if (len == 0) {
  1387. errno = ENOSPC;
  1388. return(-1);
  1389. }
  1390. }
  1391. else if (dst->overwrite == CBUF_WRAP_ONCE) {
  1392. len = MIN(len, dst->size);
  1393. }
  1394. /* Copy data from src obj to dst cbuf. Do the cbuf hokey-pokey and
  1395. * wrap-around the buffer as needed. Break out if getf() returns
  1396. * either an EOF/ERR or a short count.
  1397. */
  1398. i_dst = dst->i_in;
  1399. nleft = len;
  1400. m = 0;
  1401. while (nleft > 0) {
  1402. n = MIN(nleft, (dst->size + 1) - i_dst);
  1403. m = getf(&dst->data[i_dst], src, n);
  1404. if (m > 0) {
  1405. nleft -= m;
  1406. i_dst = (i_dst + m) % (dst->size + 1);
  1407. }
  1408. if (n != m) {
  1409. break; /* got EOF/ERR or "short" getf() */
  1410. }
  1411. }
  1412. /* Compute number of bytes written to dst cbuf.
  1413. */
  1414. n = len - nleft;
  1415. assert((n >= 0) && (n <= len));
  1416. /*
  1417. * If no data has been written, return the EOF/ERR reported by getf().
  1418. */
  1419. if (n == 0) {
  1420. return(m);
  1421. }
  1422. /* Update dst cbuf metadata.
  1423. */
  1424. if (n > 0) {
  1425. nrepl = (dst->i_out - dst->i_rep + (dst->size + 1)) % (dst->size + 1);
  1426. dst->used = MIN(dst->used + n, dst->size);
  1427. assert(i_dst == (dst->i_in + n) % (dst->size + 1));
  1428. dst->i_in = i_dst;
  1429. if (n > nfree - nrepl) {
  1430. dst->got_wrap = 1;
  1431. dst->i_rep = (dst->i_in + 1) % (dst->size + 1);
  1432. }
  1433. if (n > nfree) {
  1434. dst->i_out = dst->i_rep;
  1435. }
  1436. }
  1437. if (ndropped) {
  1438. *ndropped = MAX(0, n - nfree);
  1439. }
  1440. return(n);
  1441. }
  1442. static int
  1443. cbuf_grow (cbuf_t cb, int n)
  1444. {
  1445. /* Attempts to grow the circular buffer [cb] by at least [n] bytes.
  1446. * Returns the number of bytes by which the buffer has grown (which may be
  1447. * less-than, equal-to, or greater-than the number of bytes requested).
  1448. */
  1449. unsigned char *data;
  1450. int size_old, size_meta;
  1451. int m;
  1452. assert(cb != NULL);
  1453. assert(n > 0);
  1454. assert(cbuf_mutex_is_locked(cb));
  1455. if (cb->size == cb->maxsize) {
  1456. return(0);
  1457. }
  1458. size_old = cb->size;
  1459. size_meta = cb->alloc - cb->size; /* size of sentinel & magic cookies */
  1460. assert(size_meta > 0);
  1461. /* Attempt to grow data buffer by multiples of the chunk-size.
  1462. */
  1463. m = cb->alloc + n;
  1464. m = m + (CBUF_CHUNK - (m % CBUF_CHUNK));
  1465. m = MIN(m, (cb->maxsize + size_meta));
  1466. assert(m > cb->alloc);
  1467. data = cb->data;
  1468. #ifndef NDEBUG
  1469. data -= CBUF_MAGIC_LEN; /* jump back to what malloc returned */
  1470. #endif /* !NDEBUG */
  1471. if (!(data = realloc(data, m))) {
  1472. /*
  1473. * XXX: Set flag or somesuch to prevent regrowing when out of memory?
  1474. */
  1475. return(0); /* unable to grow data buffer */
  1476. }
  1477. cb->data = data;
  1478. cb->alloc = m;
  1479. cb->size = m - size_meta;
  1480. #ifndef NDEBUG
  1481. /* A round cookie with one bite out of it looks like a C.
  1482. * The underflow cookie will have been copied by realloc() if needed.
  1483. * But the overflow cookie must be rebaked.
  1484. * Must use memcpy since overflow cookie may not be word-aligned.
  1485. */
  1486. cb->data += CBUF_MAGIC_LEN; /* jump forward past underflow magic */
  1487. memcpy(cb->data + cb->size + 1, (void *) &cb->magic, CBUF_MAGIC_LEN);
  1488. #endif /* !NDEBUG */
  1489. /* The memory containing replay and unread data must be contiguous modulo
  1490. * the buffer size. Additional memory must be inserted between where
  1491. * new data is written in (i_in) and where replay data starts (i_rep).
  1492. * If replay data wraps-around the old buffer, move it to the new end
  1493. * of the buffer so it wraps-around in the same manner.
  1494. */
  1495. if (cb->i_rep > cb->i_in) {
  1496. n = (size_old + 1) - cb->i_rep;
  1497. m = (cb->size + 1) - n;
  1498. memmove(cb->data + m, cb->data + cb->i_rep, n);
  1499. if (cb->i_out >= cb->i_rep) {
  1500. cb->i_out += m - cb->i_rep;
  1501. }
  1502. cb->i_rep = m;
  1503. }
  1504. assert(cbuf_is_valid(cb));
  1505. return(cb->size - size_old);
  1506. }
  1507. static int
  1508. cbuf_shrink (cbuf_t cb)
  1509. {
  1510. /* XXX: DOCUMENT ME.
  1511. */
  1512. assert(cb != NULL);
  1513. assert(cbuf_mutex_is_locked(cb));
  1514. assert(cbuf_is_valid(cb));
  1515. if (cb->size == cb->minsize) {
  1516. return(0);
  1517. }
  1518. if (cb->size - cb->used <= CBUF_CHUNK) {
  1519. return(0);
  1520. }
  1521. /* FIXME: NOT IMPLEMENTED.
  1522. */
  1523. assert(cbuf_is_valid(cb));
  1524. return(0);
  1525. }
  1526. #ifndef NDEBUG
  1527. #ifdef WITH_PTHREADS
  1528. static int
  1529. cbuf_mutex_is_locked (cbuf_t cb)
  1530. {
  1531. /* Returns true if the mutex is locked; o/w, returns false.
  1532. */
  1533. int rc;
  1534. assert(cb != NULL);
  1535. rc = pthread_mutex_trylock(&cb->mutex);
  1536. return(rc == EBUSY ? 1 : 0);
  1537. }
  1538. #endif /* WITH_PTHREADS */
  1539. #endif /* !NDEBUG */
  1540. #ifndef NDEBUG
  1541. static int
  1542. cbuf_is_valid (cbuf_t cb)
  1543. {
  1544. /* Validates the data structure. All invariants should be tested here.
  1545. * Returns true if everything is valid; o/w, aborts due to assertion failure.
  1546. */
  1547. int nfree;
  1548. assert(cb != NULL);
  1549. assert(cbuf_mutex_is_locked(cb));
  1550. assert(cb->data != NULL);
  1551. assert(cb->magic == CBUF_MAGIC);
  1552. /*
  1553. * Must use memcmp since overflow cookie may not be word-aligned.
  1554. */
  1555. assert(memcmp(cb->data - CBUF_MAGIC_LEN,
  1556. (void *) &cb->magic, CBUF_MAGIC_LEN) == 0);
  1557. assert(memcmp(cb->data + cb->size + 1,
  1558. (void *) &cb->magic, CBUF_MAGIC_LEN) == 0);
  1559. assert(cb->alloc > 0);
  1560. assert(cb->alloc > cb->size);
  1561. assert(cb->size > 0);
  1562. assert(cb->size >= cb->minsize);
  1563. assert(cb->size <= cb->maxsize);
  1564. assert(cb->minsize > 0);
  1565. assert(cb->maxsize > 0);
  1566. assert(cb->used >= 0);
  1567. assert(cb->used <= cb->size);
  1568. assert(cb->overwrite == CBUF_NO_DROP
  1569. || cb->overwrite == CBUF_WRAP_ONCE
  1570. || cb->overwrite == CBUF_WRAP_MANY);
  1571. assert(cb->got_wrap || !cb->i_rep); /* i_rep = 0 if data has not wrapped */
  1572. assert(cb->i_in >= 0);
  1573. assert(cb->i_in <= cb->size);
  1574. assert(cb->i_out >= 0);
  1575. assert(cb->i_out <= cb->size);
  1576. assert(cb->i_rep >= 0);
  1577. assert(cb->i_rep <= cb->size);
  1578. if (cb->i_in >= cb->i_out) {
  1579. assert((cb->i_rep > cb->i_in) || (cb->i_rep <= cb->i_out));
  1580. }
  1581. else /* if (cb->in < cb->i_out) */ {
  1582. assert((cb->i_rep > cb->i_in) && (cb->i_rep <= cb->i_out));
  1583. }
  1584. nfree = (cb->i_out - cb->i_in - 1 + (cb->size + 1)) % (cb->size + 1);
  1585. assert(cb->size - cb->used == nfree);
  1586. return(1);
  1587. }
  1588. #endif /* !NDEBUG */