summaryrefslogtreecommitdiff
path: root/rts/Sparks.h
blob: e2c60e96251d54d1200b2f7ad626aa9b39455c35 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/* -----------------------------------------------------------------------------
 *
 * (c) The GHC Team, 2000-2006
 *
 * Sparking support for GRAN, PAR and THREADED_RTS versions of the RTS.
 * 
 * ---------------------------------------------------------------------------*/

#ifndef SPARKS_H
#define SPARKS_H

#if defined(PARALLEL_HASKELL)
#error Sparks.c using new internal structure, needs major overhaul!
#endif

/* typedef for SparkPool in RtsTypes.h */

#if defined(THREADED_RTS)

/* Spark pools: used to store pending sparks 
 *  (THREADED_RTS & PARALLEL_HASKELL only)
 * Implementation uses a DeQue to enable concurrent read accesses at
 * the top end.
 */
typedef struct  SparkPool_ {
  /* Size of elements array. Used for modulo calculation: we round up
     to powers of 2 and use the dyadic log (modulo == bitwise &) */
  StgWord size; 
  StgWord moduloSize; /* bitmask for modulo */

  /* top, index where multiple readers steal() (protected by a cas) */
  volatile StgWord top;

  /* bottom, index of next free place where one writer can push
     elements. This happens unsynchronised. */
  volatile StgWord bottom;
  /* both position indices are continuously incremented, and used as
     an index modulo the current array size. */
  
  /* lower bound on the current top value. This is an internal
     optimisation to avoid unnecessarily accessing the top field
     inside pushBottom */
  volatile StgWord topBound;

  /* The elements array */
  StgClosurePtr* elements;
  /*  Please note: the dataspace cannot follow the admin fields
      immediately, as it should be possible to enlarge it without
      disposing the old one automatically (as realloc would)! */

} SparkPool;


/* INVARIANTS, in this order: reasonable size,
   topBound consistent, space pointer, space accessible to us.
   
   NB. This is safe to use only (a) on a spark pool owned by the
   current thread, or (b) when there's only one thread running, or no
   stealing going on (e.g. during GC).
*/
#define ASSERT_SPARK_POOL_INVARIANTS(p)         \
  ASSERT((p)->size > 0);                        \
  ASSERT((p)->topBound <= (p)->top);            \
  ASSERT((p)->elements != NULL);                \
  ASSERT(*((p)->elements) || 1);                \
  ASSERT(*((p)->elements - 1  + ((p)->size)) || 1);

// No: it is possible that top > bottom when using reclaimSpark()
//  ASSERT((p)->bottom >= (p)->top);           
//  ASSERT((p)->size > (p)->bottom - (p)->top);

// Initialisation
void initSparkPools (void);

// Take a spark from the "write" end of the pool.  Can be called
// by the pool owner only.
StgClosure* reclaimSpark(SparkPool *pool);

// Returns True if the spark pool is empty (can give a false positive
// if the pool is almost empty).
rtsBool looksEmpty(SparkPool* deque);

StgClosure * tryStealSpark     (Capability *cap);
void         freeSparkPool     (SparkPool *pool);
void         createSparkThread (Capability *cap);
void         traverseSparkQueue(evac_fn evac, void *user, Capability *cap);
void         pruneSparkQueue   (evac_fn evac, void *user, Capability *cap);

INLINE_HEADER void discardSparks  (SparkPool *pool);
INLINE_HEADER nat  sparkPoolSize  (SparkPool *pool);
#endif

/* -----------------------------------------------------------------------------
 * PRIVATE below here
 * -------------------------------------------------------------------------- */

#if defined(PARALLEL_HASKELL) || defined(THREADED_RTS)

INLINE_HEADER rtsBool  
emptySparkPool (SparkPool *pool) 
{ return looksEmpty(pool); }

INLINE_HEADER nat
sparkPoolSize (SparkPool *pool) 
{ return (pool->bottom - pool->top); }

INLINE_HEADER void
discardSparks (SparkPool *pool)
{
    pool->top = pool->bottom;
//    pool->topBound = pool->top;
}

#endif

#endif /* SPARKS_H */