/usr.bin/csup/fixups.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 198 lines · 129 code · 24 blank · 45 comment · 19 complexity · 8d12971d744d43ee1f101ce780852330 MD5 · raw file

  1. /*-
  2. * Copyright (c) 2006, Maxime Henrion <mux@FreeBSD.org>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  15. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  18. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  20. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  21. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  22. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  23. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  24. * SUCH DAMAGE.
  25. *
  26. * $FreeBSD$
  27. */
  28. #include <assert.h>
  29. #include <pthread.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include "fixups.h"
  33. #include "misc.h"
  34. #include "queue.h"
  35. /*
  36. * A synchronized queue to implement fixups. The updater thread adds
  37. * fixup requests to the queue with fixups_put() when a checksum
  38. * mismatch error occurred. It then calls fixups_close() when he's
  39. * done requesting fixups. The detailer thread gets the fixups with
  40. * fixups_get() and then send the requests to the server.
  41. *
  42. * The queue is synchronized with a mutex and a condition variable.
  43. */
  44. struct fixups {
  45. pthread_mutex_t lock;
  46. pthread_cond_t cond;
  47. STAILQ_HEAD(, fixup) fixupq;
  48. struct fixup *cur;
  49. size_t size;
  50. int closed;
  51. };
  52. static void fixups_lock(struct fixups *);
  53. static void fixups_unlock(struct fixups *);
  54. static struct fixup *fixup_new(struct coll *, const char *);
  55. static void fixup_free(struct fixup *);
  56. static void
  57. fixups_lock(struct fixups *f)
  58. {
  59. int error;
  60. error = pthread_mutex_lock(&f->lock);
  61. assert(!error);
  62. }
  63. static void
  64. fixups_unlock(struct fixups *f)
  65. {
  66. int error;
  67. error = pthread_mutex_unlock(&f->lock);
  68. assert(!error);
  69. }
  70. static struct fixup *
  71. fixup_new(struct coll *coll, const char *name)
  72. {
  73. struct fixup *fixup;
  74. fixup = xmalloc(sizeof(struct fixup));
  75. fixup->f_name = xstrdup(name);
  76. fixup->f_coll = coll;
  77. return (fixup);
  78. }
  79. static void
  80. fixup_free(struct fixup *fixup)
  81. {
  82. free(fixup->f_name);
  83. free(fixup);
  84. }
  85. /* Create a new fixup queue. */
  86. struct fixups *
  87. fixups_new(void)
  88. {
  89. struct fixups *f;
  90. f = xmalloc(sizeof(struct fixups));
  91. f->size = 0;
  92. f->closed = 0;
  93. f->cur = NULL;
  94. STAILQ_INIT(&f->fixupq);
  95. pthread_mutex_init(&f->lock, NULL);
  96. pthread_cond_init(&f->cond, NULL);
  97. return (f);
  98. }
  99. /* Add a fixup request to the queue. */
  100. void
  101. fixups_put(struct fixups *f, struct coll *coll, const char *name)
  102. {
  103. struct fixup *fixup;
  104. int dosignal;
  105. dosignal = 0;
  106. fixup = fixup_new(coll, name);
  107. fixups_lock(f);
  108. assert(!f->closed);
  109. STAILQ_INSERT_TAIL(&f->fixupq, fixup, f_link);
  110. if (f->size++ == 0)
  111. dosignal = 1;
  112. fixups_unlock(f);
  113. if (dosignal)
  114. pthread_cond_signal(&f->cond);
  115. }
  116. /* Get a fixup request from the queue. */
  117. struct fixup *
  118. fixups_get(struct fixups *f)
  119. {
  120. struct fixup *fixup, *tofree;
  121. fixups_lock(f);
  122. while (f->size == 0 && !f->closed)
  123. pthread_cond_wait(&f->cond, &f->lock);
  124. if (f->closed && f->size == 0) {
  125. fixups_unlock(f);
  126. return (NULL);
  127. }
  128. assert(f->size > 0);
  129. fixup = STAILQ_FIRST(&f->fixupq);
  130. tofree = f->cur;
  131. f->cur = fixup;
  132. STAILQ_REMOVE_HEAD(&f->fixupq, f_link);
  133. f->size--;
  134. fixups_unlock(f);
  135. if (tofree != NULL)
  136. fixup_free(tofree);
  137. return (fixup);
  138. }
  139. /* Close the writing end of the queue. */
  140. void
  141. fixups_close(struct fixups *f)
  142. {
  143. int dosignal;
  144. dosignal = 0;
  145. fixups_lock(f);
  146. if (f->size == 0 && !f->closed)
  147. dosignal = 1;
  148. f->closed = 1;
  149. fixups_unlock(f);
  150. if (dosignal)
  151. pthread_cond_signal(&f->cond);
  152. }
  153. /* Free a fixups queue. */
  154. void
  155. fixups_free(struct fixups *f)
  156. {
  157. struct fixup *fixup, *fixup2;
  158. assert(f->closed);
  159. /*
  160. * Free any fixup that has been left on the queue.
  161. * This can happen if we have been aborted prematurely.
  162. */
  163. fixup = STAILQ_FIRST(&f->fixupq);
  164. while (fixup != NULL) {
  165. fixup2 = STAILQ_NEXT(fixup, f_link);
  166. fixup_free(fixup);
  167. fixup = fixup2;
  168. }
  169. if (f->cur != NULL)
  170. fixup_free(f->cur);
  171. pthread_cond_destroy(&f->cond);
  172. pthread_mutex_destroy(&f->lock);
  173. free(f);
  174. }