Ticket #7606: 0001-Red-black-trees-27-no-sleeper-fairness-copy-of-22.patch

File 0001-Red-black-trees-27-no-sleeper-fairness-copy-of-22.patch, 41.5 KB (added by ezyang, 4 months ago)

Red-black tree implementation version 27

  • includes/RtsAPI.h

    From 441dfe32b93c67ed3eb22d502382aab3910a3d9d Mon Sep 17 00:00:00 2001
    From: "Edward Z. Yang" <ezyang@mit.edu>
    Date: Sat, 26 Jan 2013 06:46:23 -0800
    Subject: [PATCH] Red-black trees 27 - no sleeper fairness (copy of 22)
    
    Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
    ---
     includes/RtsAPI.h           |    2 +
     includes/rts/storage/TSO.h  |    1 +
     includes/stg/MiscClosures.h |    2 +
     rts/Capability.c            |   13 +-
     rts/Capability.h            |   15 +-
     rts/RBTree.c                |  521 +++++++++++++++++++++++++++++++++++++++++++
     rts/RBTree.h                |   90 ++++++++
     rts/Schedule.c              |   28 +--
     rts/Schedule.h              |  115 +++++++---
     rts/StgMiscClosures.cmm     |    5 +
     rts/Threads.c               |    3 +
     rts/sm/Sanity.c             |    4 +-
     12 files changed, 734 insertions(+), 65 deletions(-)
     create mode 100644 rts/RBTree.c
     create mode 100644 rts/RBTree.h
    
    diff --git a/includes/RtsAPI.h b/includes/RtsAPI.h
    index ca87662..0ccd8aa 100644
    a b  
    3737 */ 
    3838typedef struct Capability_ Capability; 
    3939 
     40typedef struct StgRB_ StgRB; 
     41 
    4042/* 
    4143 * The public view of a Capability: we can be sure it starts with 
    4244 * these two components (but it may have more private fields). 
  • includes/rts/storage/TSO.h

    diff --git a/includes/rts/storage/TSO.h b/includes/rts/storage/TSO.h
    index 20a67a2..eb0f06b 100644
    a b  
    257257 
    258258/* this is the NIL ptr for a TSO queue (e.g. runnable queue) */ 
    259259#define END_TSO_QUEUE  ((StgTSO *)(void*)&stg_END_TSO_QUEUE_closure) 
     260#define RB_NULL        ((StgRB *)(void*)&stg_RB_NULL_closure) 
    260261 
    261262#endif /* RTS_STORAGE_TSO_H */ 
  • includes/stg/MiscClosures.h

    diff --git a/includes/stg/MiscClosures.h b/includes/stg/MiscClosures.h
    index e6d5fcd..31f18af 100644
    a b  
    114114RTS_ENTRY(stg_MUT_VAR_CLEAN); 
    115115RTS_ENTRY(stg_MUT_VAR_DIRTY); 
    116116RTS_ENTRY(stg_END_TSO_QUEUE); 
     117RTS_ENTRY(stg_RB_NULL); 
    117118RTS_ENTRY(stg_MSG_TRY_WAKEUP); 
    118119RTS_ENTRY(stg_MSG_THROWTO); 
    119120RTS_ENTRY(stg_MSG_BLACKHOLE); 
     
    142143/* closures */ 
    143144 
    144145RTS_CLOSURE(stg_END_TSO_QUEUE_closure); 
     146RTS_CLOSURE(stg_RB_NULL_closure); 
    145147RTS_CLOSURE(stg_NO_FINALIZER_closure); 
    146148RTS_CLOSURE(stg_dummy_ret_closure); 
    147149RTS_CLOSURE(stg_forceIO_closure); 
  • rts/Capability.c

    diff --git a/rts/Capability.c b/rts/Capability.c
    index 811df58..2839891 100644
    a b  
    2626#include "sm/GC.h" // for gcWorkerThread() 
    2727#include "STM.h" 
    2828#include "RtsUtils.h" 
     29#include "RBTree.h" 
    2930 
    3031#include <string.h> 
    3132 
     
    230231    cap->idle              = 0; 
    231232    cap->disabled          = rtsFalse; 
    232233 
    233     cap->run_queue_hd      = END_TSO_QUEUE; 
    234     cap->run_queue_tl      = END_TSO_QUEUE; 
     234    cap->promoted_run_queue_hd = END_TSO_QUEUE; 
    235235 
    236236#if defined(THREADED_RTS) 
    237237    initMutex(&cap->lock); 
     
    282282    cap->r.rCCCS = NULL; 
    283283#endif 
    284284 
     285    cap->rb_free_list      = RB_NULL; 
     286    cap->run_count         = 0; 
     287    cap->run_rbtree        = rbCreateNode(cap, END_TSO_QUEUE); 
     288    cap->run_active        = cap->run_rbtree; 
     289 
    285290    traceCapCreate(cap); 
    286291    traceCapsetAssignCap(CAPSET_OSPROCESS_DEFAULT, i); 
    287292    traceCapsetAssignCap(CAPSET_CLOCKDOMAIN_DEFAULT, i); 
     
    10071012    // or fewer Capabilities as GC threads, but just in case there 
    10081013    // are more, we mark every Capability whose number is the GC 
    10091014    // thread's index plus a multiple of the number of GC threads. 
    1010     evac(user, (StgClosure **)(void *)&cap->run_queue_hd); 
    1011     evac(user, (StgClosure **)(void *)&cap->run_queue_tl); 
     1015    evac(user, (StgClosure **)(void *)&cap->promoted_run_queue_hd); 
     1016    rbEvacuate(evac, user, cap->run_rbtree); 
    10121017#if defined(THREADED_RTS) 
    10131018    evac(user, (StgClosure **)(void *)&cap->inbox); 
    10141019#endif 
  • rts/Capability.h

    diff --git a/rts/Capability.h b/rts/Capability.h
    index 81322c8..ae320c8 100644
    a b  
    5555    // access to its run queue, so can wake up threads without 
    5656    // taking a lock, and the common path through the scheduler is 
    5757    // also lock-free. 
    58     StgTSO *run_queue_hd; 
    59     StgTSO *run_queue_tl; 
     58    StgTSO *promoted_run_queue_hd; 
     59    // XXX move StgRB somewhere not RBTree.h to break circular dep 
     60    StgRB *run_rbtree; 
     61    StgRB *run_active; // cached pointer to min red-black tree element 
     62    StgRB *rb_free_list; // free list of RBNodes 
     63    nat run_count; 
    6064 
    6165    // [SSS] Stride scheduling extensions.  The Task with this 
    6266    // Capability has exclusive access to this variable. 
     
    153157// These properties should be true when a Task is holding a Capability 
    154158#define ASSERT_FULL_CAPABILITY_INVARIANTS(cap,task)                     \ 
    155159  ASSERT(cap->running_task != NULL && cap->running_task == task);       \ 
     160  ASSERT((cap->run_rbtree == RB_NULL) == (cap->run_active == RB_NULL)); \ 
     161  ASSERT((cap->run_active == RB_NULL && cap->run_rbtree == RB_NULL) ||\ 
     162         (RB_HEAD_GET(cap->run_active) != END_TSO_QUEUE && RB_TAIL_GET(cap->run_active) != END_TSO_QUEUE) || \ 
     163         (RB_HEAD_GET(cap->run_active) == END_TSO_QUEUE && RB_TAIL_GET(cap->run_active) == END_TSO_QUEUE && \ 
     164            RB_LEFT_GET(cap->run_active) == RB_NULL && RB_RIGHT_GET(cap->run_active) == RB_NULL));\ 
    156165  ASSERT(task->cap == cap);                                             \ 
    157166  ASSERT_PARTIAL_CAPABILITY_INVARIANTS(cap,task) 
    158167 
     
    162171// Task is bound, its thread has just blocked, and it may have been 
    163172// moved to another Capability. 
    164173#define ASSERT_PARTIAL_CAPABILITY_INVARIANTS(cap,task)  \ 
    165   ASSERT(cap->run_queue_hd == END_TSO_QUEUE ?           \ 
    166             cap->run_queue_tl == END_TSO_QUEUE : 1);    \ 
    167174  ASSERT(myTask() == task);                             \ 
    168175  ASSERT_TASK_ID(task); 
    169176 
  • (a) /dev/null vs. (b) b/rts/RBTree.c

    diff --git a/rts/RBTree.c b/rts/RBTree.c
    new file mode 100644
    index 0000000..13170f8
    a b  
     1/* ----------------------------------------------------------------------------- 
     2 * 
     3 * (c) The GHC Team, 2013 
     4 * 
     5 * Red-black trees 
     6 * 
     7 * The core algorithm is based off of jemalloc's red-black tree 
     8 * implementation <http://www.canonware.com/rb/>, which has the following license: 
     9 * 
     10 * Copyright (C) 2002-2012 Jason Evans <jasone@canonware.com>. All rights reserved. 
     11 * Copyright (C) 2007-2012 Mozilla Foundation.  All rights reserved. 
     12 * Copyright (C) 2009-2012 Facebook, Inc.  All rights reserved. 
     13 
     14 * Redistribution and use in source and binary forms, with or without 
     15 * modification, are permitted provided that the following conditions are met: 
     16 * 1. Redistributions of source code must retain the above copyright notice(s), 
     17 *    this list of conditions and the following disclaimer. 
     18 * 2. Redistributions in binary form must reproduce the above copyright notice(s), 
     19 *    this list of conditions and the following disclaimer in the documentation 
     20 *    and/or other materials provided with the distribution. 
     21 
     22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS 
     23 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
     24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO 
     25 * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 
     26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
     27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
     28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
     29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
     30 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
     31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
     32 * 
     33 * ---------------------------------------------------------------------------*/ 
     34 
     35#include "PosixSource.h" 
     36#include "Rts.h" 
     37 
     38#include "RtsUtils.h" 
     39#include "RBTree.h" 
     40 
     41STATIC_INLINE StgRB* 
     42rbRotateLeft(Capability *cap, StgRB *a) { 
     43    ASSERT(a != RB_NULL); 
     44    StgRB *r = RB_RIGHT_GET(a); 
     45    ASSERT(r != RB_NULL); 
     46    RB_RIGHT_SET(cap, a, RB_LEFT_GET(r)); 
     47    RB_LEFT_SET(cap, r, a); 
     48    return r; 
     49} 
     50 
     51STATIC_INLINE StgRB* 
     52rbRotateRight(Capability *cap, StgRB *a) { 
     53    ASSERT(a != RB_NULL); 
     54    StgRB *l = RB_LEFT_GET(a); 
     55    ASSERT(l != RB_NULL); 
     56    RB_LEFT_SET(cap, a, RB_RIGHT_GET(l)); 
     57    RB_RIGHT_SET(cap, l, a); 
     58    return l; 
     59} 
     60 
     61int 
     62checkRBTree(StgRB *r, int forceBlack, int count, int expected) 
     63{ 
     64    if (r == RB_NULL) { 
     65        ASSERT(expected == -1 || count == expected); 
     66        ASSERT(count != 0); 
     67        return count; 
     68    } 
     69    ASSERT(LOOKS_LIKE_CLOSURE_PTR(RB_LEFT_GET(r))); 
     70    ASSERT(LOOKS_LIKE_CLOSURE_PTR(RB_RIGHT_GET(r))); 
     71    ASSERT(LOOKS_LIKE_CLOSURE_PTR(RB_HEAD_GET(r))); 
     72    ASSERT(LOOKS_LIKE_CLOSURE_PTR(RB_TAIL_GET(r))); 
     73    if (count == 0) { 
     74        // this corresponds to "fast path" empty node 
     75        if (RB_HEAD_GET(r) == END_TSO_QUEUE) { 
     76            ASSERT(RB_LEFT_GET(r) == RB_NULL); 
     77            ASSERT(RB_RIGHT_GET(r) == RB_NULL); 
     78            ASSERT(RB_TAIL_GET(r) == END_TSO_QUEUE); 
     79            ASSERT(RB_IS_BLACK(r)); 
     80        } 
     81        return 0; 
     82    } else { 
     83        ASSERT(RB_HEAD_GET(r) != END_TSO_QUEUE); 
     84        ASSERT(RB_TAIL_GET(r) != END_TSO_QUEUE); 
     85    } 
     86    ASSERT(LOOKS_LIKE_CLOSURE_PTR(RB_COLOR_GET(r))); 
     87    ASSERT(RB_COLOR_GET(r) == RB_RED || RB_COLOR_GET(r) == RB_BLACK); 
     88    if (forceBlack) { 
     89        ASSERT(RB_IS_BLACK(r)); 
     90    } 
     91    if (RB_IS_BLACK(r)) { 
     92        count++; 
     93    } 
     94    expected = checkRBTree(RB_LEFT_GET(r), RB_IS_RED(r), count, expected); 
     95    checkRBTree(RB_RIGHT_GET(r), RB_IS_RED(r), count, expected); 
     96    return expected; 
     97} 
     98 
     99void 
     100rbEvacuate(evac_fn evac, void *user, StgRB* r) { 
     101    if (r == RB_NULL) return; 
     102    evac(user, (StgClosure **)(void *)&r->head); 
     103    evac(user, (StgClosure **)(void *)&r->tail); 
     104    rbEvacuate(evac, user, r->left); 
     105    rbEvacuate(evac, user, r->right); // XXX maybe manually TCO this 
     106} 
     107 
     108// this function assumes you've checked for fastpath 
     109StgRB* 
     110rbInsert(Capability *cap, StgRB **root, StgTSO *tso) { 
     111    struct { 
     112        StgRB *node; 
     113        int cmp; 
     114    } path[sizeof(void *) << 4], *pathp; 
     115    path->node = *root; 
     116    int found = 0; 
     117    // Wind 
     118    for (pathp = path; pathp->node != RB_NULL; pathp++) { 
     119        ASSERT(RB_HEAD_GET(pathp->node) != END_TSO_QUEUE); // e.g. root is NOT a fast path empty node 
     120        ASSERT(RB_TAIL_GET(pathp->node) != END_TSO_QUEUE); 
     121        StgWord64 pass = RB_HEAD_GET(pathp->node)->ss_pass; 
     122        int cmp = pathp->cmp = (tso->ss_pass > pass) - (tso->ss_pass < pass); 
     123        if (cmp < 0) { 
     124            pathp[1].node = RB_LEFT_GET(pathp->node); 
     125        } else if (cmp == 0) { 
     126            found = 1; 
     127            break; 
     128        } else { 
     129            pathp[1].node = RB_RIGHT_GET(pathp->node); 
     130        } 
     131    } 
     132    if (found) { // O(n log n) pointer traverals but only O(1) edits 
     133        ASSERT(pathp->node != RB_NULL); 
     134        ASSERT(RB_HEAD_GET(pathp->node) != END_TSO_QUEUE); 
     135        setTSOLink(cap, RB_TAIL_GET(pathp->node), tso); 
     136        RB_TAIL_SET(cap, pathp->node, tso); 
     137        return pathp->node; 
     138    } 
     139    StgRB *node = rbCreateNode(cap, tso); 
     140    pathp->node = node; 
     141    // Unwind 
     142    for (pathp--; (void*)pathp >= (void*)path; pathp--) { 
     143        StgRB *cnode = pathp->node; 
     144        ASSERT(cnode != RB_NULL); 
     145        ASSERT(pathp->cmp != 0); 
     146        if (pathp->cmp < 0) { 
     147            StgRB *left = pathp[1].node; 
     148            RB_LEFT_SET(cap, cnode, left); 
     149            if (RB_IS_RED(left)) { 
     150                StgRB *leftleft = RB_LEFT_GET(left); 
     151                if (RB_IS_RED(leftleft)) { 
     152                    // fix up 4-node 
     153                    StgRB *tnode; 
     154                    RB_COLOR_BLACK(cap, leftleft); 
     155                    tnode = rbRotateRight(cap, cnode); 
     156                    cnode = tnode; 
     157                } 
     158            } else { 
     159                return node; 
     160            } 
     161        } else { 
     162            StgRB *right = pathp[1].node; 
     163            RB_RIGHT_SET(cap, cnode, right); 
     164            if (RB_IS_RED(right)) { 
     165                StgRB *left = RB_LEFT_GET(cnode); 
     166                if (RB_IS_RED(left)) { 
     167                    // split 4-node 
     168                    RB_COLOR_BLACK(cap, left); 
     169                    RB_COLOR_BLACK(cap, right); 
     170                    RB_COLOR_RED(cap, cnode); 
     171                } else { 
     172                    // lean left 
     173                    StgRB *tnode; 
     174                    StgClosure *tred = RB_COLOR_GET(cnode); 
     175                    tnode = rbRotateLeft(cap, cnode); 
     176                    RB_COLOR_SET(cap, tnode, tred); 
     177                    RB_COLOR_RED(cap, cnode); 
     178                    cnode = tnode; 
     179                } 
     180            } else { 
     181                return node; 
     182            } 
     183        } 
     184        pathp->node = cnode; 
     185    } 
     186    *root = path->node; 
     187    RB_COLOR_BLACK(cap, *root); 
     188    return node; 
     189} 
     190 
     191// this function assumes you've checked for fastpath 
     192StgTSO* 
     193rbRemoveMin(Capability *cap, StgRB **root) { 
     194    struct { 
     195        StgRB *node; 
     196        int cmp; 
     197    } path[sizeof(void *) << 4], *pathp, *nodep; 
     198    // Wind 
     199    nodep = NULL; 
     200    path->node = *root; 
     201    for (pathp = path; pathp->node != RB_NULL; pathp++) { 
     202        ASSERT(RB_HEAD_GET(pathp->node) != END_TSO_QUEUE); // e.g. fast path is NOT in effect 
     203        ASSERT(RB_TAIL_GET(pathp->node) != END_TSO_QUEUE); 
     204        StgRB *left = RB_LEFT_GET(pathp->node); 
     205        if (left != RB_NULL) { 
     206            pathp->cmp = -1; 
     207            pathp[1].node = left; 
     208        } else { 
     209            // Find node's successor, in preparation for swap 
     210            // XXX defer this for later 
     211            pathp[1].node = RB_RIGHT_GET(pathp->node); 
     212            pathp->cmp = 1; 
     213            nodep = pathp; 
     214            for (pathp++; pathp->node != RB_NULL; pathp++) { 
     215                pathp->cmp = -1; 
     216                pathp[1].node = RB_LEFT_GET(pathp->node); 
     217            } 
     218            break; 
     219        } 
     220    } 
     221    ASSERT(nodep->node != RB_NULL); 
     222    StgTSO *tso = RB_HEAD_GET(nodep->node); 
     223    if (tso->_link != END_TSO_QUEUE) { // fast-path! 
     224        RB_HEAD_SET(cap, nodep->node, tso->_link); 
     225        tso->_link = END_TSO_QUEUE; 
     226        return tso; // not to cleanup: no free node! 
     227    } 
     228    tso->_link = END_TSO_QUEUE; 
     229    pathp--; 
     230    StgRB *node = nodep->node; // the node to be deleted 
     231    if (pathp->node != node) { 
     232        ASSERT(pathp->node != RB_NULL); 
     233        // swap node with its successor 
     234        StgClosure *tred = RB_COLOR_GET(pathp->node); 
     235        RB_COLOR_SET(cap, pathp->node, RB_COLOR_GET(node)); 
     236        ASSERT(RB_HEAD_GET(pathp->node) != END_TSO_QUEUE); // e.g. fast path is NOT in effect 
     237        ASSERT(RB_TAIL_GET(pathp->node) != END_TSO_QUEUE); 
     238        RB_LEFT_SET(cap, pathp->node, RB_LEFT_GET(node)); 
     239        // if node's successor is its right child, the following code 
     240        // will do the wrong thing for the right child pointer. 
     241        // However, it doesn't matter, because the pointer will be 
     242        // properly set when the successor is pruned. 
     243        RB_RIGHT_SET(cap, pathp->node, RB_RIGHT_GET(node)); 
     244        RB_COLOR_SET(cap, node, tred); 
     245        // the pruned leaf node's child pointers are never accessed 
     246        // again, so don't bother setting them to nil 
     247        nodep->node = pathp->node; 
     248        pathp->node = node; 
     249        if (nodep == path) { 
     250            *root = nodep->node; 
     251        } else { 
     252            if (nodep[-1].cmp < 0) { 
     253                RB_LEFT_SET(cap, nodep[-1].node, nodep->node); 
     254            } else { 
     255                RB_RIGHT_SET(cap, nodep[-1].node, nodep->node); 
     256            } 
     257        } 
     258    } else { 
     259        StgRB *left = RB_LEFT_GET(node); 
     260        if (left != RB_NULL) { 
     261            // node has no successor, but it has a left child. 
     262            // splice node out, without losing the left child 
     263            ASSERT(RB_IS_BLACK(node)); 
     264            ASSERT(RB_IS_RED(left)); 
     265            RB_COLOR_BLACK(cap, left); 
     266            if (pathp == path) { 
     267                *root = left; 
     268            } else { 
     269                if (pathp[-1].cmp < 0) { 
     270                    RB_LEFT_SET(cap, pathp[-1].node, left); 
     271                } else { 
     272                    RB_RIGHT_SET(cap, pathp[-1].node, left); 
     273                } 
     274            } 
     275            goto cleanup; 
     276        } else if (pathp == path) { 
     277            // the tree contained only one node 
     278            // *root = RB_NULL; 
     279            // instead, setup fastpath 
     280            RB_HEAD_SET(cap, *root, END_TSO_QUEUE); 
     281            RB_TAIL_SET(cap, *root, END_TSO_QUEUE); 
     282            ASSERT(RB_LEFT_GET(*root) == RB_NULL); 
     283            ASSERT(RB_RIGHT_GET(*root) == RB_NULL); 
     284            // do NOT add to free list 
     285            return tso; 
     286        } 
     287    } 
     288    if (RB_IS_RED(pathp->node)) { 
     289        // prune red node, which requires no fixup 
     290        ASSERT(pathp[-1].cmp < 0); 
     291        RB_LEFT_SET(cap, pathp[-1].node, RB_NULL); 
     292        goto cleanup; 
     293    } 
     294    // the node to be pruned is black, so unwind until balance 
     295    // is restored 
     296    pathp->node = RB_NULL; 
     297    for (pathp--; (void*)pathp >= (void*)path; pathp--) { 
     298        ASSERT(pathp->node != RB_NULL); 
     299        ASSERT(pathp->cmp != 0); 
     300        if (pathp->cmp < 0) { 
     301            RB_LEFT_SET(cap, pathp->node, pathp[1].node); 
     302            ASSERT(RB_IS_BLACK(pathp[1].node)); 
     303            if (RB_IS_RED(pathp->node)) { 
     304                StgRB *right = RB_RIGHT_GET(pathp->node); 
     305                ASSERT(right != RB_NULL); 
     306                StgRB *rightleft = RB_LEFT_GET(right); 
     307                StgRB *tnode; 
     308                if (RB_IS_RED(rightleft)) { 
     309                    /* In the following diagrams, ||, //, and \\      */ 
     310                    /* indicate the path to the removed node.         */ 
     311                    /*                                                */ 
     312                    /*      ||                                        */ 
     313                    /*    pathp(r)                                    */ 
     314                    /*  //        \                                   */ 
     315                    /* (b)        (b)                                 */ 
     316                    /*           /                                    */ 
     317                    /*          (r)                                   */ 
     318                    /*                                                */ 
     319                    RB_COLOR_BLACK(cap, pathp->node); 
     320                    tnode = rbRotateRight(cap, right); 
     321                    RB_RIGHT_SET(cap, pathp->node, tnode); 
     322                    tnode = rbRotateLeft(cap, pathp->node); 
     323                } else { 
     324                    /*      ||                                        */ 
     325                    /*    pathp(r)                                    */ 
     326                    /*  //        \                                   */ 
     327                    /* (b)        (b)                                 */ 
     328                    /*           /                                    */ 
     329                    /*          (b)                                   */ 
     330                    /*                                                */ 
     331                    tnode = rbRotateLeft(cap, pathp->node); 
     332                } 
     333                // balance restored, but rotation modified subtree root. 
     334                ASSERT(pathp > path); 
     335                if (pathp[-1].cmp < 0) { 
     336                    RB_LEFT_SET(cap, pathp[-1].node, tnode); 
     337                } else { 
     338                    RB_RIGHT_SET(cap, pathp[-1].node, tnode); 
     339                } 
     340                goto cleanup; 
     341            } else { 
     342                StgRB *right = RB_RIGHT_GET(pathp->node); 
     343                ASSERT(right != RB_NULL); 
     344                StgRB *rightleft = RB_LEFT_GET(right); 
     345                if (RB_IS_RED(rightleft)) { 
     346                    /*      ||                                        */ 
     347                    /*    pathp(b)                                    */ 
     348                    /*  //        \                                   */ 
     349                    /* (b)        (b)                                 */ 
     350                    /*           /                                    */ 
     351                    /*          (r)                                   */ 
     352                    StgRB *tnode; 
     353                    RB_COLOR_BLACK(cap, rightleft); 
     354                    tnode = rbRotateRight(cap, right); 
     355                    RB_RIGHT_SET(cap, pathp->node, tnode); 
     356                    tnode = rbRotateLeft(cap, pathp->node); 
     357                    // balance restored, but rotation modified 
     358                    // subtree root, which may actually be the tree root 
     359                    if (pathp == path) { 
     360                        // set root 
     361                        *root = tnode; 
     362                    } else { 
     363                        if (pathp[-1].cmp < 0) { 
     364                            RB_LEFT_SET(cap, pathp[-1].node, tnode); 
     365                        } else { 
     366                            RB_RIGHT_SET(cap, pathp[-1].node, tnode); 
     367                        } 
     368                    } 
     369                    goto cleanup; 
     370                } else { 
     371                    /*      ||                                        */ 
     372                    /*    pathp(b)                                    */ 
     373                    /*  //        \                                   */ 
     374                    /* (b)        (b)                                 */ 
     375                    /*           /                                    */ 
     376                    /*          (b)                                   */ 
     377                    StgRB *tnode; 
     378                    RB_COLOR_RED(cap, pathp->node); 
     379                    tnode = rbRotateLeft(cap, pathp->node); 
     380                    pathp->node = tnode; 
     381                } 
     382            } 
     383        } else { 
     384            StgRB *left; 
     385            RB_RIGHT_SET(cap, pathp->node, pathp[1].node); 
     386            left = RB_LEFT_GET(pathp->node); 
     387            ASSERT(left != RB_NULL); 
     388            if (RB_IS_RED(left)) { 
     389                StgRB *tnode; 
     390                StgRB *leftright = RB_RIGHT_GET(left); 
     391                ASSERT(leftright != RB_NULL); 
     392                StgRB *leftrightleft = RB_LEFT_GET(leftright); 
     393                if (RB_IS_RED(leftrightleft)) { 
     394                    /*      ||                                        */ 
     395                    /*    pathp(b)                                    */ 
     396                    /*   /        \\                                  */ 
     397                    /* (r)        (b)                                 */ 
     398                    /*   \                                            */ 
     399                    /*   (b)                                          */ 
     400                    /*   /                                            */ 
     401                    /* (r)                                            */ 
     402                    StgRB *unode; 
     403                    RB_COLOR_BLACK(cap, leftrightleft); 
     404                    unode = rbRotateRight(cap, pathp->node); 
     405                    tnode = rbRotateRight(cap, pathp->node); 
     406                    RB_RIGHT_SET(cap, unode, tnode); 
     407                    tnode = rbRotateLeft(cap, unode); 
     408                } else { 
     409                    /*      ||                                        */ 
     410                    /*    pathp(b)                                    */ 
     411                    /*   /        \\                                  */ 
     412                    /* (r)        (b)                                 */ 
     413                    /*   \                                            */ 
     414                    /*   (b)                                          */ 
     415                    /*   /                                            */ 
     416                    /* (b)                                            */ 
     417                    ASSERT(leftright != RB_NULL); 
     418                    RB_COLOR_RED(cap, leftright); 
     419                    tnode = rbRotateRight(cap, pathp->node); 
     420                    RB_COLOR_BLACK(cap, tnode); 
     421                } 
     422                /* Balance restored, but rotation modified subtree    */ 
     423                /* root, which may actually be the tree root.         */ 
     424                if (pathp == path) { 
     425                    /* Set root. */ 
     426                    *root = tnode; 
     427                } else { 
     428                    if (pathp[-1].cmp < 0) { 
     429                        RB_LEFT_SET(cap, pathp[-1].node, tnode); 
     430                    } else { 
     431                        RB_RIGHT_SET(cap, pathp[-1].node, tnode); 
     432                    } 
     433                } 
     434                goto cleanup; 
     435            } else if (RB_IS_RED(pathp->node)) { 
     436                StgRB *leftleft = RB_LEFT_GET(left); 
     437                if (RB_IS_RED(leftleft)) { 
     438                    /*        ||                                      */ 
     439                    /*      pathp(r)                                  */ 
     440                    /*     /        \\                                */ 
     441                    /*   (b)        (b)                               */ 
     442                    /*   /                                            */ 
     443                    /* (r)                                            */ 
     444                    StgRB *tnode; 
     445                    RB_COLOR_BLACK(cap, pathp->node); 
     446                    RB_COLOR_RED(cap, left); 
     447                    RB_COLOR_BLACK(cap, leftleft); 
     448                    tnode = rbRotateRight(cap, pathp->node); 
     449                    /* Balance restored, but rotation modified        */ 
     450                    /* subtree root.                                  */ 
     451                    ASSERT(pathp > path); 
     452                    if (pathp[-1].cmp < 0) { 
     453                        RB_LEFT_SET(cap, pathp[-1].node, tnode); 
     454                    } else { 
     455                        RB_RIGHT_SET(cap, pathp[-1].node, tnode); 
     456                    } 
     457                    goto cleanup; 
     458                } else { 
     459                    /*        ||                                      */ 
     460                    /*      pathp(r)                                  */ 
     461                    /*     /        \\                                */ 
     462                    /*   (b)        (b)                               */ 
     463                    /*   /                                            */ 
     464                    /* (b)                                            */ 
     465                    RB_COLOR_RED(cap, left); 
     466                    RB_COLOR_BLACK(cap, pathp->node); 
     467                    /* Balance restored. */ 
     468                    goto cleanup; 
     469                } 
     470            } else { 
     471                StgRB *leftleft = RB_LEFT_GET(left); 
     472                if (RB_IS_RED(leftleft)) { 
     473                    /*               ||                               */ 
     474                    /*             pathp(b)                           */ 
     475                    /*            /        \\                         */ 
     476                    /*          (b)        (b)                        */ 
     477                    /*          /                                     */ 
     478                    /*        (r)                                     */ 
     479                    StgRB *tnode; 
     480                    RB_COLOR_BLACK(cap, leftleft); 
     481                    tnode = rbRotateRight(cap, pathp->node); 
     482                    /* Balance restored, but rotation modified        */ 
     483                    /* subtree root, which may actually be the tree   */ 
     484                    /* root.                                          */ 
     485                    if (pathp == path) { 
     486                        /* Set root. */ 
     487                        *root = tnode; 
     488                    } else { 
     489                        if (pathp[-1].cmp < 0) { 
     490                            RB_LEFT_SET(cap, pathp[-1].node, tnode); 
     491                        } else { 
     492                            RB_RIGHT_SET(cap, pathp[-1].node, tnode); 
     493                        } 
     494                    } 
     495                    goto cleanup; 
     496                } else { 
     497                    /*               ||                               */ 
     498                    /*             pathp(b)                           */ 
     499                    /*            /        \\                         */ 
     500                    /*          (b)        (b)                        */ 
     501                    /*          /                                     */ 
     502                    /*        (b)                                     */ 
     503                    RB_COLOR_RED(cap, left); 
     504                } 
     505            } 
     506        } 
     507    } 
     508    // set root 
     509    *root = path->node; 
     510    ASSERT(RB_IS_BLACK(*root)); 
     511cleanup: 
     512    // return node to the free list 
     513    RB_LEFT_SET(cap, node, cap->rb_free_list); 
     514#ifdef DEBUG 
     515    RB_RIGHT_SET(cap, node, RB_NULL); 
     516    RB_HEAD_SET(cap, node, END_TSO_QUEUE); 
     517    RB_TAIL_SET(cap, node, END_TSO_QUEUE); 
     518#endif 
     519    cap->rb_free_list = node; 
     520    return tso; 
     521} 
  • (a) /dev/null vs. (b) b/rts/RBTree.h

    diff --git a/rts/RBTree.h b/rts/RBTree.h
    new file mode 100644
    index 0000000..df5fbaa
    a b  
     1#ifndef RBTREE_H 
     2#define RBTREE_H 
     3 
     4#include "Capability.h" 
     5#include "RtsUtils.h" 
     6 
     7// http://www.canonware.com/rb/ 
     8 
     9struct StgRB_ { 
     10    StgRB *left, *right; 
     11    StgTSO *head, *tail; 
     12    int color; 
     13}; // typedef in RtsAPI 
     14 
     15#define RB_RED 0 
     16#define RB_BLACK 1 
     17 
     18#define RB_LEFT_GET(n)           ((n)->left) 
     19#define RB_LEFT_SET(cap, n,p)    (n)->left = p; 
     20#define RB_RIGHT_GET(n)          ((n)->right) 
     21#define RB_RIGHT_SET(cap, n,p)   (n)->right = p; 
     22#define RB_HEAD_GET(n)           ((n)->head) 
     23#define RB_HEAD_SET(cap, n,p)    (n)->head = p; 
     24#define RB_TAIL_GET(n)           ((n)->tail) 
     25#define RB_TAIL_SET(cap, n,p)    (n)->tail = p; 
     26// alternatively, setup a static RB_NULL closure with the appropriate 
     27// structure and do the normal thing 
     28#define RB_IS_RED(n)        ((n) != RB_NULL && (n)->color == RB_RED) 
     29#define RB_IS_BLACK(n)      ((n) == RB_NULL || (n)->color == RB_BLACK) 
     30#define RB_COLOR_GET(n)     ((n) == RB_NULL ? RB_BLACK : (n)->color) 
     31#define RB_COLOR_RED(cap, n)     (n)->color = RB_RED; 
     32#define RB_COLOR_BLACK(cap, n)   (n)->color = RB_BLACK; 
     33#define RB_COLOR_SET(cap, n,c)       (n)->color = c; 
     34 
     35int checkRBTree(StgRB *r, int forceBlack, int count, int expected); 
     36StgRB* rbInsert(Capability *cap, StgRB **root, StgTSO *tso); 
     37StgTSO* rbRemoveMin(Capability *cap, StgRB **root); 
     38void rbEvacuate(evac_fn evac, void *user, StgRB* r); 
     39 
     40// maintain a free list of nodes so we don't have to continually 
     41// allocate them 
     42 
     43#define RB_CHUNK (1024 * sizeof(W_) / sizeof(StgRB)) 
     44 
     45INLINE_HEADER StgRB* 
     46rbCreateNode(Capability *cap, StgTSO *tso) { 
     47    StgRB *n; 
     48    if (cap->rb_free_list != RB_NULL) { 
     49        n = cap->rb_free_list; 
     50        cap->rb_free_list = RB_LEFT_GET(n); 
     51    } else { 
     52        n = (StgRB*) stgMallocBytes(RB_CHUNK * sizeof(StgRB), "rbCreateNode"); 
     53        cap->rb_free_list = n + 1; 
     54        StgRB *p; 
     55        for (p = cap->rb_free_list; p < n + RB_CHUNK - 1; p++) { 
     56            p->left = p + 1; 
     57        } 
     58        p->left = RB_NULL; 
     59    } 
     60    RB_LEFT_SET(cap, n, RB_NULL); 
     61    RB_RIGHT_SET(cap, n, RB_NULL); 
     62    RB_HEAD_SET(cap, n, tso); 
     63    RB_TAIL_SET(cap, n, tso); 
     64    if (tso == END_TSO_QUEUE) { 
     65        RB_COLOR_BLACK(cap, n); 
     66    } else { 
     67        RB_COLOR_RED(cap, n); 
     68    } 
     69    return n; 
     70} 
     71 
     72EXTERN_INLINE StgRB* 
     73rbFirst(StgRB *n); 
     74 
     75EXTERN_INLINE StgRB* 
     76rbFirst(StgRB *n) { 
     77    for (; RB_LEFT_GET(n) != RB_NULL; n = RB_LEFT_GET(n)) {} 
     78    return n; 
     79} 
     80 
     81EXTERN_INLINE StgRB* 
     82rbLast(StgRB *n); 
     83 
     84EXTERN_INLINE StgRB* 
     85rbLast(StgRB *n) { 
     86    for (; RB_RIGHT_GET(n) != RB_NULL; n = RB_RIGHT_GET(n)) {} 
     87    return n; 
     88} 
     89 
     90#endif /* RBTREE_H */ 
  • rts/Schedule.c

    diff --git a/rts/Schedule.c b/rts/Schedule.c
    index 3de00c5..8e93fbc 100644
    a b  
    560560 * -------------------------------------------------------------------------- */ 
    561561 
    562562void 
    563 removeFromRunQueue (Capability *cap, StgTSO *tso) 
     563removeFromRunQueue (Capability *cap STG_UNUSED, StgTSO *tso STG_UNUSED) 
    564564{ 
    565     if (tso->block_info.prev == END_TSO_QUEUE) { 
    566         ASSERT(cap->run_queue_hd == tso); 
    567         cap->run_queue_hd = tso->_link; 
    568     } else { 
    569         setTSOLink(cap, tso->block_info.prev, tso->_link); 
    570     } 
    571     if (tso->_link == END_TSO_QUEUE) { 
    572         ASSERT(cap->run_queue_tl == tso); 
    573         cap->run_queue_tl = tso->block_info.prev; 
    574     } else { 
    575         setTSOPrev(cap, tso->_link, tso->block_info.prev); 
    576     } 
    577     tso->_link = tso->block_info.prev = END_TSO_QUEUE; 
    578  
    579     IF_DEBUG(sanity, checkRunQueue(cap)); 
     565    //barf("removeFromRunQueue"); 
    580566} 
    581567 
    582568void 
    583 promoteInRunQueue (Capability *cap, StgTSO *tso) 
     569promoteInRunQueue (Capability *cap STG_UNUSED, StgTSO *tso STG_UNUSED) 
    584570{ 
    585     removeFromRunQueue(cap, tso); 
    586     pushOnRunQueue(cap, tso); 
     571    //removeFromRunQueue(cap, tso); 
     572    //pushOnRunQueue(cap, tso); 
    587573} 
    588574 
    589575/* ---------------------------------------------------------------------------- 
     
    742728    //   - giving low priority to moving long-lived threads 
    743729 
    744730    if (n_free_caps > 0) { 
    745         StgTSO *prev, *t, *next; 
     731        //StgTSO *prev, *t, *next; 
    746732#ifdef SPARK_PUSHING 
    747733        rtsBool pushed_to_all; 
    748734#endif 
     
    759745        pushed_to_all = rtsFalse; 
    760746#endif 
    761747 
     748        /* 
    762749        if (cap->run_queue_hd != END_TSO_QUEUE) { 
    763750            prev = cap->run_queue_hd; 
    764751            t = prev->_link; 
     
    795782 
    796783            IF_DEBUG(sanity, checkRunQueue(cap)); 
    797784        } 
     785        */ 
    798786 
    799787#ifdef SPARK_PUSHING 
    800788        /* JB I left this code in place, it would work but is not necessary */ 
  • rts/Schedule.h

    diff --git a/rts/Schedule.h b/rts/Schedule.h
    index e4425af..65457c0 100644
    a b  
    1313#include "rts/OSThreads.h" 
    1414#include "Capability.h" 
    1515#include "Trace.h" 
     16#include "RBTree.h" 
    1617 
    1718#include "BeginPrivate.h" 
    1819 
     
    140141EXTERN_INLINE void 
    141142appendToRunQueue (Capability *cap, StgTSO *tso) 
    142143{ 
    143     ASSERT(tso->_link == END_TSO_QUEUE); 
    144     if (cap->run_queue_hd == END_TSO_QUEUE) { 
    145         cap->run_queue_hd = tso; 
    146         tso->block_info.prev = END_TSO_QUEUE; 
     144    tso->block_info.closure = (StgClosure*)END_TSO_QUEUE; 
     145    tso->ss_pass += STRIDE1 / tso->ss_tickets; 
     146    StgTSO *cur = RB_HEAD_GET(cap->run_active); 
     147    cap->run_count++; 
     148    if (cur == END_TSO_QUEUE) { 
     149        // fastpath 
     150        ASSERT(RB_IS_BLACK(cap->run_active)); 
     151        ASSERT(RB_LEFT_GET(cap->run_active) == RB_NULL); 
     152        ASSERT(RB_RIGHT_GET(cap->run_active) == RB_NULL); 
     153        RB_HEAD_SET(cap, cap->run_active, tso); 
     154        RB_TAIL_SET(cap, cap->run_active, tso); 
    147155    } else { 
    148         setTSOLink(cap, cap->run_queue_tl, tso); 
    149         setTSOPrev(cap, tso, cap->run_queue_tl); 
     156        StgWord64 pass = cur->ss_pass; 
     157        if (tso->ss_pass < pass) { 
     158            cap->run_active = rbInsert(cap, &cap->run_rbtree, tso); 
     159        } else if (tso->ss_pass == pass) { 
     160            setTSOLink(cap, RB_TAIL_GET(cap->run_active), tso); 
     161            RB_TAIL_SET(cap, cap->run_active, tso); 
     162        } else { 
     163            rbInsert(cap, &cap->run_rbtree, tso); 
     164        } 
     165        IF_DEBUG(sanity, checkRBTree(cap->run_rbtree, 1, 0, -1)); 
    150166    } 
    151     cap->run_queue_tl = tso; 
    152167} 
    153168 
    154169EXTERN_INLINE void 
     
    157172EXTERN_INLINE void 
    158173joinRunQueue(Capability *cap, StgTSO *tso) 
    159174{ 
     175    tso->ss_pass = cap->ss_pass - STRIDE1 / tso->ss_tickets; 
    160176    appendToRunQueue(cap, tso); 
    161177} 
    162178 
     
    169185EXTERN_INLINE void 
    170186pushOnRunQueue (Capability *cap, StgTSO *tso) 
    171187{ 
    172     setTSOLink(cap, tso, cap->run_queue_hd); 
    173     tso->block_info.prev = END_TSO_QUEUE; 
    174     if (cap->run_queue_hd != END_TSO_QUEUE) { 
    175         setTSOPrev(cap, cap->run_queue_hd, tso); 
    176     } 
    177     cap->run_queue_hd = tso; 
    178     if (cap->run_queue_tl == END_TSO_QUEUE) { 
    179         cap->run_queue_tl = tso; 
     188    tso->block_info.closure = (StgClosure*)END_TSO_QUEUE; 
     189    tso->ss_pass += STRIDE1 / tso->ss_tickets; 
     190    cap->run_count++; 
     191    if (cap->promoted_run_queue_hd == END_TSO_QUEUE) { 
     192    } else { 
     193        setTSOLink(cap, tso, cap->promoted_run_queue_hd); 
    180194    } 
     195    cap->promoted_run_queue_hd = tso; 
    181196} 
    182197 
    183198EXTERN_INLINE void 
     
    186201EXTERN_INLINE void 
    187202fastJoinRunQueue(Capability *cap, StgTSO *tso) 
    188203{ 
     204    tso->ss_pass = cap->ss_pass - STRIDE1 / tso->ss_tickets; 
    189205    pushOnRunQueue(cap, tso); 
    190206} 
    191207 
     
    194210INLINE_HEADER StgTSO * 
    195211popRunQueue (Capability *cap) 
    196212{  
    197     StgTSO *t = cap->run_queue_hd; 
    198     ASSERT(t != END_TSO_QUEUE); 
    199     cap->run_queue_hd = t->_link; 
    200     if (t->_link != END_TSO_QUEUE) { 
    201         t->_link->block_info.prev = END_TSO_QUEUE; 
    202     } 
    203     t->_link = END_TSO_QUEUE; // no write barrier req'd 
    204     if (cap->run_queue_hd == END_TSO_QUEUE) { 
    205         cap->run_queue_tl = END_TSO_QUEUE; 
     213    cap->run_count--; 
     214    if (cap->promoted_run_queue_hd == END_TSO_QUEUE) { 
     215        StgTSO *candidate = RB_HEAD_GET(cap->run_active); 
     216        if (candidate == END_TSO_QUEUE) { 
     217            barf("popRunQueue: queue is empty"); 
     218        } 
     219        if ( // unconditional fastpath (no-rb tree) 
     220             (candidate->_link != END_TSO_QUEUE) || 
     221             // fastpath for a queue that just got emptied 
     222             (cap->run_rbtree == cap->run_active && RB_RIGHT_GET(cap->run_active) == RB_NULL) 
     223        ) { 
     224            RB_HEAD_SET(cap, cap->run_active, candidate->_link); 
     225            if (candidate->_link == END_TSO_QUEUE) { 
     226                RB_TAIL_SET(cap, cap->run_active, END_TSO_QUEUE); 
     227            } 
     228            candidate->_link = END_TSO_QUEUE; 
     229            return candidate; 
     230        } 
     231        StgTSO *t = rbRemoveMin(cap, &cap->run_rbtree); 
     232        IF_DEBUG(sanity, checkRBTree(cap->run_rbtree, 1, 0, -1)); 
     233        // XXX maybe this can be folded into removeMin 
     234        cap->run_active = rbFirst(cap->run_rbtree); 
     235        if (RB_HEAD_GET(cap->run_active) != END_TSO_QUEUE) { 
     236            StgWord64 npass = RB_HEAD_GET(cap->run_active)->ss_pass; 
     237            if (npass > cap->ss_pass) { 
     238                cap->ss_pass = npass; 
     239            } 
     240        } 
     241        return t; 
     242    } else { 
     243        StgTSO *t = cap->promoted_run_queue_hd; 
     244        cap->promoted_run_queue_hd = t->_link; 
     245        t->_link = END_TSO_QUEUE; // no write barrier req'd 
     246        return t; 
    206247    } 
    207     return t; 
    208248} 
    209249 
    210250INLINE_HEADER StgTSO * 
    211251peekRunQueue (Capability *cap) 
    212252{ 
    213     return cap->run_queue_hd; 
     253    if (cap->promoted_run_queue_hd == END_TSO_QUEUE) { 
     254        return RB_HEAD_GET(cap->run_active); 
     255    } else { 
     256        return cap->promoted_run_queue_hd; 
     257    } 
    214258} 
    215259 
    216260EXTERN_INLINE void 
    217261leaveRunQueue (Capability *cap, StgTSO *tso); 
    218262 
    219263EXTERN_INLINE void 
    220 leaveRunQueue (Capability *cap, StgTSO *tso) 
     264leaveRunQueue (Capability *cap STG_UNUSED, StgTSO *tso STG_UNUSED) 
    221265{ 
    222266    // XXX implement me 
    223267} 
     
    233277{ 
    234278    ASSERT(tso->_link == END_TSO_QUEUE); 
    235279    if (blocked_queue_hd == END_TSO_QUEUE) { 
    236         blocked_queue_hd = tso; 
     280       blocked_queue_hd = tso; 
    237281    } else { 
    238         setTSOLink(&MainCapability, blocked_queue_tl, tso); 
     282       setTSOLink(&MainCapability, blocked_queue_tl, tso); 
    239283    } 
    240284    blocked_queue_tl = tso; 
    241285} 
     
    252296INLINE_HEADER rtsBool 
    253297emptyRunQueue(Capability *cap) 
    254298{ 
    255     return emptyQueue(cap->run_queue_hd); 
     299    return cap->run_count == 0; 
    256300} 
    257301 
    258 /* assumes that the queue is not empty; so combine this with 
    259  * an emptyRunQueue check! */ 
    260302INLINE_HEADER rtsBool 
    261303singletonRunQueue(Capability *cap) 
    262304{ 
    263     ASSERT(!emptyRunQueue(cap)); 
    264     return cap->run_queue_hd->_link == END_TSO_QUEUE; 
     305    return cap->run_count == 1; 
    265306} 
    266307 
    267308INLINE_HEADER void 
    268309truncateRunQueue(Capability *cap) 
    269310{ 
    270     cap->run_queue_hd = END_TSO_QUEUE; 
    271     cap->run_queue_tl = END_TSO_QUEUE; 
     311    cap->promoted_run_queue_hd = END_TSO_QUEUE; 
     312    // XXX leak 
     313    cap->run_rbtree = cap->run_active = rbCreateNode(cap, END_TSO_QUEUE); 
     314    cap->run_count = 0; 
    272315} 
    273316 
    274317#if !defined(THREADED_RTS) 
  • rts/StgMiscClosures.cmm

    diff --git a/rts/StgMiscClosures.cmm b/rts/StgMiscClosures.cmm
    index 4341013..bb33229 100644
    a b  
    546546 
    547547CLOSURE(stg_END_TSO_QUEUE_closure,stg_END_TSO_QUEUE); 
    548548 
     549INFO_TABLE_CONSTR(stg_RB_NULL,0,0,0,CONSTR_NOCAF_STATIC,"RB_NULL","RB_NULL") 
     550{ foreign "C" barf("RB_NULL object entered!") never returns; } 
     551 
     552CLOSURE(stg_RB_NULL_closure,stg_RB_NULL); 
     553 
    549554/* ---------------------------------------------------------------------------- 
    550555   Arrays 
    551556 
  • rts/Threads.c

    diff --git a/rts/Threads.c b/rts/Threads.c
    index 758d368..5701e4b 100644
    a b  
    113113    tso->trec = NO_TREC; 
    114114 
    115115    tso->ss_tickets = DEFAULT_TICKETS; 
     116    tso->ss_pass = cap->ss_pass; 
    116117 
    117118#ifdef PROFILING 
    118119    tso->prof.cccs = CCS_MAIN; 
     
    844845  for (i = 0; i < n_capabilities; i++) { 
    845846      cap = &capabilities[i]; 
    846847      debugBelch("threads on capability %d:\n", cap->no); 
     848      /* 
    847849      for (t = cap->run_queue_hd; t != END_TSO_QUEUE; t = t->_link) { 
    848850          printThreadStatus(t); 
    849851      } 
     852      */ 
    850853  } 
    851854 
    852855  debugBelch("other threads:\n"); 
  • rts/sm/Sanity.c

    diff --git a/rts/sm/Sanity.c b/rts/sm/Sanity.c
    index f0e1659..fbc0971 100644
    a b  
    787787} 
    788788 
    789789void 
    790 checkRunQueue(Capability *cap) 
     790checkRunQueue(Capability *cap STG_UNUSED) 
    791791{ 
     792    /* 
    792793    StgTSO *prev, *tso; 
    793794    prev = END_TSO_QUEUE; 
    794795    for (tso = cap->run_queue_hd; tso != END_TSO_QUEUE;  
     
    797798        ASSERT(tso->block_info.prev == prev); 
    798799    } 
    799800    ASSERT(cap->run_queue_tl == prev); 
     801    */ 
    800802} 
    801803 
    802804/* -----------------------------------------------------------------------------