/* -----------------------------------------------------------------------------
- * $Id: PrimOps.hc,v 1.30 1999/09/15 13:45:18 simonmar Exp $
+ * $Id: PrimOps.hc,v 1.46 2000/03/14 09:55:05 simonmar Exp $
*
- * (c) The GHC Team, 1998-1999
+ * (c) The GHC Team, 1998-2000
*
* Primitive functions / data
*
#include "Rts.h"
-#ifdef COMPILER
-
#include "RtsFlags.h"
#include "StgStartup.h"
#include "SchedAPI.h"
#include "StablePriv.h"
#include "HeapStackCheck.h"
#include "StgRun.h"
+#include "Prelude.h"
/* ** temporary **
*/
/*------ All Regs available */
-#ifdef REG_R8
+#if defined(REG_R8)
# define RET_P(a) R1.w = (W_)(a); JMP_(ENTRY_CODE(Sp[0]));
# define RET_N(a) RET_P(a)
R4.w = (W_)(d); R5.w = (W_)(e); R6.w = (W_)(f); \
JMP_(ENTRY_CODE(Sp[0]));
-#else
-
-#if defined(REG_R7) || defined(REG_R6) || defined(REG_R5) || \
- defined(REG_R4) || defined(REG_R3) || defined(REG_R2)
+#elif defined(REG_R7) || defined(REG_R6) || defined(REG_R5) || \
+ defined(REG_R4) || defined(REG_R3)
# error RET_n macros not defined for this setup.
-#else
+
+/*------ 2 Registers available */
+#elif defined(REG_R2)
+
+# define RET_P(a) R1.w = (W_)(a); JMP_(ENTRY_CODE(Sp[0]));
+# define RET_N(a) RET_P(a)
+
+# define RET_PP(a,b) R1.w = (W_)(a); R2.w = (W_)(b); \
+ JMP_(ENTRY_CODE(Sp[0]));
+# define RET_NN(a,b) RET_PP(a,b)
+# define RET_NP(a,b) RET_PP(a,b)
+
+# define RET_PPP(a,b,c) \
+ R1.w = (W_)(a); R2.w = (W_)(b); Sp[-1] = (W_)(c); Sp -= 1; \
+ JMP_(ENTRY_CODE(Sp[1]));
+# define RET_NNP(a,b,c) \
+ R1.w = (W_)(a); R2.w = (W_)(b); Sp[-1] = (W_)(c); Sp -= 1; \
+ JMP_(ENTRY_CODE(Sp[1]));
+
+# define RET_NNNP(a,b,c,d) \
+ R1.w = (W_)(a); \
+ R2.w = (W_)(b); \
+ /* Sp[-3] = ARGTAG(1); */ \
+ Sp[-2] = (W_)(c); \
+ Sp[-1] = (W_)(d); \
+ Sp -= 3; \
+ JMP_(ENTRY_CODE(Sp[3]));
+
+# define RET_NPNP(a,b,c,d) \
+ R1.w = (W_)(a); \
+ R2.w = (W_)(b); \
+ /* Sp[-3] = ARGTAG(1); */ \
+ Sp[-2] = (W_)(c); \
+ Sp[-1] = (W_)(d); \
+ Sp -= 3; \
+ JMP_(ENTRY_CODE(Sp[3]));
+
+# define RET_NNPNNP(a,b,c,d,e,f) \
+ R1.w = (W_)(a); \
+ R2.w = (W_)(b); \
+ Sp[-6] = (W_)(c); \
+ /* Sp[-5] = ARGTAG(1); */ \
+ Sp[-4] = (W_)(d); \
+ /* Sp[-3] = ARGTAG(1); */ \
+ Sp[-2] = (W_)(e); \
+ Sp[-1] = (W_)(f); \
+ Sp -= 6; \
+ JMP_(ENTRY_CODE(Sp[6]));
/*------ 1 Register available */
-#ifdef REG_R1
+#elif defined(REG_R1)
# define RET_P(a) R1.w = (W_)(a); JMP_(ENTRY_CODE(Sp[0]));
# define RET_N(a) RET_P(a)
#else /* 0 Regs available */
#define PUSH_P(o,x) Sp[-o] = (W_)(x)
-#define PUSH_N(o,x) Sp[1-o] = (W_)(x); /* Sp[-o] = ARGTAG(1) */
+
+#ifdef DEBUG
+#define PUSH_N(o,x) Sp[1-o] = (W_)(x); Sp[-o] = ARG_TAG(1);
+#else
+#define PUSH_N(o,x) Sp[1-o] = (W_)(x);
+#endif
+
#define PUSHED(m) Sp -= (m); JMP_(ENTRY_CODE(Sp[m]));
/* Here's how to construct these macros:
#endif
-#endif
-#endif
-
/*-----------------------------------------------------------------------------
Array Primitives
/* Args: R1.p = initialisation value */
FB_
- HP_CHK_GEN(sizeofW(StgMutVar), R1_PTR, newMutVarzh_fast,);
+ HP_CHK_GEN_TICKY(sizeofW(StgMutVar), R1_PTR, newMutVarzh_fast,);
TICK_ALLOC_PRIM(sizeofW(StgHeader)+1,1, 0); /* hack, dependent on rep. */
CCS_ALLOC(CCCS,sizeofW(StgMutVar));
StgForeignObj *result;
FB_
- HP_CHK_GEN(sizeofW(StgForeignObj), NO_PTRS, makeForeignObjzh_fast,);
+ HP_CHK_GEN_TICKY(sizeofW(StgForeignObj), NO_PTRS, makeForeignObjzh_fast,);
TICK_ALLOC_PRIM(sizeofW(StgHeader),
sizeofW(StgForeignObj)-sizeofW(StgHeader), 0);
CCS_ALLOC(CCCS,sizeofW(StgForeignObj)); /* ccs prof */
{
/* R1.p = key
R2.p = value
- R3.p = finalizer
+ R3.p = finalizer (or NULL)
*/
StgWeak *w;
FB_
- HP_CHK_GEN(sizeofW(StgWeak), R1_PTR|R2_PTR|R3_PTR, mkWeakzh_fast,);
+ if (R3.cl == NULL) {
+ R3.cl = &NO_FINALIZER_closure;
+ }
+
+ HP_CHK_GEN_TICKY(sizeofW(StgWeak),R1_PTR|R2_PTR|R3_PTR, mkWeakzh_fast,);
TICK_ALLOC_PRIM(sizeofW(StgHeader)+1, // +1 is for the link field
sizeofW(StgWeak)-sizeofW(StgHeader)-1, 0);
CCS_ALLOC(CCCS,sizeofW(StgWeak)); /* ccs prof */
w->key = R1.cl;
w->value = R2.cl;
- if (R3.cl) {
- w->finalizer = R3.cl;
- } else {
- w->finalizer = &NO_FINALIZER_closure;
- }
+ w->finalizer = R3.cl;
w->link = weak_ptr_list;
weak_ptr_list = w;
FB_
val = R1.i;
- HP_CHK_GEN(sizeofW(StgArrWords)+1, NO_PTRS, int2Integerzh_fast,);
+ HP_CHK_GEN_TICKY(sizeofW(StgArrWords)+1, NO_PTRS, int2Integerzh_fast,);
TICK_ALLOC_PRIM(sizeofW(StgArrWords),1,0);
CCS_ALLOC(CCCS,sizeofW(StgArrWords)+1); /* ccs prof */
FB_
val = R1.w;
- HP_CHK_GEN(sizeofW(StgArrWords)+1, NO_PTRS, word2Integerzh_fast,)
+ HP_CHK_GEN_TICKY(sizeofW(StgArrWords)+1, NO_PTRS, word2Integerzh_fast,)
TICK_ALLOC_PRIM(sizeofW(StgArrWords),1,0);
CCS_ALLOC(CCCS,sizeofW(StgArrWords)+1); /* ccs prof */
/* minimum is one word */
words_needed = 1;
}
- HP_CHK_GEN(sizeofW(StgArrWords)+words_needed, NO_PTRS, int64ToIntegerzh_fast,)
+ HP_CHK_GEN_TICKY(sizeofW(StgArrWords)+words_needed, NO_PTRS, int64ToIntegerzh_fast,)
TICK_ALLOC_PRIM(sizeofW(StgArrWords),words_needed,0);
CCS_ALLOC(CCCS,sizeofW(StgArrWords)+words_needed); /* ccs prof */
} else {
words_needed = 1;
}
- HP_CHK_GEN(sizeofW(StgArrWords)+words_needed, NO_PTRS, word64ToIntegerzh_fast,)
+ HP_CHK_GEN_TICKY(sizeofW(StgArrWords)+words_needed, NO_PTRS, word64ToIntegerzh_fast,)
TICK_ALLOC_PRIM(sizeofW(StgArrWords),words_needed,0);
CCS_ALLOC(CCCS,sizeofW(StgArrWords)+words_needed); /* ccs prof */
FN_(name) \
{ \
MP_INT arg1, arg2, result; \
- I_ s1, s2; \
+ I_ s1, s2; \
StgArrWords* d1; \
StgArrWords* d2; \
FB_ \
FN_(name) \
{ \
MP_INT arg1, arg2, result1, result2; \
- I_ s1, s2; \
+ I_ s1, s2; \
StgArrWords* d1; \
StgArrWords* d2; \
FB_ \
FE_ \
}
-GMP_TAKE2_RET1(plusIntegerzh_fast, mpz_add);
-GMP_TAKE2_RET1(minusIntegerzh_fast, mpz_sub);
-GMP_TAKE2_RET1(timesIntegerzh_fast, mpz_mul);
-GMP_TAKE2_RET1(gcdIntegerzh_fast, mpz_gcd);
+GMP_TAKE2_RET1(plusIntegerzh_fast, mpz_add);
+GMP_TAKE2_RET1(minusIntegerzh_fast, mpz_sub);
+GMP_TAKE2_RET1(timesIntegerzh_fast, mpz_mul);
+GMP_TAKE2_RET1(gcdIntegerzh_fast, mpz_gcd);
+GMP_TAKE2_RET1(quotIntegerzh_fast, mpz_tdiv_q);
+GMP_TAKE2_RET1(remIntegerzh_fast, mpz_tdiv_r);
+GMP_TAKE2_RET1(divExactIntegerzh_fast, mpz_divexact);
GMP_TAKE2_RET2(quotRemIntegerzh_fast, mpz_tdiv_qr);
GMP_TAKE2_RET2(divModIntegerzh_fast, mpz_fdiv_qr);
/* arguments: F1 = Float# */
arg = F1;
- HP_CHK_GEN(sizeofW(StgArrWords)+1, NO_PTRS, decodeFloatzh_fast,);
+ HP_CHK_GEN_TICKY(sizeofW(StgArrWords)+1, NO_PTRS, decodeFloatzh_fast,);
TICK_ALLOC_PRIM(sizeofW(StgArrWords),1,0);
CCS_ALLOC(CCCS,sizeofW(StgArrWords)+1); /* ccs prof */
/* arguments: D1 = Double# */
arg = D1;
- HP_CHK_GEN(ARR_SIZE, NO_PTRS, decodeDoublezh_fast,);
+ HP_CHK_GEN_TICKY(ARR_SIZE, NO_PTRS, decodeDoublezh_fast,);
TICK_ALLOC_PRIM(sizeofW(StgArrWords),DOUBLE_MANTISSA_SIZE,0);
CCS_ALLOC(CCCS,ARR_SIZE); /* ccs prof */
/* create it right now, return ThreadID in R1 */
R1.t = RET_STGCALL2(StgTSO *, createIOThread,
RtsFlags.GcFlags.initialStkSize, R1.cl);
+ STGCALL1(scheduleThread, R1.t);
/* switch at the earliest opportunity */
context_switch = 1;
FE_
}
-FN_(killThreadzh_fast)
-{
- FB_
- /* args: R1.p = TSO to kill, R2.p = Exception */
-
- /* The thread is dead, but the TSO sticks around for a while. That's why
- * we don't have to explicitly remove it from any queues it might be on.
- */
-
- /* We might have killed ourselves. In which case, better be *very*
- * careful. If the exception killed us, then return to the scheduler.
- * If the exception went to a catch frame, we'll just continue from
- * the handler.
- */
- if (R1.t == CurrentTSO) {
- SaveThreadState(); /* inline! */
- STGCALL2(raiseAsync, R1.t, R2.cl);
- if (CurrentTSO->whatNext == ThreadKilled) {
- R1.w = ThreadYielding;
- JMP_(StgReturn);
- }
- LoadThreadState();
- if (CurrentTSO->whatNext == ThreadEnterGHC) {
- R1.w = Sp[0];
- Sp++;
- JMP_(GET_ENTRY(R1.cl));
- } else {
- barf("killThreadzh_fast");
- }
- } else {
- STGCALL2(raiseAsync, R1.t, R2.cl);
- }
-
- JMP_(ENTRY_CODE(Sp[0]));
- FE_
-}
-
FN_(newMVarzh_fast)
{
StgMVar *mvar;
FB_
/* args: none */
- HP_CHK_GEN(sizeofW(StgMVar), NO_PTRS, newMVarzh_fast,);
+ HP_CHK_GEN_TICKY(sizeofW(StgMVar), NO_PTRS, newMVarzh_fast,);
TICK_ALLOC_PRIM(sizeofW(StgMutVar)-1, // consider head,tail,link as admin wds
1, 0);
CCS_ALLOC(CCCS,sizeofW(StgMVar)); /* ccs prof */
{
StgMVar *mvar;
StgClosure *val;
+ const StgInfoTable *info;
FB_
/* args: R1 = MVar closure */
mvar = (StgMVar *)R1.p;
+#ifdef SMP
+ info = LOCK_CLOSURE(mvar);
+#else
+ info = GET_INFO(mvar);
+#endif
+
/* If the MVar is empty, put ourselves on its blocking queue,
* and wait until we're woken up.
*/
- if (GET_INFO(mvar) != &FULL_MVAR_info) {
+ if (info == &EMPTY_MVAR_info) {
if (mvar->head == (StgTSO *)&END_TSO_QUEUE_closure) {
mvar->head = CurrentTSO;
} else {
CurrentTSO->block_info.closure = (StgClosure *)mvar;
mvar->tail = CurrentTSO;
+#ifdef SMP
+ /* unlock the MVar */
+ mvar->header.info = &EMPTY_MVAR_info;
+#endif
BLOCK(R1_PTR, takeMVarzh_fast);
}
- SET_INFO(mvar,&EMPTY_MVAR_info);
val = mvar->value;
mvar->value = (StgClosure *)&END_TSO_QUEUE_closure;
+ /* do this last... we might have locked the MVar in the SMP case,
+ * and writing the info pointer will unlock it.
+ */
+ SET_INFO(mvar,&EMPTY_MVAR_info);
+
TICK_RET_UNBOXED_TUP(1);
RET_P(val);
FE_
FN_(putMVarzh_fast)
{
StgMVar *mvar;
+ const StgInfoTable *info;
FB_
/* args: R1 = MVar, R2 = value */
mvar = (StgMVar *)R1.p;
- if (GET_INFO(mvar) == &FULL_MVAR_info) {
- fprintf(stderr, "putMVar#: MVar already full.\n");
- stg_exit(EXIT_FAILURE);
+
+#ifdef SMP
+ info = LOCK_CLOSURE(mvar);
+#else
+ info = GET_INFO(mvar);
+#endif
+
+ if (info == &FULL_MVAR_info) {
+#ifdef INTERPRETER
+ fprintf(stderr, "fatal: put on a full MVar in Hugs; aborting\n" );
+ exit(1);
+#else
+ R1.cl = (StgClosure *)PutFullMVar_closure;
+ JMP_(raisezh_fast);
+#endif
}
- SET_INFO(mvar,&FULL_MVAR_info);
mvar->value = R2.cl;
/* wake up the first thread on the queue, it will continue with the
*/
if (mvar->head != (StgTSO *)&END_TSO_QUEUE_closure) {
ASSERT(mvar->head->why_blocked == BlockedOnMVar);
+#if defined(GRAN)
+ mvar->head = RET_STGCALL2(StgTSO *,unblockOne,mvar->head,mvar);
+#elif defined(PAR)
+ // ToDo: check 2nd arg (mvar) is right
+ mvar->head = RET_STGCALL2(StgTSO *,unblockOne,mvar->head,mvar);
+#else
mvar->head = RET_STGCALL1(StgTSO *,unblockOne,mvar->head);
+#endif
if (mvar->head == (StgTSO *)&END_TSO_QUEUE_closure) {
mvar->tail = (StgTSO *)&END_TSO_QUEUE_closure;
}
}
+ /* unlocks the MVar in the SMP case */
+ SET_INFO(mvar,&FULL_MVAR_info);
+
/* ToDo: yield here for better communication performance? */
JMP_(ENTRY_CODE(Sp[0]));
FE_
StgStableName *sn_obj;
FB_
- HP_CHK_GEN(sizeofW(StgStableName), R1_PTR, makeStableNamezh_fast,);
+ HP_CHK_GEN_TICKY(sizeofW(StgStableName), R1_PTR, makeStableNamezh_fast,);
TICK_ALLOC_PRIM(sizeofW(StgHeader),
sizeofW(StgStableName)-sizeofW(StgHeader), 0);
CCS_ALLOC(CCCS,sizeofW(StgStableName)); /* ccs prof */
ASSERT(CurrentTSO->why_blocked == NotBlocked);
CurrentTSO->why_blocked = BlockedOnRead;
CurrentTSO->block_info.fd = R1.i;
- PUSH_ON_BLOCKED_QUEUE(CurrentTSO);
+ ACQUIRE_LOCK(&sched_mutex);
+ APPEND_TO_BLOCKED_QUEUE(CurrentTSO);
+ RELEASE_LOCK(&sched_mutex);
JMP_(stg_block_noregs);
FE_
}
ASSERT(CurrentTSO->why_blocked == NotBlocked);
CurrentTSO->why_blocked = BlockedOnWrite;
CurrentTSO->block_info.fd = R1.i;
- PUSH_ON_BLOCKED_QUEUE(CurrentTSO);
+ ACQUIRE_LOCK(&sched_mutex);
+ APPEND_TO_BLOCKED_QUEUE(CurrentTSO);
+ RELEASE_LOCK(&sched_mutex);
JMP_(stg_block_noregs);
FE_
}
ASSERT(CurrentTSO->why_blocked == NotBlocked);
CurrentTSO->why_blocked = BlockedOnDelay;
+ ACQUIRE_LOCK(&sched_mutex);
+
/* Add on ticks_since_select, since these will be subtracted at
* the next awaitEvent call.
*/
CurrentTSO->block_info.delay = R1.i + ticks_since_select;
- PUSH_ON_BLOCKED_QUEUE(CurrentTSO);
+ APPEND_TO_BLOCKED_QUEUE(CurrentTSO);
+
+ RELEASE_LOCK(&sched_mutex);
JMP_(stg_block_noregs);
FE_
}
-#endif /* COMPILER */