Edit

IABSD.fr/src/include/tib.h

Branch :

  • Show log

    Commit

  • Author : miod
    Date : 2023-12-08 19:14:36
    Hash : 9b42e9bf
    Message : Make sure TIB_INIT correctly initializes tib_thread_flags; regression introduced in 1.3, causing sporadic pthread_main_np() erroneous results (and possibly more subtle problems). With and ok kurt@

  • include/tib.h
  • /*	$OpenBSD: tib.h,v 1.10 2023/12/08 19:14:36 miod Exp $	*/
    /*
     * Copyright (c) 2011,2014 Philip Guenther <guenther@openbsd.org>
     *
     * 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 Information Block (TIB) and Thread Local Storage (TLS) handling
     * (the TCB, Thread Control Block, is part of the TIB)
     */
    
    #ifndef	_TIB_H_
    #define	_TIB_H_
    
    #include <sys/types.h>
    #include <machine/tcb.h>
    
    #include <stddef.h>
    
    
    /*
     * This header defines struct tib and at least eight macros:
     *	TLS_VARIANT
     *		Either 1 or 2  (Actually defined by <machine/tcb.h>)
     *
     *	TCB_SET(tcb)
     *		Set the TCB pointer for this thread to 'tcb'
     *
     *	TCB_GET()
     *		Return the TCB pointer for this thread
     *
     *	TCB_TO_TIB(tcb)
     *		Given a TCB pointer, return the matching TIB pointer
     *
     *	TIB_TO_TCB(tib)
     *		Given a TIB pointer, return the matching TCB pointer
     *
     *	TIB_INIT(tib, dtv, thread)
     *		Initializes a TIB for a new thread, using the supplied
     *		values for its dtv and thread pointers
     *
     *	TIB_GET()
     *		Short-hand for TCB_TO_TIB(TCB_GET())
     *
     *	TIB_EXTRA_ALIGN
     *		On TLS variant 2 archs, what alignment is sufficient
     *		for the extra space that will be used for struct pthread?
     *
     * The following functions are provided by either ld.so (dynamic) or
     * libc (static) for allocating and freeing a common memory block that
     * will hold both the TIB and the pthread structure:
     *	_dl_allocate_tib(sizeof(struct pthread))
     *		Allocates a combined TIB and pthread memory region.
     *		The argument is the amount of space to reserve
     *		for the pthread structure.  Returns a pointer to
     *		the TIB inside the allocated block.
     *
     * 	_dl_free_tib(tib, sizeof(struct pthread))
     *		Frees a TIB and pthread block previously allocated
     *		with _dl_allocate_tib().  Must be passed the return
     *		value of that previous call.
     */
    
    /*
     * Regarding <machine/tcb.h>:
     *  - it must define the TLS_VARIANT macro
     *  - it may define TCB_OFFSET if the TCB address in the kernel and/or
     *    register is offset from the actual TCB address.  TCB_OFFSET > 0
     *    means the kernel/register points to *after* the real data.
     *  - if there's a faster way to get or set the TCB pointer for the thread
     *    than the __{get,set}_tcb() syscalls, it should define either or both
     *    the TCB_{GET,SET} macros to do so.
     */
    
    
    /* All archs but mips64 have fast TCB_GET() and don't need caching */
    #ifndef	__mips64__
    # define TCB_HAVE_MD_GET	1
    #endif
    #ifdef	TCB_SET
    # define TCB_HAVE_MD_SET	1
    #else
    # define TCB_SET(tcb)		__set_tcb(tcb)
    #endif
    #ifndef TCB_OFFSET
    # define TCB_OFFSET	0
    #endif
    
    /*
     * tib_cantcancel values is non-zero if the thread should skip all
     * cancellation processing
     */
    #define CANCEL_DISABLED	1
    #define CANCEL_DYING	2
    
    /*
     * tib_cancel_point is non-zero if we're in a cancel point; its modified
     * by the cancel point code and read by the cancellation signal handler
     */
    #define CANCEL_POINT		1
    #define CANCEL_POINT_DELAYED	2
    
    
    #if TLS_VARIANT == 1
    /*
     * ABI specifies that the static TLS data starts two words after the
     * (notional) thread pointer, with the first of those two words being
     * the TLS dtv pointer.  The other (second) word is reserved for the
     * implementation, so we place the pointer to the thread structure there,
     * but we place our actual thread bits before the TCB, at negative offsets
     * from the TCB pointer.  Ergo, memory is laid out, low to high, as:
     *
     *	[pthread structure]
     *	TIB {
     *		...cancelation and other int-sized info...
     *		int errno
     *		void *locale
     *		TCB (- TCB_OFFSET) {
     *			void *dtv
     *			struct pthread *thread
     *		}
     *	}
     *	static TLS data
     */
    
    struct tib {
    	void	*tib_atexit;
    	int	tib_thread_flags;	/* internal to libpthread */
    	pid_t	tib_tid;
    	int	tib_cantcancel;
    	int	tib_cancel_point;
    	int	tib_canceled;
    	int	tib_errno;
    	void	*tib_locale;
    #ifdef __powerpc64__
    	void	*tib_thread;
    	void	*tib_dtv;		/* internal to the runtime linker */
    #else
    	void	*tib_dtv;		/* internal to the runtime linker */
    	void	*tib_thread;
    #endif
    };
    
    
    #elif TLS_VARIANT == 2
    /*
     * ABI specifies that the static TLS data occupies the memory before
     * the TCB pointer, at negative offsets, and that on i386 and amd64
     * the word the TCB points to contains a pointer to itself.  So,
     * we place errno and our thread bits after that.  Memory is laid
     * out, low to high, as:
     *	static TLS data
     *	TIB {
     *		TCB (- TCB_OFFSET) {
     *			self pointer [i386/amd64 only]
     *			void *dtv
     *		}
     *		struct pthread *thread
     *		void *locale
     *		int errno
     *		...cancelation and other int-sized info...
     *	}
     *	[pthread structure]
     */
    
    struct tib {
    #if defined(__i386) || defined(__amd64)
    	struct	tib *__tib_self;
    # define __tib_tcb __tib_self
    #endif
    	void	*tib_dtv;		/* internal to the runtime linker */
    	void	*tib_thread;
    	void	*tib_locale;
    	int	tib_errno;
    	int	tib_canceled;
    	int	tib_cancel_point;
    	int	tib_cantcancel;
    	pid_t	tib_tid;
    	int	tib_thread_flags;	/* internal to libpthread */
    	void	*tib_atexit;
    };
    
    #if defined(__i386) || defined(__amd64)
    # define _TIB_PREP(tib)	\
    	((void)((tib)->__tib_self = (tib)))
    #endif
    
    #define	TIB_EXTRA_ALIGN		sizeof(void *)
    
    #else
    # error "unknown TLS variant"
    #endif
    
    /* nothing to do by default */
    #ifndef	_TIB_PREP
    # define _TIB_PREP(tib)	((void)0)
    #endif
    
    #define	TIB_INIT(tib, dtv, thread)	do {		\
    		(tib)->tib_thread	= (thread);	\
    		(tib)->tib_atexit	= NULL;		\
    		(tib)->tib_locale	= NULL;		\
    		(tib)->tib_cantcancel	= 0;		\
    		(tib)->tib_cancel_point	= 0;		\
    		(tib)->tib_canceled	= 0;		\
    		(tib)->tib_dtv		= (dtv);	\
    		(tib)->tib_errno	= 0;		\
    		(tib)->tib_thread_flags = 0;		\
    		_TIB_PREP(tib);				\
    	} while (0)
    
    #ifndef	__tib_tcb
    # define __tib_tcb		tib_dtv
    #endif
    #define	_TIBO_TCB		(offsetof(struct tib, __tib_tcb) + TCB_OFFSET)
    
    #define	TCB_TO_TIB(tcb)		((struct tib *)((char *)(tcb) - _TIBO_TCB))
    #define	TIB_TO_TCB(tib)		((char *)(tib) + _TIBO_TCB)
    #define	TIB_GET()		TCB_TO_TIB(TCB_GET())
    
    
    __BEGIN_DECLS
    struct dl_info;
    struct dl_phdr_info;
    struct dl_cb_0 {
    	void	*(*dl_allocate_tib)(size_t);
    	void	 (*dl_free_tib)(void *, size_t);
    	void	 (*dl_clean_boot)(void);
    	void	*(*dlopen)(const char *, int);
    	int	 (*dlclose)(void *);
    	void	*(*dlsym)(void *, const char *);
    	int	 (*dladdr)(const void *, struct dl_info *);
    	int	 (*dlctl)(void *, int, void *);
    	char	*(*dlerror)(void);
    	int	 (*dl_iterate_phdr)(int (*)(struct dl_phdr_info *,
    		    size_t, void *), void *);
    };
    
    #define	DL_CB_CUR	0
    typedef	struct dl_cb_0	dl_cb;
    
    /* type of function passed to init functions that returns a dl_cb */
    typedef	const void *dl_cb_cb(int _version);
    
    void	*_dl_allocate_tib(size_t _extra) __dso_public;
    void	_dl_free_tib(void *_tib, size_t _extra) __dso_public;
    
    /* The actual syscalls */
    void	*__get_tcb(void);
    void	__set_tcb(void *_tcb);
    __END_DECLS
    
    #endif /* _TIB_H_ */