/*
 * @(#)context_md.h	1.22 98/07/01
 *
 * Copyright 1995-1998 by Sun Microsystems, Inc.,
 * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
 * All rights reserved.
 * 
 * This software is the confidential and proprietary information
 * of Sun Microsystems, Inc. ("Confidential Information").  You
 * shall not disclose such Confidential Information and shall use
 * it only in accordance with the terms of the license agreement
 * you entered into with Sun.
 */

/*
 * FreeBSD-dependent API
 */

#ifndef _FREEBSD_CONTEXT_MD_H_
#define _FREEBSD_CONTEXT_MD_H_

#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <setjmp.h>

typedef struct lj_ucontext {
	sigjmp_buf	jmpbuf;
	char		floatbuf[108];
} lj_ucontext_t;

/*
 * Routines that call getcontext have strange control flow graphs,
 * since a call to a routine that calls setcontext will eventually
 * return at the getcontext site, not the original call site.  This
 * utterly wrecks control flow analysis.
 */
#pragma unknown_control_flow(getcontext)

/*
 * A freebsd2 context.  Everything else is on the stack.
 */
typedef struct {
    unsigned int unix_errno;
    lj_ucontext_t lj_ucontext;
} context_t;

/* Save state of the current content and call rescheduler */

void reschedule(void);

#if defined(i386)

#define	switchContext(contextp) {			\
    errno = (contextp)->unix_errno;			\
    siglongjmp((contextp)->lj_ucontext.jmpbuf, 1);	\
}

#define yieldContext(contextp) {				\
    char * fdata = (char *)contextp->lj_ucontext.floatbuf;	\
    __asm__ ("fsave %0"::"m" (*fdata));				\
    __asm__ ("fwait");						\
    if (!sigsetjmp(contextp->lj_ucontext.jmpbuf,-1)) {		\
          (contextp)->unix_errno = errno;			\
          reschedule();						\
    } else {							\
        /*							\
	 * FreeBSD's siglongjmp resets the FPU with 'fninit',	\
	 * so restore it.					\
	 */							\
	__asm__ ("frstor %0"::"m" (*fdata));			\
    }								\
}

#else

#error Unsupported ISA

#endif


/*
 * Workaround for BUG 4007713/4026661/1262991:
 * create a private copy (fix) for x86 green threads getcontext
 * called green_getcontext to avoid the libc getcontext bug.
 * Furthermore, the green_getcontext code differs from the
 * libc behavior since it does not call __cerror if the system
 * call fails. Reference to __cerror was removed since its no
 * longer a global in Solaris 2.6 libc. This change in API should
 * be benign to the VM (we don't check for getcontext return code).
 */

#if defined(__solaris)
#if defined(i386)

#if defined(__STDC__)

extern int green_getcontext(ucontext_t *);

#else

extern int green_getcontext();

#endif /* __STDC__ */

#define getcontext green_getcontext

#endif /* i386 */
#endif /* __solaris__ */

#endif /* !_FREEBSD_CONTEXT_MD_H_ */
