/*************************************************************************/
/*
 * GeekOS master source distribution and/or project solution
 * Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
 * Copyright (c) 2003 Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
 * Copyright (c) 2004 Michael Hicks <mwh@cs.umd.edu>
 *
 * This file is not distributed under the standard GeekOS license.
 * Publication or redistribution of this file without permission of
 * the author(s) is prohibited.
 */
/*************************************************************************/
/*
 * Interface file for calling Cyclone code from C code in GeekOS 
 * Copyright (c) 2004, Michael Hicks <mwh@cs.umd.edu>
 * $Revision: 1.1.1.1 $
 * 
 * This is free software.  You are permitted to use,
 * redistribute, and modify it as specified in the file "COPYING".
 */

#ifndef __CYCLONE_H__
#define __CYCLONE_H__

#include "runtime_tls.h"

extern struct _xtunion_struct* Cyc_Core_get_exn_thrown();
extern const char *Cyc_Core_get_exn_filename();
extern int Cyc_Core_get_exn_lineno();     

extern int cyc_runtime_register_thread(tls_slot_t *slot);
extern int cyc_runtime_register_thread_dbg(tls_slot_t *slot, const char *fname);
extern int cyc_runtime_unregister_thread();
extern int cyc_runtime_unregister_thread_dbg(const char *fname);

/* To call a Cyclone function.

   If you want to call the cyclone function using the call foo(arg)
   then to use this macro you would do

   cyc_call(res,foo,arg)  or
   void_cyc_call(foo,arg)

   where the former is used if a result is returned and the latter if not.

   This macro does two things: 

   1) Places an exception handler around this call to catch
   any stray exceptions.  The result of the macro is NULL if no
   exception is thrown, or the exception name if it was.
   2) Places Cyc_ prefix around the call.

   For cyc_call, the result is stored in the provided variable res.
*/
#define cyc_call(res,f,arg...)							\
({                                                                              \
   tls_record_t tlr;                                                            \
   tls_slot_t tls;  tls.record=&tlr;                                            \
   cyc_runtime_register_thread_dbg(&tls, # f);                                  \
   struct _handler_cons h;							\
   int status = 0;								\
   char *exn_name = NULL;							\
   _push_handler(&h);								\
   if (setjmp(h.handler)) status = 1;						\
   if (!status) {								\
     res = Cyc_ ## f (arg);							\
     _pop_handler();								\
   } else {									\
     struct _xtunion_struct *exn_thrown = Cyc_Core_get_exn_thrown();		\
     const char *exn_filename = Cyc_Core_get_exn_filename();			\
     int exn_lineno = Cyc_Core_get_exn_lineno();				\
     exn_name = exn_thrown->tag;						\
     printk("<3>" "Uncaught exception %s thrown from around %s:%d\n",exn_name,	\
	       exn_filename,exn_lineno);					\
  }										\
  cyc_runtime_unregister_thread_dbg(# f);                                       \
  exn_name;									\
})

#define void_cyc_call(f,arg...)							\
({                                                                              \
   tls_record_t tlr;                                                            \
   tls_slot_t tls; tls.pid=0; tls.record=&tlr;                                  \
   cyc_runtime_register_thread_dbg(&tls, # f);                                  \
   struct _handler_cons h;							\
   int status = 0;								\
   char *exn_name = NULL;							\
   _push_handler(&h);								\
   if (setjmp(h.handler)) status = 1;						\
   if (!status) {								\
     Cyc_ ## f (arg);								\
     _pop_handler();								\
   } else {									\
     struct _xtunion_struct *exn_thrown = Cyc_Core_get_exn_thrown();		\
     const char *exn_filename = Cyc_Core_get_exn_filename();			\
     int exn_lineno = Cyc_Core_get_exn_lineno();				\
     exn_name = exn_thrown->tag;						\
     printk("<3>" "Uncaught exception %s thrown from around %s:%d\n",exn_name,	\
	       exn_filename,exn_lineno);					\
  }										\
  cyc_runtime_unregister_thread_dbg(# f);                                       \
  exn_name;									\
})

#endif
