1 /* $NetBSD: thread-stub.c,v 1.37 2026/09/24 18:05:37 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2003, 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #if defined(LIBC_SCCS) && !defined(lint) 34 __RCSID("$NetBSD: thread-stub.c,v 1.37 2026/09/24 18:05:37 christos Exp $"); 35 #endif /* LIBC_SCCS and not lint */ 36 37 /* 38 * Stubs for thread operations, for use when threads are not used by 39 * the application. See "reentrant.h" for details. 40 */ 41 42 #ifdef _REENTRANT 43 44 #define __LIBC_THREAD_STUBS 45 46 #include "namespace.h" 47 #include "reentrant.h" 48 #include "tsd.h" 49 50 #include <errno.h> 51 #include <signal.h> 52 #include <stdlib.h> 53 #include <unistd.h> 54 55 extern int __isthreaded; 56 57 #define DIE() (void)raise(SIGABRT) 58 59 #define CHECK_NOT_THREADED_ALWAYS() \ 60 do { \ 61 if (__isthreaded) \ 62 DIE(); \ 63 } while (0) 64 65 #if 1 66 #define CHECK_NOT_THREADED() CHECK_NOT_THREADED_ALWAYS() 67 #else 68 #define CHECK_NOT_THREADED() /* nothing */ 69 #endif 70 71 /* 72 * These aliases are probably not necessary but have been there 73 * historically, probably by mistake. 74 */ 75 __weak_alias(pthread_join, __libc_thr_join) 76 __weak_alias(pthread_detach, __libc_thr_detach) 77 78 /* 79 * These aliases appear to have been an accident -- nothing has ever 80 * exposed them in a .h file, and they have probably never been used. 81 */ 82 __strong_alias(__libc_pthread_join, __libc_thr_join) 83 __strong_alias(__libc_pthread_detach, __libc_thr_detach) 84 85 /* 86 * These aliases are exposed by pthread.h and overridden by libpthread. 87 * This way libraries can have calls to pthread_create/join/detach 88 * without linking against libpthread, but they will fail at runtime in 89 * applications not linked against libpthread. (Libraries linked 90 * against libpthread themselves, of course, will work, and carry the 91 * dependency to the application.) 92 */ 93 __weak_alias(__libc_thr_join, __libc_thr_join_stub) 94 __weak_alias(__libc_thr_detach, __libc_thr_detach_stub) 95 96 int 97 __libc_thr_join_stub(pthread_t thread, void **valptr) 98 { 99 100 if (thread == pthread_self()) 101 return EDEADLK; 102 return ESRCH; 103 } 104 105 int 106 __libc_thr_detach_stub(pthread_t thread) 107 { 108 109 if (thread == pthread_self()) 110 return 0; 111 return ESRCH; 112 } 113 114 __weak_alias(pthread_setname, __libc_mutex_catchall_stub) 115 __weak_alias(pthread_setaffinity_np, __libc_mutex_catchall_stub) 116 117 /* thread creation attributes */ 118 119 __weak_alias(__libc_thr_attr_init, __libc_mutex_catchall_stub) 120 __weak_alias(__libc_thr_attr_setdetachstate, __libc_mutex_catchall_stub) 121 __weak_alias(__libc_thr_attr_destroy, __libc_mutex_catchall_stub) 122 123 /* mutexes */ 124 125 int __libc_mutex_catchall_stub(mutex_t *); 126 127 __weak_alias(__libc_mutex_init,__libc_mutex_init_stub) 128 __weak_alias(__libc_mutex_lock,__libc_mutex_catchall_stub) 129 __weak_alias(__libc_mutex_trylock,__libc_mutex_catchall_stub) 130 __weak_alias(__libc_mutex_unlock,__libc_mutex_catchall_stub) 131 __weak_alias(__libc_mutex_destroy,__libc_mutex_catchall_stub) 132 133 __strong_alias(__libc_mutex_lock_stub,__libc_mutex_catchall_stub) 134 __strong_alias(__libc_mutex_trylock_stub,__libc_mutex_catchall_stub) 135 __strong_alias(__libc_mutex_unlock_stub,__libc_mutex_catchall_stub) 136 __strong_alias(__libc_mutex_destroy_stub,__libc_mutex_catchall_stub) 137 138 int __libc_mutexattr_catchall_stub(mutexattr_t *); 139 140 __weak_alias(__libc_mutexattr_init,__libc_mutexattr_catchall_stub) 141 __weak_alias(__libc_mutexattr_destroy,__libc_mutexattr_catchall_stub) 142 __weak_alias(__libc_mutexattr_settype,__libc_mutexattr_settype_stub) 143 144 __strong_alias(__libc_mutexattr_init_stub,__libc_mutexattr_catchall_stub) 145 __strong_alias(__libc_mutexattr_destroy_stub,__libc_mutexattr_catchall_stub) 146 147 int 148 __libc_mutex_init_stub(mutex_t *m, const mutexattr_t *a) 149 { 150 /* LINTED deliberate lack of effect */ 151 (void)m; 152 /* LINTED deliberate lack of effect */ 153 (void)a; 154 155 CHECK_NOT_THREADED(); 156 157 return (0); 158 } 159 160 int 161 __libc_mutex_catchall_stub(mutex_t *m) 162 { 163 /* LINTED deliberate lack of effect */ 164 (void)m; 165 166 CHECK_NOT_THREADED(); 167 168 return (0); 169 } 170 171 int 172 __libc_mutexattr_settype_stub(mutexattr_t *ma, int type) 173 { 174 /* LINTED deliberate lack of effect */ 175 (void)ma; 176 /* LINTED deliberate lack of effect */ 177 (void)type; 178 179 CHECK_NOT_THREADED(); 180 181 return (0); 182 } 183 184 int 185 __libc_mutexattr_catchall_stub(mutexattr_t *ma) 186 { 187 /* LINTED deliberate lack of effect */ 188 (void)ma; 189 190 CHECK_NOT_THREADED(); 191 192 return (0); 193 } 194 195 /* condition attribute variables */ 196 197 int __libc_condattr_catchall_stub(condattr_t *); 198 int __libc_condattr_setclock_stub(condattr_t *, clockid_t); 199 200 __weak_alias(__libc_condattr_init,__libc_condattr_catchall_stub) 201 __weak_alias(__libc_condattr_destroy,__libc_condattr_catchall_stub) 202 __weak_alias(__libc_condattr_setclock,__libc_condattr_setclock_stub) 203 204 int 205 __libc_condattr_catchall_stub(condattr_t *a) 206 { 207 /* LINTED deliberate lack of effect */ 208 (void)a; 209 210 CHECK_NOT_THREADED(); 211 212 return (0); 213 } 214 215 int 216 __libc_condattr_setclock_stub(condattr_t *a, clockid_t b) 217 { 218 /* LINTED deliberate lack of effect */ 219 (void)a; 220 221 /* LINTED deliberate lack of effect */ 222 (void)b; 223 224 CHECK_NOT_THREADED(); 225 226 return (0); 227 } 228 229 /* condition variables */ 230 231 int __libc_cond_catchall_stub(cond_t *); 232 233 __weak_alias(__libc_cond_init,__libc_cond_init_stub) 234 __weak_alias(__libc_cond_signal,__libc_cond_catchall_stub) 235 __weak_alias(__libc_cond_broadcast,__libc_cond_catchall_stub) 236 __weak_alias(__libc_cond_wait,__libc_cond_catchall_stub) 237 __weak_alias(__libc_cond_timedwait,__libc_cond_timedwait_stub) 238 __weak_alias(__libc_cond_destroy,__libc_cond_catchall_stub) 239 240 __strong_alias(__libc_cond_signal_stub,__libc_cond_catchall_stub) 241 __strong_alias(__libc_cond_broadcast_stub,__libc_cond_catchall_stub) 242 __strong_alias(__libc_cond_destroy_stub,__libc_cond_catchall_stub) 243 244 int 245 __libc_cond_init_stub(cond_t *c, const condattr_t *a) 246 { 247 /* LINTED deliberate lack of effect */ 248 (void)c; 249 /* LINTED deliberate lack of effect */ 250 (void)a; 251 252 CHECK_NOT_THREADED(); 253 254 return (0); 255 } 256 257 int 258 __libc_cond_wait_stub(cond_t *c, mutex_t *m) 259 { 260 /* LINTED deliberate lack of effect */ 261 (void)c; 262 /* LINTED deliberate lack of effect */ 263 (void)m; 264 265 CHECK_NOT_THREADED(); 266 267 return (0); 268 } 269 270 int 271 __libc_cond_timedwait_stub(cond_t *c, mutex_t *m, const struct timespec *t) 272 { 273 /* LINTED deliberate lack of effect */ 274 (void)c; 275 /* LINTED deliberate lack of effect */ 276 (void)m; 277 /* LINTED deliberate lack of effect */ 278 (void)t; 279 280 CHECK_NOT_THREADED(); 281 282 return (0); 283 } 284 285 int 286 __libc_cond_catchall_stub(cond_t *c) 287 { 288 /* LINTED deliberate lack of effect */ 289 (void)c; 290 291 CHECK_NOT_THREADED(); 292 293 return (0); 294 } 295 296 297 /* read-write locks */ 298 299 int __libc_rwlock_catchall_stub(rwlock_t *); 300 301 __weak_alias(__libc_rwlock_init,__libc_rwlock_init_stub) 302 __weak_alias(__libc_rwlock_rdlock,__libc_rwlock_catchall_stub) 303 __weak_alias(__libc_rwlock_wrlock,__libc_rwlock_catchall_stub) 304 __weak_alias(__libc_rwlock_tryrdlock,__libc_rwlock_catchall_stub) 305 __weak_alias(__libc_rwlock_trywrlock,__libc_rwlock_catchall_stub) 306 __weak_alias(__libc_rwlock_unlock,__libc_rwlock_catchall_stub) 307 __weak_alias(__libc_rwlock_destroy,__libc_rwlock_catchall_stub) 308 309 __strong_alias(__libc_rwlock_rdlock_stub,__libc_rwlock_catchall_stub) 310 __strong_alias(__libc_rwlock_wrlock_stub,__libc_rwlock_catchall_stub) 311 __strong_alias(__libc_rwlock_tryrdlock_stub,__libc_rwlock_catchall_stub) 312 __strong_alias(__libc_rwlock_trywrlock_stub,__libc_rwlock_catchall_stub) 313 __strong_alias(__libc_rwlock_unlock_stub,__libc_rwlock_catchall_stub) 314 __strong_alias(__libc_rwlock_destroy_stub,__libc_rwlock_catchall_stub) 315 316 317 int 318 __libc_rwlock_init_stub(rwlock_t *l, const rwlockattr_t *a) 319 { 320 /* LINTED deliberate lack of effect */ 321 (void)l; 322 /* LINTED deliberate lack of effect */ 323 (void)a; 324 325 CHECK_NOT_THREADED(); 326 327 return (0); 328 } 329 330 int 331 __libc_rwlock_catchall_stub(rwlock_t *l) 332 { 333 /* LINTED deliberate lack of effect */ 334 (void)l; 335 336 CHECK_NOT_THREADED(); 337 338 return (0); 339 } 340 341 342 /* 343 * thread-specific data; we need to actually provide a simple TSD 344 * implementation, since some thread-safe libraries want to use it. 345 */ 346 347 struct __libc_tsd __libc_tsd[TSD_KEYS_MAX]; 348 static int __libc_tsd_nextkey; 349 350 __weak_alias(__libc_thr_keycreate,__libc_thr_keycreate_stub) 351 __weak_alias(__libc_thr_setspecific,__libc_thr_setspecific_stub) 352 __weak_alias(__libc_thr_getspecific,__libc_thr_getspecific_stub) 353 __weak_alias(__libc_thr_keydelete,__libc_thr_keydelete_stub) 354 355 int 356 __libc_thr_keycreate_stub(thread_key_t *k, void (*d)(void *)) 357 { 358 int i; 359 360 for (i = __libc_tsd_nextkey; i < TSD_KEYS_MAX; i++) { 361 if (__libc_tsd[i].tsd_inuse == 0) 362 goto out; 363 } 364 365 for (i = 0; i < __libc_tsd_nextkey; i++) { 366 if (__libc_tsd[i].tsd_inuse == 0) 367 goto out; 368 } 369 370 return (EAGAIN); 371 372 out: 373 /* 374 * XXX We don't actually do anything with the destructor. We 375 * XXX probably should. 376 */ 377 __libc_tsd[i].tsd_inuse = 1; 378 __libc_tsd_nextkey = (i + i) % TSD_KEYS_MAX; 379 __libc_tsd[i].tsd_dtor = d; 380 *k = i; 381 382 return (0); 383 } 384 385 int 386 __libc_thr_setspecific_stub(thread_key_t k, const void *v) 387 { 388 389 __libc_tsd[k].tsd_val = __UNCONST(v); 390 391 return (0); 392 } 393 394 void * 395 __libc_thr_getspecific_stub(thread_key_t k) 396 { 397 398 return (__libc_tsd[k].tsd_val); 399 } 400 401 int 402 __libc_thr_keydelete_stub(thread_key_t k) 403 { 404 405 /* 406 * XXX Do not recycle key; see big comment in libpthread. 407 */ 408 409 __libc_tsd[k].tsd_dtor = NULL; 410 411 return (0); 412 } 413 414 415 /* misc. */ 416 417 __weak_alias(__libc_thr_once,__libc_thr_once_stub) 418 __weak_alias(__libc_thr_sigsetmask,__libc_thr_sigsetmask_stub) 419 __weak_alias(__libc_thr_self,__libc_thr_self_stub) 420 __weak_alias(__libc_thr_yield,__libc_thr_yield_stub) 421 __weak_alias(__libc_thr_create,__libc_thr_create_stub) 422 __weak_alias(__libc_thr_exit,__libc_thr_exit_stub) 423 __weak_alias(__libc_thr_setcancelstate,__libc_thr_setcancelstate_stub) 424 __weak_alias(__libc_thr_equal,__libc_thr_equal_stub) 425 __weak_alias(__libc_thr_curcpu,__libc_thr_curcpu_stub) 426 427 428 int 429 __libc_thr_once_stub(once_t *o, void (*r)(void)) 430 { 431 432 /* XXX Knowledge of libpthread types. */ 433 434 if (o->pto_done == 0) { 435 (*r)(); 436 o->pto_done = 1; 437 } 438 439 return (0); 440 } 441 442 int 443 __libc_thr_sigsetmask_stub(int h, const sigset_t *s, sigset_t *o) 444 { 445 446 CHECK_NOT_THREADED(); 447 448 if (sigprocmask(h, s, o)) 449 return errno; 450 return 0; 451 } 452 453 thr_t 454 __libc_thr_self_stub(void) 455 { 456 457 return ((thr_t) -1); 458 } 459 460 /* This is the strong symbol generated for sched_yield(2) via WSYSCALL() */ 461 int _sys_sched_yield(void); 462 463 int 464 __libc_thr_yield_stub(void) 465 { 466 return _sys_sched_yield(); 467 } 468 469 int 470 __libc_thr_create_stub(thr_t *tp, const thrattr_t *ta, 471 void *(*f)(void *), void *a) 472 { 473 /* LINTED deliberate lack of effect */ 474 (void)tp; 475 /* LINTED deliberate lack of effect */ 476 (void)ta; 477 /* LINTED deliberate lack of effect */ 478 (void)f; 479 /* LINTED deliberate lack of effect */ 480 (void)a; 481 482 CHECK_NOT_THREADED(); 483 484 return EOPNOTSUPP; 485 } 486 487 __dead void 488 __libc_thr_exit_stub(void *v) 489 { 490 /* LINTED deliberate lack of effect */ 491 (void)v; 492 exit(0); 493 } 494 495 int 496 __libc_thr_setcancelstate_stub(int new, int *old) 497 { 498 /* LINTED deliberate lack of effect */ 499 (void)new; 500 501 /* LINTED deliberate lack of effect */ 502 (void)old; 503 504 CHECK_NOT_THREADED(); 505 506 return (0); 507 } 508 509 int 510 __libc_thr_equal_stub(pthread_t t1, pthread_t t2) 511 { 512 513 /* assert that t1=t2=pthread_self() */ 514 return (t1 == t2); 515 } 516 517 unsigned int 518 __libc_thr_curcpu_stub(void) 519 { 520 521 return (0); 522 } 523 524 #endif /* _REENTRANT */ 525