thread_cond.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /* Licensed to the Apache Software Foundation (ASF) under one or more
  2. * contributor license agreements. See the NOTICE file distributed with
  3. * this work for additional information regarding copyright ownership.
  4. * The ASF licenses this file to You under the Apache License, Version 2.0
  5. * (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "apr_arch_thread_mutex.h"
  17. #include "apr_arch_thread_cond.h"
  18. #include "apr_strings.h"
  19. #include "apr_portable.h"
  20. static apr_status_t thread_cond_cleanup(void *data)
  21. {
  22. struct waiter *w;
  23. apr_thread_cond_t *cond = (apr_thread_cond_t *)data;
  24. acquire_sem(cond->lock);
  25. delete_sem(cond->lock);
  26. return APR_SUCCESS;
  27. }
  28. static struct waiter_t *make_waiter(apr_pool_t *pool)
  29. {
  30. struct waiter_t *w = (struct waiter_t*)
  31. apr_palloc(pool, sizeof(struct waiter_t));
  32. if (w == NULL)
  33. return NULL;
  34. w->sem = create_sem(0, "apr conditional waiter");
  35. if (w->sem < 0)
  36. return NULL;
  37. APR_RING_ELEM_INIT(w, link);
  38. return w;
  39. }
  40. APR_DECLARE(apr_status_t) apr_thread_cond_create(apr_thread_cond_t **cond,
  41. apr_pool_t *pool)
  42. {
  43. apr_thread_cond_t *new_cond;
  44. sem_id rv;
  45. int i;
  46. new_cond = (apr_thread_cond_t *)apr_palloc(pool, sizeof(apr_thread_cond_t));
  47. if (new_cond == NULL)
  48. return APR_ENOMEM;
  49. if ((rv = create_sem(1, "apr conditional lock")) < B_OK)
  50. return rv;
  51. new_cond->lock = rv;
  52. new_cond->pool = pool;
  53. APR_RING_INIT(&new_cond->alist, waiter_t, link);
  54. APR_RING_INIT(&new_cond->flist, waiter_t, link);
  55. for (i=0;i < 10 ;i++) {
  56. struct waiter_t *nw = make_waiter(pool);
  57. APR_RING_INSERT_TAIL(&new_cond->flist, nw, waiter_t, link);
  58. }
  59. apr_pool_cleanup_register(new_cond->pool,
  60. (void *)new_cond, thread_cond_cleanup,
  61. apr_pool_cleanup_null);
  62. *cond = new_cond;
  63. return APR_SUCCESS;
  64. }
  65. static apr_status_t do_wait(apr_thread_cond_t *cond, apr_thread_mutex_t *mutex,
  66. int timeout)
  67. {
  68. struct waiter_t *wait;
  69. thread_id cth = find_thread(NULL);
  70. apr_status_t rv;
  71. int flags = B_RELATIVE_TIMEOUT;
  72. /* We must be the owner of the mutex or we can't do this... */
  73. if (mutex->owner != cth) {
  74. /* What should we return??? */
  75. return APR_EINVAL;
  76. }
  77. acquire_sem(cond->lock);
  78. wait = APR_RING_FIRST(&cond->flist);
  79. if (wait)
  80. APR_RING_REMOVE(wait, link);
  81. else
  82. wait = make_waiter(cond->pool);
  83. APR_RING_INSERT_TAIL(&cond->alist, wait, waiter_t, link);
  84. cond->condlock = mutex;
  85. release_sem(cond->lock);
  86. apr_thread_mutex_unlock(cond->condlock);
  87. if (timeout == 0)
  88. flags = 0;
  89. rv = acquire_sem_etc(wait->sem, 1, flags, timeout);
  90. apr_thread_mutex_lock(cond->condlock);
  91. if (rv != B_OK)
  92. if (rv == B_TIMED_OUT)
  93. return APR_TIMEUP;
  94. return rv;
  95. acquire_sem(cond->lock);
  96. APR_RING_REMOVE(wait, link);
  97. APR_RING_INSERT_TAIL(&cond->flist, wait, waiter_t, link);
  98. release_sem(cond->lock);
  99. return APR_SUCCESS;
  100. }
  101. APR_DECLARE(apr_status_t) apr_thread_cond_wait(apr_thread_cond_t *cond,
  102. apr_thread_mutex_t *mutex)
  103. {
  104. return do_wait(cond, mutex, 0);
  105. }
  106. APR_DECLARE(apr_status_t) apr_thread_cond_timedwait(apr_thread_cond_t *cond,
  107. apr_thread_mutex_t *mutex,
  108. apr_interval_time_t timeout)
  109. {
  110. return do_wait(cond, mutex, timeout);
  111. }
  112. APR_DECLARE(apr_status_t) apr_thread_cond_signal(apr_thread_cond_t *cond)
  113. {
  114. struct waiter_t *wake;
  115. acquire_sem(cond->lock);
  116. if (!APR_RING_EMPTY(&cond->alist, waiter_t, link)) {
  117. wake = APR_RING_FIRST(&cond->alist);
  118. APR_RING_REMOVE(wake, link);
  119. release_sem(wake->sem);
  120. APR_RING_INSERT_TAIL(&cond->flist, wake, waiter_t, link);
  121. }
  122. release_sem(cond->lock);
  123. return APR_SUCCESS;
  124. }
  125. APR_DECLARE(apr_status_t) apr_thread_cond_broadcast(apr_thread_cond_t *cond)
  126. {
  127. struct waiter_t *wake;
  128. acquire_sem(cond->lock);
  129. while (! APR_RING_EMPTY(&cond->alist, waiter_t, link)) {
  130. wake = APR_RING_FIRST(&cond->alist);
  131. APR_RING_REMOVE(wake, link);
  132. release_sem(wake->sem);
  133. APR_RING_INSERT_TAIL(&cond->flist, wake, waiter_t, link);
  134. }
  135. release_sem(cond->lock);
  136. return APR_SUCCESS;
  137. }
  138. APR_DECLARE(apr_status_t) apr_thread_cond_destroy(apr_thread_cond_t *cond)
  139. {
  140. apr_status_t stat;
  141. if ((stat = thread_cond_cleanup(cond)) == APR_SUCCESS) {
  142. apr_pool_cleanup_kill(cond->pool, cond, thread_cond_cleanup);
  143. return APR_SUCCESS;
  144. }
  145. return stat;
  146. }
  147. APR_POOL_IMPLEMENT_ACCESSOR(thread_cond)