1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <pthread.h>
27 #include <malloc.h>
28 #include <memory.h>
29 #include "dataq.h"
30 #include <assert.h>
31
32 #ifndef NDEBUG
33 static int
dataq_check(dataq_t * ptr)34 dataq_check(dataq_t *ptr) /* call while holding lock! */
35 {
36 assert(ptr->num_data == ll_check(&ptr->data));
37 assert(ptr->num_waiters == ll_check(&ptr->waiters));
38 return (1);
39 }
40 #endif
41
42 int
dataq_init(dataq_t * ptr)43 dataq_init(dataq_t *ptr)
44 {
45 ptr->num_data = 0;
46 ptr->num_waiters = 0;
47 ll_init(&ptr->data);
48 ll_init(&ptr->waiters);
49 (void) pthread_mutex_init(&ptr->lock, NULL);
50 assert((pthread_mutex_lock(&ptr->lock) == 0) &&
51 (dataq_check(ptr) == 1) &&
52 (pthread_mutex_unlock(&ptr->lock) == 0));
53 return (0);
54 }
55
56 int
dataq_enqueue(dataq_t * dataq,void * in)57 dataq_enqueue(dataq_t *dataq, void *in)
58 {
59 dataq_data_t *ptr = (dataq_data_t *)malloc(sizeof (*ptr));
60 dataq_waiter_t *sleeper;
61
62 if (ptr == NULL)
63 return (-1);
64 ptr->data = in;
65 (void) pthread_mutex_lock(&dataq->lock);
66 assert(dataq_check(dataq));
67 ll_enqueue(&dataq->data, &ptr->list);
68 dataq->num_data++;
69 if (dataq->num_waiters) {
70 /*LINTED*/
71 sleeper = (dataq_waiter_t *)ll_peek(&dataq->waiters);
72 sleeper->wakeup = 1;
73 (void) pthread_cond_signal(&sleeper->cv);
74 }
75 assert(dataq_check(dataq));
76 (void) pthread_mutex_unlock(&dataq->lock);
77 return (0);
78 }
79
80 int
dataq_dequeue(dataq_t * dataq,void ** outptr,int try)81 dataq_dequeue(dataq_t *dataq, void **outptr, int try)
82 {
83 dataq_data_t *dptr;
84 dataq_waiter_t *sleeper;
85
86 (void) pthread_mutex_lock(&dataq->lock);
87 if ((dataq->num_waiters > 0) ||
88 ((dptr = (dataq_data_t *)ll_dequeue(&dataq->data)) == NULL)) {
89 dataq_waiter_t wait;
90 if (try) {
91 (void) pthread_mutex_unlock(&dataq->lock);
92 return (1);
93 }
94 wait.wakeup = 0;
95 (void) pthread_cond_init(&wait.cv, NULL);
96 dataq->num_waiters++;
97 ll_enqueue(&dataq->waiters, &wait.list);
98 while (wait.wakeup == 0)
99 (void) pthread_cond_wait(&wait.cv, &dataq->lock);
100 (void) ll_dequeue(&dataq->waiters);
101 dataq->num_waiters--;
102 (void) pthread_cond_destroy(&wait.cv);
103 dptr = (dataq_data_t *)ll_dequeue(&dataq->data);
104 }
105 dataq->num_data--;
106 if (dataq->num_data && dataq->num_waiters) {
107 /*LINTED*/
108 sleeper = (dataq_waiter_t *)ll_peek(&dataq->waiters);
109 sleeper->wakeup = 1;
110 (void) pthread_cond_signal(&sleeper->cv);
111 }
112 (void) pthread_mutex_unlock(&dataq->lock);
113 *outptr = dptr->data;
114 free(dptr);
115 return (0);
116 }
117
118 static void
dataq_data_destroy(void * p)119 dataq_data_destroy(void * p)
120 {
121 dataq_data_t *d = (dataq_data_t *)p;
122 free(d->data);
123 free(d);
124 }
125
126 static void
dataq_waiters_destroy(void * p)127 dataq_waiters_destroy(void * p)
128 {
129 dataq_waiter_t *d = (dataq_waiter_t *)p;
130 (void) pthread_cond_destroy(&d->cv);
131 free(d);
132 }
133
134 int
dataq_destroy(dataq_t * dataq)135 dataq_destroy(dataq_t *dataq)
136 {
137 (void) pthread_mutex_destroy(&dataq->lock);
138 ll_mapf(&dataq->data, dataq_data_destroy);
139 ll_mapf(&dataq->waiters, dataq_waiters_destroy);
140 return (0);
141 }
142