Edit

IABSD.fr/src/lib/libc/thread/rthread_tls.c

Branch :

  • Show log

    Commit

  • Author : jsg
    Date : 2023-04-19 12:30:09
    Hash : 02c3c5b9
    Message : remove duplicate includes ok tb@

  • lib/libc/thread/rthread_tls.c
  • /*	$OpenBSD: rthread_tls.c,v 1.5 2023/04/19 12:30:09 jsg Exp $ */
    /*
     * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org>
     * All Rights Reserved.
     *
     * Permission to use, copy, modify, and distribute this software for any
     * purpose with or without fee is hereby granted, provided that the above
     * copyright notice and this permission notice appear in all copies.
     *
     * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     */
    /*
     * thread specific storage
     */
    
    #include <errno.h>
    #include <pthread.h>
    #include <stdlib.h>
    
    #include "rthread.h"
    
    
    struct rthread_key {
    	int used;
    	void (*destructor)(void *);
    };
    
    static struct rthread_key rkeys[PTHREAD_KEYS_MAX];
    static _atomic_lock_t rkeyslock = _SPINLOCK_UNLOCKED;
    
    int
    pthread_key_create(pthread_key_t *key, void (*destructor)(void*))
    {
    	static int hint;
    	int i;
    
    	_spinlock(&rkeyslock);
    	if (rkeys[hint].used) {
    		for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
    			if (!rkeys[i].used)
    				break;
    		}
    		if (i == PTHREAD_KEYS_MAX) {
    			_spinunlock(&rkeyslock);
    			return (EAGAIN);
    		}
    		hint = i;
    	}
    	rkeys[hint].used = 1;
    	rkeys[hint].destructor = destructor;
    
    	*key = hint++;
    	if (hint >= PTHREAD_KEYS_MAX)
    		hint = 0;
    	_spinunlock(&rkeyslock);
    
    	return (0);
    }
    DEF_STRONG(pthread_key_create);
    
    int
    pthread_key_delete(pthread_key_t key)
    {
    	struct rthread_storage *rs;
    	int rv = 0;
    
    	if (key < 0 || key >= PTHREAD_KEYS_MAX)
    		return (EINVAL);
    
    	_spinlock(&rkeyslock);
    	if (!rkeys[key].used) {
    		rv = EINVAL;
    		goto out;
    	}
    
    	rkeys[key].used = 0;
    	rkeys[key].destructor = NULL;
    	if (_thread_cb.tc_thread_key_zero != NULL)
    		_thread_cb.tc_thread_key_zero(key);
    	else {
    		for (rs = _initial_thread.local_storage; rs; rs = rs->next) {
    			if (rs->keyid == key)
    				rs->data = NULL;
    		}
    	}
    
    out:
    	_spinunlock(&rkeyslock);
    	return (rv);
    }
    
    static struct rthread_storage *
    _rthread_findstorage(pthread_key_t key)
    {
    	struct rthread_storage *rs;
    	pthread_t self;
    
    	if (!rkeys[key].used) {
    		rs = NULL;
    		goto out;
    	}
    
    	self = pthread_self();
    
    	for (rs = self->local_storage; rs; rs = rs->next) {
    		if (rs->keyid == key)
    			break;
    	}
    	if (!rs) {
    		rs = calloc(1, sizeof(*rs));
    		if (!rs)
    			goto out;
    		rs->keyid = key;
    		rs->data = NULL;
    		rs->next = self->local_storage;
    		self->local_storage = rs;
    	}
    
    out:
    	return (rs);
    }
    
    void *
    pthread_getspecific(pthread_key_t key)
    {
    	struct rthread_storage *rs;
    
    	if (key < 0 || key >= PTHREAD_KEYS_MAX)
    		return (NULL);
    
    	rs = _rthread_findstorage(key);
    	if (!rs)
    		return (NULL);
    
    	return (rs->data);
    }
    DEF_STRONG(pthread_getspecific);
    
    int
    pthread_setspecific(pthread_key_t key, const void *data)
    {
    	struct rthread_storage *rs;
    
    	if (key < 0 || key >= PTHREAD_KEYS_MAX)
    		return (EINVAL);
    
    	rs = _rthread_findstorage(key);
    	if (!rs)
    		return (ENOMEM);
    	rs->data = (void *)data;
    
    	return (0);
    }
    DEF_STRONG(pthread_setspecific);
    
    void
    _rthread_tls_destructors(pthread_t thread)
    {
    	struct rthread_storage *rs;
    	int i;
    
    	_spinlock(&rkeyslock);
    	for (i = 0; i < PTHREAD_DESTRUCTOR_ITERATIONS; i++) {
    		for (rs = thread->local_storage; rs; rs = rs->next) {
    			if (!rs->data)
    				continue;
    			if (rkeys[rs->keyid].destructor) {
    				void (*destructor)(void *) =
    				    rkeys[rs->keyid].destructor;
    				void *data = rs->data;
    				rs->data = NULL;
    				_spinunlock(&rkeyslock);
    				destructor(data);
    				_spinlock(&rkeyslock);
    			}
    		}
    	}
    	for (rs = thread->local_storage; rs; rs = thread->local_storage) {
    		thread->local_storage = rs->next;
    		free(rs);
    	}
    	_spinunlock(&rkeyslock);
    }