/*
 * $Id: setjmp.h,v 1.7 2001/03/02 21:49:58 k-abe Exp $
 *
 * This file is part of PTL, Portable Thread Library.
 *
 * Copyright (C) 1997-2000 Kota Abe
 *
 */

#ifndef __PTL_SETJMP_H__
#define __PTL_SETJMP_H__

/* ---------------------------------------------------------------- */
#ifdef __PTL_RENAMED__
#define __PTL_ALREADY_RENAMED_SETJMP_H
#else
#include <sys/pthread-before.h>
#endif

#ifdef __GNUC__
#include <00root-gcc/setjmp.h>
#else
#include <00root-system/setjmp.h>
#endif

#include <sys/pthread-after.h>
/* ---------------------------------------------------------------- */

#include <pthread.h>
#include <signal.h>

#undef sigjmp_buf
#undef sigsetjmp
#undef siglongjmp
#undef jmp_buf

#ifdef HAVE__SETJMP
# define ORIG_SETJMP(env)	_setjmp(env)
# define ORIG_LONGJMP(env,val)	_longjmp(env, val)
# define ORIG_JMP_BUF		__jmp_buf_orig
#else
#ifdef HAVE_SIGSETJMP
# define ORIG_SETJMP(env)	sigsetjmp(env,0)
# define ORIG_LONGJMP(env,val)	siglongjmp(env,val)
# define ORIG_JMP_BUF		__sigjmp_buf_orig
#else
	#error "you lose"
#endif
#endif

/*
 * POSIX sigsetjmp, siglongjmp interface
 */

/*
 * Initial part of (sig)jmp_buf must be identical with original jmp_buf,
 * because this struct is also used by _setjmp/_longjmp functions!
 */
typedef struct _ptl_sigjmp_buf {
    ORIG_JMP_BUF		jmpenv;
    int				savemask;
    pthread_t			tid;
    sigset_t			mask;
    struct _pthread_handler_rec	*cleanhead;
} sigjmp_buf[1];

/* Our version of jmp_buf is identical with sigjmp_buf */
typedef struct _ptl_sigjmp_buf jmp_buf[1];

extern int (*_pthread_setjmp_addr)();

#ifndef PTL_INTERNAL

/*
 * sigsetjmp, siglongjmp, setjmp, longjmp
 */

# define	sigsetjmp(env,sm)					\
    (((env)[0].tid = pthread_self()),					\
     (((env)[0].savemask = (sm)) &&					\
      pthread_sigmask(SIG_UNBLOCK, NULL, &(env)[0].mask)),		\
     (env)[0].cleanhead = *_pthread_cleanup_header(),			\
     (*_pthread_setjmp_addr)((env)[0].jmpenv))

# undef siglongjmp
# define siglongjmp		_pthread_siglongjmp

__PTL_BEGIN_DECLS

extern void _pthread_siglongjmp __PTL_P((sigjmp_buf, int)) __PTL_NORET;

__PTL_END_DECLS

/* setjmp must be a macro in ANSI C standard */
# undef setjmp
# define setjmp(env)		sigsetjmp((env),1)

# undef longjmp
# define longjmp(env,val)	_pthread_siglongjmp((env),(val))

#endif /* PTL_INTERNAL */

/* ---------------------------------------------------------------- */
#ifdef __PTL_ALREADY_RENAMED_SETJMP_H
#include <sys/pthread-before.h>
#undef __PTL_ALREADY_RENAMED_SETJMP_H
#else
#include <sys/pthread-after.h>
#endif
/* ---------------------------------------------------------------- */

#endif /* __PTL_SETJMP_H__ */
