[project @ 1998-12-02 13:17:09 by simonm]
[ghc-hetmet.git] / ghc / runtime / c-as-asm / StablePtr.lc
diff --git a/ghc/runtime/c-as-asm/StablePtr.lc b/ghc/runtime/c-as-asm/StablePtr.lc
deleted file mode 100644 (file)
index 749cd37..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-\section[Stable-Pointers]{Creation and use of Stable Pointers}
-
-\begin{code}
-#if !defined(PAR)
-
-#include "rtsdefs.h"
-\end{code}
-
-This files (together with @ghc/runtime/storage/PerformIO.lhc@ and a
-small change in @HpOverflow.lc@) consists of the changes in the
-runtime system required to implement "Stable Pointers". But we're
-getting a bit ahead of ourselves --- what is a stable pointer and what
-is it used for?
-
-When Haskell calls C, it normally just passes over primitive integers,
-floats, bools, strings, etc.  This doesn't cause any problems at all
-for garbage collection because the act of passing them makes a copy
-from the heap, stack or wherever they are onto the C-world stack.
-However, if we were to pass a heap object such as a (Haskell) @String@
-and a garbage collection occured before we finished using it, we'd run
-into problems since the heap object might have been moved or even
-deleted.
-
-So, if a C call is able to cause a garbage collection or we want to
-store a pointer to a heap object between C calls, we must be careful
-when passing heap objects. Our solution is to keep a table of all
-objects we've given to the C-world and to make sure that the garbage
-collector collects these objects --- updating the table as required to
-make sure we can still find the object.
-
-
-Of course, all this rather begs the question: why would we want to
-pass a boxed value?
-
-One very good reason is to preserve laziness across the language
-interface. Rather than evaluating an integer or a string because it
-{\em might\/} be required by the C function, we can wait until the C
-function actually wants the value and then force an evaluation.
-
-Another very good reason (the motivating reason!) is that the C code
-might want to execute an object of sort $IO ()$ for the side-effects
-it will produce. For example, this is used when interfacing to an X
-widgets library to allow a direct implementation of callbacks.
-
-
-The @makeStablePointer# :: a -> PrimIO (StablePtr a)@ function
-converts a value into a stable pointer.  It is part of the @PrimIO@
-monad, because we want to be sure we don't allocate one twice by
-accident, and then only free one of the copies.
-
-\begin{verbatim}
-makeStablePointer#  :: a -> State# _RealWorld -> StateAndStablePtr# _RealWorld a
-freeStablePointer#  :: StablePtr# a -> State# _RealWorld -> State# _RealWorld
-deRefStablePointer# :: StablePtr# a -> State# _RealWorld -> StateAndPtr _RealWorld a
-\end{verbatim}
-There is also a C procedure @FreeStablePtr@ which frees a stable pointer.
-
-There may be additional functions on the C side to allow evaluation,
-application, etc of a stable pointer.
-
-\begin{code}
-EXTDATA(UnusedSP_closure);
-EXTDATA(EmptySPTable_closure);
-
-void
-enlargeSPTable( newTable, oldTable )
-  StgPtr newTable;
-  StgPtr oldTable;
-{
-  StgInt OldNoPtrs = SPT_NoPTRS(oldTable);
-  StgInt NewNoPtrs = SPT_NoPTRS(newTable);
-  StgInt i, NewTop;
-
-  ASSERT( NewNoPtrs > OldNoPtrs );
-  ASSERT( SPT_TOP(oldTable) == 0 );
-
-  CHECK_SPT_CLOSURE(oldTable);
-
-  /* Copy old stable pointers over */
-  for( i = 0; i < OldNoPtrs; ++i ) {
-    SPT_SPTR(newTable, i) = SPT_SPTR(oldTable,i);
-  }
-  /* Top up with unused stable pointers */
-  for( i = OldNoPtrs; i < NewNoPtrs; ++i ) {
-    SPT_SPTR(newTable, i) = UnusedSP_closure;
-  }
-
-  /* Setup free stack with indices of new stable pointers*/
-  NewTop = 0;
-  for( i = OldNoPtrs; i < NewNoPtrs; ++i ) {
-    SPT_FREE(newTable, NewTop++) = i;
-  }
-  SPT_TOP(newTable) = NewTop;
-
-  StorageMgrInfo.StablePointerTable = newTable;
-
-#if defined(DEBUG)
-  /* Now trash the old table to encourage bugs to show themselves */
-  if ( oldTable != EmptySPTable_closure ) { 
-    I_ size = SPT_SIZE(oldTable) + _FHS;
-
-    for( i = 0; i != size; ++i ) {
-      oldTable[ i ] = DEALLOCATED_TRASH;
-    }
-  }
-#endif     
-
-  CHECK_SPT_CLOSURE(newTable);
-}
-\end{code}
-
-
-There are a lot of checks in here.  However, they are not to catch
-bugs in the compiler - they are to catch bugs in the users program.
-
-ToDo: maybe have a compiler switch to be less paranoid? [ADR]
-
-\begin{code}
-EXTDATA(UnusedSP_closure);
-
-void
-freeStablePointer(stablePtr)
-  I_ stablePtr;
-{
-  P_ SPTable = StorageMgrInfo.StablePointerTable;
-
-  /* Check what we can of tables integrity - can't check infotable
-     since we may be in a GC and (compacting) GC may have mangled it. */
-  CHECK_SPT_Size(SPTable);
-  CHECK_SPT_Contents(SPTable);
-
-  if (! (0 <= stablePtr && stablePtr < SPT_NoPTRS(SPTable)) ) { /* bogus index */
-    /* This can only happen if the Haskell/C programmer has really messed up. */
-   
-    fprintf(stderr, "Panic (freeStablePointer): stable pointer %ld not in range 0..%ld.\n",
-           stablePtr, SPT_NoPTRS(SPTable)-1);
-    abort();
-  }
-
-  if (SPT_SPTR(SPTable,stablePtr) == UnusedSP_closure) { /* freeing an unused stable pointer */
-    /* This can only happen if the Haskell/C programmer has already
-       returned the same stable pointer or never allocated it. */
-   
-    fprintf(stderr, "Panic: stable pointer %ld freed multiple times (or never allocated)\nby the Haskell/C programmer.\n", stablePtr);
-    EXIT(EXIT_FAILURE); /* ToDo: abort()? */
-  }
-
-  if (SPT_FULL(SPTable)) { /* free stack full! */
-    /* This can only happen if the Haskell/C programmer has returned
-       the same stable pointer several times.
-     */
-   
-    fprintf(stderr, "Panic: stable pointer free stack overflowed.\nThis is probably due to the same stable pointer being freed multiple times\nby the Haskell/C programmer.\n");
-    EXIT(EXIT_FAILURE); /* ToDo: abort()? */
-  }
-
-  SPT_SPTR(SPTable,stablePtr) = UnusedSP_closure; /* erase old entry */
-  SPT_PUSH(SPTable,stablePtr);                   /* Add it to free stack */  
-
-  CHECK_SPT_Size(SPTable);
-  CHECK_SPT_Contents(SPTable);
-}
-\end{code}
-
-\begin{code}
-StgPtr
-_deRefStablePointer(stablePtr,SPTable)
-  StgInt stablePtr;
-  StgPtr SPTable;
-{
-  CHECK_SPT_CLOSURE(SPTable);
-
-  if (! (0 <= stablePtr && stablePtr < SPT_NoPTRS(SPTable)) ) { /* bogus index */
-    /* This can only happen if the Haskell/C programmer has really messed up. */
-   
-    fprintf(stderr, "Panic (deRefStablePointer): stable pointer %ld not in range 0..%ld.\n",
-           stablePtr, SPT_NoPTRS(SPTable)-1);
-    EXIT(EXIT_FAILURE); /* ToDo: abort()? */
-  }
-
-  if (SPT_SPTR(SPTable,stablePtr) == UnusedSP_closure) { /* dereferencing an unused stable pointer */
-    /* This can only happen if the Haskell/C programmer has already
-       returned this stable pointer. */
-   
-    fprintf(stderr, "Panic: stable pointer %ld not allocated by the Haskell/C programmer.\n", stablePtr);
-    EXIT(EXIT_FAILURE); /* ToDo: abort()? */
-  }
-
-  return SPT_SPTR(SPTable,stablePtr);
-}
-\end{code}
-
-For error detecting in the debug version, we have a check that all
-free pointers are really free and all non-free pointers are really not
-free.
-
-\begin{code}
-#ifdef DEBUG
-int ValidateSPTable( P_ SPTable )
-{
-  I_ i, j;
-  I_ NoPtrs = SPT_NoPTRS( SPTable );
-  I_ Top = SPT_TOP( SPTable );
-
-  for( i = 0; i != Top; ++i ) {
-    /* Check the free indexes are in range */
-    if (!( (0 <= SPT_FREE( SPTable, i )) && (SPT_FREE( SPTable, i ) < NoPtrs) ) ) return 1;
-    /* Check the free indexes are unused */
-    if ( SPT_SPTR( SPTable, SPT_FREE( SPTable, i ) ) != UnusedSP_closure ) return 2;
-  }
-
-  /* Check each unused stable pointer is in free list (and vice-versa) */
-  for( i = 0; i != NoPtrs; i++ ) {
-    if ( SPT_SPTR( SPTable, i ) == UnusedSP_closure ) {
-      j = 0;
-      while (j != Top && SPT_FREE( SPTable, j ) != i) {
-       j++;
-      }
-      if (j == Top) return 3; /* Space leak - losing free SPs */
-    } else {
-      j = Top;
-      while (j != NoPtrs && SPT_FREE( SPTable, j ) != i) {
-       j++;
-      }
-    }
-  }    
-
-  /* If all that worked, we've got a good structure here */
-  return 0;
-}
-#endif /* DEBUG */
-
-#endif /* ! PAR */
-\end{code}