1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2015 Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * Some portions of this software may have been derived from the 36 * https://github.com/halayli/lthread which carrys the following license. 37 * 38 * Copyright (C) 2012, Hasan Alayli <[email protected]> 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 49 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 */ 61 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <string.h> 65 #include <stdint.h> 66 #include <stddef.h> 67 #include <limits.h> 68 #include <inttypes.h> 69 #include <unistd.h> 70 #include <pthread.h> 71 #include <fcntl.h> 72 #include <sys/time.h> 73 #include <sys/mman.h> 74 #include <errno.h> 75 76 #include <rte_log.h> 77 #include <rte_common.h> 78 79 #include "lthread_api.h" 80 #include "lthread_diag_api.h" 81 #include "lthread_diag.h" 82 #include "lthread_int.h" 83 #include "lthread_sched.h" 84 #include "lthread_queue.h" 85 #include "lthread_objcache.h" 86 #include "lthread_timer.h" 87 #include "lthread_mutex.h" 88 #include "lthread_cond.h" 89 90 /* 91 * Create a condition variable 92 */ 93 int 94 lthread_cond_init(char *name, struct lthread_cond **cond, 95 __rte_unused const struct lthread_condattr *attr) 96 { 97 struct lthread_cond *c; 98 99 if (cond == NULL) 100 return POSIX_ERRNO(EINVAL); 101 102 /* allocate a condition variable from cache */ 103 c = _lthread_objcache_alloc((THIS_SCHED)->cond_cache); 104 105 if (c == NULL) 106 return POSIX_ERRNO(EAGAIN); 107 108 c->blocked = _lthread_queue_create("blocked"); 109 if (c->blocked == NULL) { 110 _lthread_objcache_free((THIS_SCHED)->cond_cache, (void *)c); 111 return POSIX_ERRNO(EAGAIN); 112 } 113 114 if (name == NULL) 115 strncpy(c->name, "no name", sizeof(c->name)); 116 else 117 strncpy(c->name, name, sizeof(c->name)); 118 c->name[sizeof(c->name)-1] = 0; 119 120 c->root_sched = THIS_SCHED; 121 122 (*cond) = c; 123 DIAG_CREATE_EVENT((*cond), LT_DIAG_COND_CREATE); 124 return 0; 125 } 126 127 /* 128 * Destroy a condition variable 129 */ 130 int lthread_cond_destroy(struct lthread_cond *c) 131 { 132 if (c == NULL) { 133 DIAG_EVENT(c, LT_DIAG_COND_DESTROY, c, POSIX_ERRNO(EINVAL)); 134 return POSIX_ERRNO(EINVAL); 135 } 136 137 /* try to free it */ 138 if (_lthread_queue_destroy(c->blocked) < 0) { 139 /* queue in use */ 140 DIAG_EVENT(c, LT_DIAG_COND_DESTROY, c, POSIX_ERRNO(EBUSY)); 141 return POSIX_ERRNO(EBUSY); 142 } 143 144 /* okay free it */ 145 _lthread_objcache_free(c->root_sched->cond_cache, c); 146 DIAG_EVENT(c, LT_DIAG_COND_DESTROY, c, 0); 147 return 0; 148 } 149 150 /* 151 * Wait on a condition variable 152 */ 153 int lthread_cond_wait(struct lthread_cond *c, __rte_unused uint64_t reserved) 154 { 155 struct lthread *lt = THIS_LTHREAD; 156 157 if (c == NULL) { 158 DIAG_EVENT(c, LT_DIAG_COND_WAIT, c, POSIX_ERRNO(EINVAL)); 159 return POSIX_ERRNO(EINVAL); 160 } 161 162 163 DIAG_EVENT(c, LT_DIAG_COND_WAIT, c, 0); 164 165 /* queue the current thread in the blocked queue 166 * this will be written when we return to the scheduler 167 * to ensure that the current thread context is saved 168 * before any signal could result in it being dequeued and 169 * resumed 170 */ 171 lt->pending_wr_queue = c->blocked; 172 _suspend(); 173 174 /* the condition happened */ 175 return 0; 176 } 177 178 /* 179 * Signal a condition variable 180 * attempt to resume any blocked thread 181 */ 182 int lthread_cond_signal(struct lthread_cond *c) 183 { 184 struct lthread *lt; 185 186 if (c == NULL) { 187 DIAG_EVENT(c, LT_DIAG_COND_SIGNAL, c, POSIX_ERRNO(EINVAL)); 188 return POSIX_ERRNO(EINVAL); 189 } 190 191 lt = _lthread_queue_remove(c->blocked); 192 193 if (lt != NULL) { 194 /* okay wake up this thread */ 195 DIAG_EVENT(c, LT_DIAG_COND_SIGNAL, c, lt); 196 _ready_queue_insert((struct lthread_sched *)lt->sched, lt); 197 } 198 return 0; 199 } 200 201 /* 202 * Broadcast a condition variable 203 */ 204 int lthread_cond_broadcast(struct lthread_cond *c) 205 { 206 struct lthread *lt; 207 208 if (c == NULL) { 209 DIAG_EVENT(c, LT_DIAG_COND_BROADCAST, c, POSIX_ERRNO(EINVAL)); 210 return POSIX_ERRNO(EINVAL); 211 } 212 213 DIAG_EVENT(c, LT_DIAG_COND_BROADCAST, c, 0); 214 do { 215 /* drain the queue waking everybody */ 216 lt = _lthread_queue_remove(c->blocked); 217 218 if (lt != NULL) { 219 DIAG_EVENT(c, LT_DIAG_COND_BROADCAST, c, lt); 220 /* wake up */ 221 _ready_queue_insert((struct lthread_sched *)lt->sched, 222 lt); 223 } 224 } while (!_lthread_queue_empty(c->blocked)); 225 _reschedule(); 226 DIAG_EVENT(c, LT_DIAG_COND_BROADCAST, c, 0); 227 return 0; 228 } 229 230 /* 231 * return the diagnostic ref val stored in a condition var 232 */ 233 uint64_t 234 lthread_cond_diag_ref(struct lthread_cond *c) 235 { 236 if (c == NULL) 237 return 0; 238 return c->diag_ref; 239 } 240