~ubuntu-branches/ubuntu/trusty/erlang/trusty

« back to all changes in this revision

Viewing changes to erts/emulator/beam/erl_process.c

  • Committer: Bazaar Package Importer
  • Author(s): Clint Byrum
  • Date: 2011-05-05 15:48:43 UTC
  • mfrom: (3.5.13 sid)
  • Revision ID: james.westby@ubuntu.com-20110505154843-0om6ekzg6m7ugj27
Tags: 1:14.b.2-dfsg-3ubuntu1
* Merge from debian unstable.  Remaining changes:
  - Drop libwxgtk2.8-dev build dependency. Wx isn't in main, and not
    supposed to.
  - Drop erlang-wx binary.
  - Drop erlang-wx dependency from -megaco, -common-test, and -reltool, they
    do not really need wx. Also drop it from -debugger; the GUI needs wx,
    but it apparently has CLI bits as well, and is also needed by -megaco,
    so let's keep the package for now.
  - debian/patches/series: Do what I meant, and enable build-options.patch
    instead.
* Additional changes:
  - Drop erlang-wx from -et
* Dropped Changes:
  - patches/pcre-crash.patch: CVE-2008-2371: outer level option with
    alternatives caused crash. (Applied Upstream)
  - fix for ssl certificate verification in newSSL: 
    ssl_cacertfile_fix.patch (Applied Upstream)
  - debian/patches/series: Enable native.patch again, to get stripped beam
    files and reduce the package size again. (build-options is what
    actually accomplished this)
  - Remove build-options.patch on advice from upstream and because it caused
    odd build failures.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * %CopyrightBegin%
3
 
 * 
4
 
 * Copyright Ericsson AB 1996-2009. All Rights Reserved.
5
 
 * 
 
3
 *
 
4
 * Copyright Ericsson AB 1996-2011. All Rights Reserved.
 
5
 *
6
6
 * The contents of this file are subject to the Erlang Public License,
7
7
 * Version 1.1, (the "License"); you may not use this file except in
8
8
 * compliance with the License. You should have received a copy of the
9
9
 * Erlang Public License along with this software. If not, it can be
10
10
 * retrieved online at http://www.erlang.org/.
11
 
 * 
 
11
 *
12
12
 * Software distributed under the License is distributed on an "AS IS"
13
13
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
14
14
 * the License for the specific language governing rights and limitations
15
15
 * under the License.
16
 
 * 
 
16
 *
17
17
 * %CopyrightEnd%
18
18
 */
19
19
 
24
24
#endif
25
25
 
26
26
#include <stddef.h> /* offsetof() */
27
 
#include <ctype.h>
28
27
#include "sys.h"
29
28
#include "erl_vm.h"
30
29
#include "global.h"
38
37
#include "erl_instrument.h"
39
38
#include "erl_threads.h"
40
39
#include "erl_binary.h"
 
40
#include "beam_bp.h"
 
41
#include "erl_cpu_topology.h"
41
42
 
42
43
#define ERTS_RUNQ_CHECK_BALANCE_REDS_PER_SCHED (2000*CONTEXT_REDS)
43
44
#define ERTS_RUNQ_CALL_CHECK_BALANCE_REDS \
45
46
 
46
47
#define ERTS_PROC_MIN_CONTEXT_SWITCH_REDS_COST (CONTEXT_REDS/10)
47
48
 
48
 
#define ERTS_SCHED_SLEEP_SPINCOUNT 10000
49
 
 
50
 
#define ERTS_WAKEUP_OTHER_LIMIT (100*CONTEXT_REDS/2)
 
49
#define ERTS_SCHED_SPIN_UNTIL_YIELD 100
 
50
 
 
51
#define ERTS_SCHED_SYS_SLEEP_SPINCOUNT 10
 
52
#define ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT 1000
 
53
#define ERTS_SCHED_TSE_SLEEP_SPINCOUNT \
 
54
  (ERTS_SCHED_SYS_SLEEP_SPINCOUNT*ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT)
 
55
#define ERTS_SCHED_SUSPEND_SLEEP_SPINCOUNT 0
 
56
 
 
57
#define ERTS_WAKEUP_OTHER_LIMIT_VERY_HIGH (200*CONTEXT_REDS)
 
58
#define ERTS_WAKEUP_OTHER_LIMIT_HIGH (50*CONTEXT_REDS)
 
59
#define ERTS_WAKEUP_OTHER_LIMIT_MEDIUM (10*CONTEXT_REDS)
 
60
#define ERTS_WAKEUP_OTHER_LIMIT_LOW (CONTEXT_REDS)
 
61
#define ERTS_WAKEUP_OTHER_LIMIT_VERY_LOW (CONTEXT_REDS/10)
 
62
 
51
63
#define ERTS_WAKEUP_OTHER_DEC 10
52
64
#define ERTS_WAKEUP_OTHER_FIXED_INC (CONTEXT_REDS/10)
53
65
 
54
 
#define ERTS_MAX_CPU_TOPOLOGY_ID ((int) 0xffff)
55
 
 
56
66
#if 0 || defined(DEBUG)
57
67
#define ERTS_FAKE_SCHED_BIND_PRINT_SORTED_CPU_DATA
58
68
#endif
91
101
#define ERTS_EMPTY_RUNQ(RQ) \
92
102
  ((RQ)->len == 0 && (RQ)->misc.start == NULL)
93
103
 
94
 
extern Eterm beam_apply[];
95
 
extern Eterm beam_exit[];
96
 
extern Eterm beam_continue_exit[];
 
104
extern BeamInstr beam_apply[];
 
105
extern BeamInstr beam_exit[];
 
106
extern BeamInstr beam_continue_exit[];
97
107
 
98
108
static Sint p_last;
99
109
static Sint p_next;
105
115
Uint erts_max_processes = ERTS_DEFAULT_MAX_PROCESSES;
106
116
Uint erts_process_tab_index_mask;
107
117
 
 
118
static int wakeup_other_limit;
 
119
 
108
120
int erts_sched_thread_suggested_stack_size = -1;
109
121
 
110
122
#ifdef ERTS_ENABLE_LOCK_CHECK
115
127
 
116
128
int erts_disable_proc_not_running_opt;
117
129
 
118
 
#define ERTS_SCHED_CHANGING_ONLINE 1
119
 
#define ERTS_SCHED_CHANGING_MULTI_SCHED 2
 
130
#define ERTS_SCHDLR_SSPND_CHNG_WAITER           (((erts_aint32_t) 1) << 0)
 
131
#define ERTS_SCHDLR_SSPND_CHNG_MSB              (((erts_aint32_t) 1) << 1)
 
132
#define ERTS_SCHDLR_SSPND_CHNG_ONLN             (((erts_aint32_t) 1) << 2)
 
133
 
 
134
#ifndef DEBUG
 
135
 
 
136
#define ERTS_SCHDLR_SSPND_CHNG_SET(VAL, OLD_VAL) \
 
137
  erts_smp_atomic32_set(&schdlr_sspnd.changing, (VAL))
 
138
 
 
139
#else
 
140
 
 
141
#define ERTS_SCHDLR_SSPND_CHNG_SET(VAL, OLD_VAL)                        \
 
142
do {                                                                    \
 
143
    erts_aint32_t old_val__;                                            \
 
144
    old_val__ = erts_smp_atomic32_xchg(&schdlr_sspnd.changing,          \
 
145
                                       (VAL));                          \
 
146
    ASSERT(old_val__ == (OLD_VAL));                                     \
 
147
} while (0)
 
148
 
 
149
#endif
 
150
 
120
151
 
121
152
static struct {
122
153
    erts_smp_mtx_t mtx;
123
154
    erts_smp_cnd_t cnd;
124
 
    int changing;
125
155
    int online;
126
156
    int curr_online;
127
157
    int wait_curr_online;
128
 
    erts_smp_atomic_t active;
 
158
    erts_smp_atomic32_t changing;
 
159
    erts_smp_atomic32_t active;
129
160
    struct {
130
 
        erts_smp_atomic_t ongoing;
 
161
        erts_smp_atomic32_t ongoing;
131
162
        long wait_active;
132
163
        ErtsProcList *procs;
133
164
    } msb; /* Multi Scheduling Block */
135
166
 
136
167
static struct {
137
168
    erts_smp_mtx_t update_mtx;
138
 
    erts_smp_atomic_t active_runqs;
 
169
    erts_smp_atomic32_t active_runqs;
139
170
    int last_active_runqs;
140
 
    erts_smp_atomic_t used_runqs;
 
171
    erts_smp_atomic32_t used_runqs;
141
172
    int forced_check_balance;
142
 
    erts_smp_atomic_t checking_balance;
 
173
    erts_smp_atomic32_t checking_balance;
143
174
    int halftime;
144
175
    int full_reds_history_index;
145
176
    struct {
159
190
 
160
191
#endif
161
192
 
162
 
/*
163
 
 * Cpu topology hierarchy.
164
 
 */
165
 
#define ERTS_TOPOLOGY_NODE              0
166
 
#define ERTS_TOPOLOGY_PROCESSOR         1
167
 
#define ERTS_TOPOLOGY_PROCESSOR_NODE    2
168
 
#define ERTS_TOPOLOGY_CORE              3
169
 
#define ERTS_TOPOLOGY_THREAD            4
170
 
#define ERTS_TOPOLOGY_LOGICAL           5
171
 
 
172
 
#define ERTS_TOPOLOGY_MAX_DEPTH         6
173
 
 
174
 
typedef struct {
175
 
    int bind_id;
176
 
    int bound_id;
177
 
} ErtsCpuBindData;
178
 
 
179
 
static ErtsCpuBindData *scheduler2cpu_map;
180
 
erts_smp_rwmtx_t erts_cpu_bind_rwmtx;
181
 
 
182
 
typedef enum {
183
 
    ERTS_CPU_BIND_SPREAD,
184
 
    ERTS_CPU_BIND_PROCESSOR_SPREAD,
185
 
    ERTS_CPU_BIND_THREAD_SPREAD,
186
 
    ERTS_CPU_BIND_THREAD_NO_NODE_PROCESSOR_SPREAD,
187
 
    ERTS_CPU_BIND_NO_NODE_PROCESSOR_SPREAD,
188
 
    ERTS_CPU_BIND_NO_NODE_THREAD_SPREAD,
189
 
    ERTS_CPU_BIND_NO_SPREAD,
190
 
    ERTS_CPU_BIND_NONE
191
 
} ErtsCpuBindOrder;
192
 
 
193
 
ErtsCpuBindOrder cpu_bind_order;
194
 
 
195
 
static erts_cpu_topology_t *user_cpudata;
196
 
static int user_cpudata_size;
197
 
static erts_cpu_topology_t *system_cpudata;
198
 
static int system_cpudata_size;
199
 
 
200
193
erts_sched_stat_t erts_sched_stat;
201
194
 
202
195
ErtsRunQueue *erts_common_run_queue;
207
200
 
208
201
static erts_smp_mtx_t proc_tab_mtx;
209
202
 
210
 
static erts_smp_atomic_t function_calls;
 
203
static erts_smp_atomic32_t function_calls;
211
204
 
212
205
#ifdef ERTS_SMP
213
 
static erts_smp_atomic_t doing_sys_schedule;
214
 
static erts_smp_atomic_t no_empty_run_queues;
 
206
static erts_smp_atomic32_t doing_sys_schedule;
 
207
static erts_smp_atomic32_t no_empty_run_queues;
215
208
#else /* !ERTS_SMP */
216
209
ErtsSchedulerData *erts_scheduler_data;
217
210
#endif
219
212
ErtsAlignedRunQueue *erts_aligned_run_queues;
220
213
Uint erts_no_run_queues;
221
214
 
222
 
typedef struct {
223
 
    ErtsSchedulerData esd;
224
 
    char align[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(ErtsSchedulerData))];
225
 
} ErtsAlignedSchedulerData;
226
 
 
227
215
ErtsAlignedSchedulerData *erts_aligned_scheduler_data;
228
216
 
 
217
#ifdef ERTS_SMP
 
218
 
 
219
typedef union {
 
220
    ErtsSchedulerSleepInfo ssi;
 
221
    char align[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(ErtsSchedulerSleepInfo))];
 
222
} ErtsAlignedSchedulerSleepInfo;
 
223
 
 
224
static ErtsAlignedSchedulerSleepInfo *aligned_sched_sleep_info;
 
225
 
 
226
#endif
 
227
 
229
228
#ifndef BM_COUNTERS
230
229
static int processes_busy;
231
230
#endif
249
248
Process** erts_active_procs;
250
249
#endif
251
250
 
252
 
static erts_smp_atomic_t process_count;
 
251
#if ERTS_MAX_PROCESSES > 0x7fffffff
 
252
#error "Need to store process_count in another type"
 
253
#endif
 
254
static erts_smp_atomic32_t process_count;
253
255
 
254
256
typedef struct ErtsTermProcElement_ ErtsTermProcElement;
255
257
struct ErtsTermProcElement_ {
283
285
                                 200,
284
286
                                 ERTS_ALC_T_PROC_LIST)
285
287
 
286
 
#define ERTS_RUNQ_IX(IX)        (&erts_aligned_run_queues[(IX)].runq)
287
 
#define ERTS_SCHEDULER_IX(IX)   (&erts_aligned_scheduler_data[(IX)].esd)
 
288
#define ERTS_SCHED_SLEEP_INFO_IX(IX)                                    \
 
289
  (ASSERT_EXPR(0 <= (IX) && (IX) < erts_no_schedulers),                 \
 
290
   &aligned_sched_sleep_info[(IX)].ssi)
288
291
 
289
292
#define ERTS_FOREACH_RUNQ(RQVAR, DO)                                    \
290
293
do {                                                                    \
334
337
static void init_processes_bif(void);
335
338
static void save_terminating_process(Process *p);
336
339
static void exec_misc_ops(ErtsRunQueue *);
337
 
static void print_function_from_pc(int to, void *to_arg, Eterm* x);
 
340
static void print_function_from_pc(int to, void *to_arg, BeamInstr* x);
338
341
static int stack_element_dump(int to, void *to_arg, Process* p, Eterm* sp,
339
342
                              int yreg);
340
343
#ifdef ERTS_SMP
341
344
static void handle_pending_exiters(ErtsProcList *);
342
345
 
343
 
static void cpu_bind_order_sort(erts_cpu_topology_t *cpudata,
344
 
                                int size,
345
 
                                ErtsCpuBindOrder bind_order,
346
 
                                int mk_seq);
347
 
static void signal_schedulers_bind_change(erts_cpu_topology_t *cpudata, int size);
348
 
 
349
346
#endif
350
347
 
351
 
static void early_cpu_bind_init(void);
352
 
static void late_cpu_bind_init(void);
353
 
 
354
348
#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
355
349
int
356
350
erts_smp_lc_runq_is_locked(ErtsRunQueue *runq)
388
382
     erts_psd_required_locks[ERTS_PSD_DIST_ENTRY].get_locks
389
383
         = ERTS_PSD_DIST_ENTRY_GET_LOCKS;
390
384
     erts_psd_required_locks[ERTS_PSD_DIST_ENTRY].set_locks
391
 
         = ERTS_PSD_DIST_ENTRY_GET_LOCKS;
 
385
         = ERTS_PSD_DIST_ENTRY_SET_LOCKS;
 
386
 
 
387
     erts_psd_required_locks[ERTS_PSD_CALL_TIME_BP].get_locks
 
388
         = ERTS_PSD_CALL_TIME_BP_GET_LOCKS;
 
389
     erts_psd_required_locks[ERTS_PSD_CALL_TIME_BP].set_locks
 
390
         = ERTS_PSD_CALL_TIME_BP_SET_LOCKS;
392
391
 
393
392
     /* Check that we have locks for all entries */
394
393
     for (ix = 0; ix < ERTS_PSD_SIZE; ix++) {
401
400
 
402
401
/* initialize the scheduler */
403
402
void
404
 
erts_init_process(void)
 
403
erts_init_process(int ncpu)
405
404
{
406
405
    Uint proc_bits = ERTS_PROC_BITS;
407
406
 
408
407
#ifdef ERTS_SMP
409
408
    erts_disable_proc_not_running_opt = 0;
410
 
    erts_init_proc_lock();
 
409
    erts_init_proc_lock(ncpu);
411
410
#endif
412
411
 
413
412
    init_proclist_alloc();
414
413
 
415
 
    erts_smp_atomic_init(&process_count, 0);
 
414
    erts_smp_atomic32_init(&process_count, 0);
416
415
 
417
416
    if (erts_use_r9_pids_ports) {
418
417
        proc_bits = ERTS_R9_PROC_BITS;
572
571
 
573
572
#ifdef ERTS_SMP
574
573
 
 
574
void
 
575
erts_sched_finish_poke(ErtsSchedulerSleepInfo *ssi, erts_aint32_t flags)
 
576
{
 
577
    switch (flags & ERTS_SSI_FLGS_SLEEP_TYPE) {
 
578
    case ERTS_SSI_FLG_POLL_SLEEPING:
 
579
        erts_sys_schedule_interrupt(1);
 
580
        break;
 
581
    case ERTS_SSI_FLG_TSE_SLEEPING:
 
582
        erts_tse_set(ssi->event);
 
583
        break;
 
584
    case 0:
 
585
        break;
 
586
    default:
 
587
        erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error\n",
 
588
                 __FILE__, __LINE__);
 
589
        break;
 
590
    }
 
591
}
 
592
 
 
593
typedef struct erts_misc_aux_work_t_ erts_misc_aux_work_t;
 
594
struct erts_misc_aux_work_t_ {
 
595
    erts_misc_aux_work_t *next;
 
596
    void (*func)(void *);
 
597
    void *arg;
 
598
};
 
599
 
 
600
typedef struct {
 
601
    erts_smp_mtx_t mtx;
 
602
    erts_misc_aux_work_t *first;
 
603
    erts_misc_aux_work_t *last;
 
604
} erts_misc_aux_work_q_t;
 
605
 
 
606
typedef union {
 
607
    erts_misc_aux_work_q_t data;
 
608
    char align[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(erts_misc_aux_work_q_t))];
 
609
} erts_algnd_misc_aux_work_q_t;
 
610
 
 
611
static erts_algnd_misc_aux_work_q_t *misc_aux_work_queues;
 
612
 
 
613
ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(misc_aux_work,
 
614
                                 erts_misc_aux_work_t,
 
615
                                 200,
 
616
                                 ERTS_ALC_T_MISC_AUX_WORK)
 
617
 
 
618
static void
 
619
init_misc_aux_work(void)
 
620
{
 
621
    int ix;
 
622
 
 
623
    init_misc_aux_work_alloc();
 
624
 
 
625
    misc_aux_work_queues = 
 
626
        erts_alloc_permanent_cache_aligned(ERTS_ALC_T_MISC_AUX_WORK_Q,
 
627
                                           erts_no_schedulers *
 
628
                                           sizeof(erts_algnd_misc_aux_work_q_t));
 
629
 
 
630
    for (ix = 0; ix < erts_no_schedulers; ix++) {
 
631
        erts_smp_mtx_init_x(&misc_aux_work_queues[ix].data.mtx,
 
632
                            "misc_aux_work_queue",
 
633
                            make_small(ix + 1));
 
634
        misc_aux_work_queues[ix].data.first = NULL;
 
635
        misc_aux_work_queues[ix].data.last = NULL;
 
636
    }
 
637
}
 
638
 
 
639
static void
 
640
handle_misc_aux_work(ErtsSchedulerData *esdp)
 
641
{
 
642
    int ix = (int) esdp->no - 1;
 
643
    erts_misc_aux_work_t *mawp;
 
644
 
 
645
    erts_smp_mtx_lock(&misc_aux_work_queues[ix].data.mtx);
 
646
    mawp = misc_aux_work_queues[ix].data.first;
 
647
    misc_aux_work_queues[ix].data.first = NULL;
 
648
    misc_aux_work_queues[ix].data.last = NULL;
 
649
    erts_smp_mtx_unlock(&misc_aux_work_queues[ix].data.mtx);
 
650
 
 
651
    while (mawp) {
 
652
        erts_misc_aux_work_t *free_mawp;
 
653
        mawp->func(mawp->arg);
 
654
        free_mawp = mawp;
 
655
        mawp = mawp->next;
 
656
        misc_aux_work_free(free_mawp);
 
657
    }
 
658
}
 
659
 
 
660
void
 
661
erts_smp_schedule_misc_aux_work(int ignore_self,
 
662
                                int max_sched,
 
663
                                void (*func)(void *),
 
664
                                void *arg)
 
665
{
 
666
    int ix, ignore_ix = -1;
 
667
 
 
668
    if (ignore_self) {
 
669
        ErtsSchedulerData *esdp = erts_get_scheduler_data();
 
670
        if (esdp)
 
671
            ignore_ix = (int) esdp->no - 1;
 
672
    }
 
673
 
 
674
    ASSERT(0 <= max_sched && max_sched <= erts_no_schedulers);
 
675
 
 
676
    for (ix = 0; ix < max_sched; ix++) {
 
677
        erts_aint32_t aux_work;
 
678
        erts_misc_aux_work_t *mawp;
 
679
        ErtsSchedulerSleepInfo *ssi;
 
680
        if (ix == ignore_ix)
 
681
            continue;
 
682
 
 
683
        mawp = misc_aux_work_alloc();
 
684
 
 
685
        mawp->func = func;
 
686
        mawp->arg = arg;
 
687
        mawp->next = NULL;
 
688
 
 
689
        erts_smp_mtx_lock(&misc_aux_work_queues[ix].data.mtx);
 
690
        if (!misc_aux_work_queues[ix].data.last)
 
691
            misc_aux_work_queues[ix].data.first = mawp;
 
692
        else
 
693
            misc_aux_work_queues[ix].data.last->next = mawp;
 
694
        misc_aux_work_queues[ix].data.last = mawp;
 
695
        erts_smp_mtx_unlock(&misc_aux_work_queues[ix].data.mtx);
 
696
 
 
697
        ssi = ERTS_SCHED_SLEEP_INFO_IX(ix);
 
698
        aux_work = erts_smp_atomic32_bor(&ssi->aux_work,
 
699
                                         ERTS_SSI_AUX_WORK_MISC);
 
700
        if ((aux_work & ERTS_SSI_AUX_WORK_MISC) == 0)
 
701
            erts_sched_poke(ssi);
 
702
   }
 
703
}
 
704
 
 
705
#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
 
706
void
 
707
erts_smp_notify_check_children_needed(void)
 
708
{
 
709
    int i;
 
710
 
 
711
    for (i = 0; i < erts_no_schedulers; i++) {
 
712
        erts_aint32_t aux_work;
 
713
        ErtsSchedulerSleepInfo *ssi;
 
714
        ssi = ERTS_SCHED_SLEEP_INFO_IX(i);
 
715
        aux_work = erts_smp_atomic32_bor(&ssi->aux_work,
 
716
                                         ERTS_SSI_AUX_WORK_CHECK_CHILDREN);
 
717
        if (!(aux_work & ERTS_SSI_AUX_WORK_CHECK_CHILDREN))
 
718
            erts_sched_poke(ssi);
 
719
    }
 
720
}
 
721
#endif
 
722
 
 
723
#ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
 
724
static ERTS_INLINE erts_aint32_t
 
725
blockable_aux_work(ErtsSchedulerData *esdp,
 
726
                   ErtsSchedulerSleepInfo *ssi,
 
727
                   erts_aint32_t aux_work)
 
728
{
 
729
    if (aux_work & ERTS_SSI_BLOCKABLE_AUX_WORK_MASK) {
 
730
        if (aux_work & ERTS_SSI_AUX_WORK_MISC) {
 
731
            aux_work = erts_smp_atomic32_band(&ssi->aux_work,
 
732
                                              ~ERTS_SSI_AUX_WORK_MISC);
 
733
            aux_work &= ~ERTS_SSI_AUX_WORK_MISC;
 
734
            handle_misc_aux_work(esdp);
 
735
        }
 
736
#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
 
737
        if (aux_work & ERTS_SSI_AUX_WORK_CHECK_CHILDREN) {
 
738
            aux_work = erts_smp_atomic32_band(&ssi->aux_work,
 
739
                                              ~ERTS_SSI_AUX_WORK_CHECK_CHILDREN);
 
740
            aux_work &= ~ERTS_SSI_AUX_WORK_CHECK_CHILDREN;
 
741
            erts_check_children();
 
742
        }
 
743
#endif
 
744
    }
 
745
    return aux_work;
 
746
}
 
747
 
 
748
#endif
 
749
 
 
750
#ifdef ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK
 
751
static ERTS_INLINE erts_aint32_t
 
752
nonblockable_aux_work(ErtsSchedulerData *esdp,
 
753
                      ErtsSchedulerSleepInfo *ssi,
 
754
                      erts_aint32_t aux_work)
 
755
{
 
756
    if (aux_work & ERTS_SSI_NONBLOCKABLE_AUX_WORK_MASK) {
 
757
 
 
758
    }
 
759
}
 
760
#endif
 
761
 
575
762
static void
576
763
prepare_for_block(void *vrq)
577
764
{
627
814
#ifdef ERTS_SMP
628
815
 
629
816
static ERTS_INLINE void
 
817
clear_sys_scheduling(void)
 
818
{
 
819
    erts_smp_atomic32_set_relb(&doing_sys_schedule, 0);
 
820
}
 
821
 
 
822
static ERTS_INLINE int
 
823
try_set_sys_scheduling(void)
 
824
{
 
825
    return 0 == erts_smp_atomic32_cmpxchg_acqb(&doing_sys_schedule, 1, 0);
 
826
}
 
827
 
 
828
#endif
 
829
 
 
830
static ERTS_INLINE int
 
831
prepare_for_sys_schedule(void)
 
832
{
 
833
#ifdef ERTS_SMP
 
834
    while (!erts_port_task_have_outstanding_io_tasks()
 
835
           && try_set_sys_scheduling()) {
 
836
        if (!erts_port_task_have_outstanding_io_tasks())
 
837
            return 1;
 
838
        clear_sys_scheduling();
 
839
    }
 
840
    return 0;
 
841
#else
 
842
    return !erts_port_task_have_outstanding_io_tasks();
 
843
#endif
 
844
}
 
845
 
 
846
#ifdef ERTS_SMP
 
847
 
 
848
static ERTS_INLINE void
 
849
sched_change_waiting_sys_to_waiting(Uint no, ErtsRunQueue *rq)
 
850
{
 
851
    ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
 
852
    ASSERT(rq->waiting < 0);
 
853
    rq->waiting *= -1;
 
854
}
 
855
 
 
856
static ERTS_INLINE void
630
857
sched_waiting(Uint no, ErtsRunQueue *rq)
631
858
{
632
859
    ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
656
883
static int ERTS_INLINE
657
884
ongoing_multi_scheduling_block(void)
658
885
{
659
 
    return erts_smp_atomic_read(&schdlr_sspnd.msb.ongoing) != 0;
 
886
    return erts_smp_atomic32_read(&schdlr_sspnd.msb.ongoing) != 0;
660
887
}
661
888
 
662
889
static ERTS_INLINE void
663
890
empty_runq(ErtsRunQueue *rq)
664
891
{
665
 
    long oifls = erts_smp_atomic_band(&rq->info_flags, ~ERTS_RUNQ_IFLG_NONEMPTY);
 
892
    erts_aint32_t oifls = erts_smp_atomic32_band(&rq->info_flags,
 
893
                                                 ~ERTS_RUNQ_IFLG_NONEMPTY);
666
894
    if (oifls & ERTS_RUNQ_IFLG_NONEMPTY) {
667
895
#ifdef DEBUG
668
 
        long empty = erts_smp_atomic_read(&no_empty_run_queues);
669
 
        ASSERT(0 <= empty && empty < erts_no_run_queues);
 
896
        erts_aint32_t empty = erts_smp_atomic32_read(&no_empty_run_queues);
 
897
        /*
 
898
         * For a short period of time no_empty_run_queues may have
 
899
         * been increased twice for a specific run queue.
 
900
         */
 
901
        ASSERT(0 <= empty && empty < 2*erts_no_run_queues);
670
902
#endif
671
 
        erts_smp_atomic_inc(&no_empty_run_queues);
 
903
        erts_smp_atomic32_inc(&no_empty_run_queues);
672
904
    }
673
905
}
674
906
 
675
907
static ERTS_INLINE void
676
908
non_empty_runq(ErtsRunQueue *rq)
677
909
{
678
 
    long oifls = erts_smp_atomic_bor(&rq->info_flags, ERTS_RUNQ_IFLG_NONEMPTY);
 
910
    erts_aint32_t oifls = erts_smp_atomic32_bor(&rq->info_flags,
 
911
                                                ERTS_RUNQ_IFLG_NONEMPTY);
679
912
    if (!(oifls & ERTS_RUNQ_IFLG_NONEMPTY)) {
680
913
#ifdef DEBUG
681
 
        long empty = erts_smp_atomic_read(&no_empty_run_queues);
682
 
        ASSERT(0 < empty && empty <= erts_no_run_queues);
683
 
#endif
684
 
        erts_smp_atomic_dec(&no_empty_run_queues);
685
 
    }
686
 
}
687
 
 
688
 
static ERTS_INLINE int
689
 
sched_spin_wake(ErtsRunQueue *rq)
690
 
{
691
 
#if ERTS_SCHED_SLEEP_SPINCOUNT == 0
692
 
    return 0;
693
 
#else
694
 
    long val;
695
 
    ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
696
 
 
697
 
    val = erts_smp_atomic_read(&rq->spin_waiter);
698
 
    ASSERT(val >= 0);
699
 
    if (val != 0) {
700
 
        erts_smp_atomic_inc(&rq->spin_wake);
701
 
        return 1;
702
 
    }
703
 
    return 0;
704
 
#endif
705
 
}
706
 
 
707
 
static ERTS_INLINE int
708
 
sched_spin_wake_all(ErtsRunQueue *rq)
709
 
{
710
 
#if ERTS_SCHED_SLEEP_SPINCOUNT == 0
711
 
    return 0;
712
 
#else
713
 
    long val;
714
 
    ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
715
 
 
716
 
    val = erts_smp_atomic_read(&rq->spin_waiter);
717
 
    ASSERT(val >= 0);
718
 
    if (val != 0)
719
 
        erts_smp_atomic_add(&rq->spin_wake, val);
720
 
    return val;
721
 
#endif
722
 
}
 
914
        erts_aint32_t empty = erts_smp_atomic32_read(&no_empty_run_queues);
 
915
        /*
 
916
         * For a short period of time no_empty_run_queues may have
 
917
         * been increased twice for a specific run queue.
 
918
         */
 
919
        ASSERT(0 < empty && empty <= 2*erts_no_run_queues);
 
920
#endif
 
921
        erts_smp_atomic32_dec(&no_empty_run_queues);
 
922
    }
 
923
}
 
924
 
 
925
static erts_aint32_t
 
926
sched_prep_spin_wait(ErtsSchedulerSleepInfo *ssi)
 
927
{
 
928
    erts_aint32_t oflgs;
 
929
    erts_aint32_t nflgs = (ERTS_SSI_FLG_SLEEPING
 
930
                           | ERTS_SSI_FLG_WAITING);
 
931
    erts_aint32_t xflgs = 0;
 
932
 
 
933
    do {
 
934
        oflgs = erts_smp_atomic32_cmpxchg(&ssi->flags, nflgs, xflgs);
 
935
        if (oflgs == xflgs)
 
936
            return nflgs;
 
937
        xflgs = oflgs;
 
938
    } while (!(oflgs & ERTS_SSI_FLG_SUSPENDED));
 
939
    return oflgs;
 
940
}
 
941
 
 
942
static erts_aint32_t
 
943
sched_prep_cont_spin_wait(ErtsSchedulerSleepInfo *ssi)
 
944
{
 
945
    erts_aint32_t oflgs;
 
946
    erts_aint32_t nflgs = (ERTS_SSI_FLG_SLEEPING
 
947
                           | ERTS_SSI_FLG_WAITING);
 
948
    erts_aint32_t xflgs = ERTS_SSI_FLG_WAITING;
 
949
 
 
950
    do {
 
951
        oflgs = erts_smp_atomic32_cmpxchg(&ssi->flags, nflgs, xflgs);
 
952
        if (oflgs == xflgs)
 
953
            return nflgs;
 
954
        xflgs = oflgs;
 
955
        nflgs |= oflgs & ERTS_SSI_FLG_SUSPENDED;
 
956
    } while (oflgs & ERTS_SSI_FLG_WAITING);
 
957
    return oflgs;
 
958
}
 
959
 
 
960
static erts_aint32_t
 
961
sched_spin_wait(ErtsSchedulerSleepInfo *ssi, int spincount)
 
962
{
 
963
    int until_yield = ERTS_SCHED_SPIN_UNTIL_YIELD;
 
964
    int sc = spincount;
 
965
    erts_aint32_t flgs;
 
966
 
 
967
    do {
 
968
        flgs = erts_smp_atomic32_read(&ssi->flags);
 
969
        if ((flgs & (ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING))
 
970
            != (ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING)) {
 
971
            break;
 
972
        }
 
973
        ERTS_SPIN_BODY;
 
974
        if (--until_yield == 0) {
 
975
            until_yield = ERTS_SCHED_SPIN_UNTIL_YIELD;
 
976
            erts_thr_yield();
 
977
        }
 
978
    } while (--sc > 0);
 
979
    return flgs;
 
980
}
 
981
 
 
982
static erts_aint32_t
 
983
sched_set_sleeptype(ErtsSchedulerSleepInfo *ssi, erts_aint32_t sleep_type)
 
984
{
 
985
    erts_aint32_t oflgs;
 
986
    erts_aint32_t nflgs = ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING|sleep_type;
 
987
    erts_aint32_t xflgs = ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING;
 
988
 
 
989
    if (sleep_type == ERTS_SSI_FLG_TSE_SLEEPING)
 
990
        erts_tse_reset(ssi->event);
 
991
 
 
992
    while (1) {
 
993
        oflgs = erts_smp_atomic32_cmpxchg(&ssi->flags, nflgs, xflgs);
 
994
        if (oflgs == xflgs)
 
995
            return nflgs;
 
996
        if ((oflgs & (ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING))
 
997
            != (ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING)) {
 
998
            return oflgs;
 
999
        }
 
1000
        xflgs = oflgs;
 
1001
        nflgs |= oflgs & ERTS_SSI_FLG_SUSPENDED;
 
1002
    }
 
1003
}
 
1004
 
 
1005
#define ERTS_SCHED_WAIT_WOKEN(FLGS)                             \
 
1006
  (((FLGS) & (ERTS_SSI_FLG_WAITING|ERTS_SSI_FLG_SUSPENDED))     \
 
1007
   != ERTS_SSI_FLG_WAITING)
723
1008
 
724
1009
static void
725
 
sched_sys_wait(Uint no, ErtsRunQueue *rq)
 
1010
scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
726
1011
{
727
 
    long dt;
728
 
#if ERTS_SCHED_SLEEP_SPINCOUNT != 0
729
 
    int val;
730
 
    int spincount = ERTS_SCHED_SLEEP_SPINCOUNT;
 
1012
    ErtsSchedulerSleepInfo *ssi = esdp->ssi;
 
1013
    int spincount;
 
1014
    erts_aint32_t flgs;
 
1015
#if defined(ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK) \
 
1016
    || defined(ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK)
 
1017
    erts_aint32_t aux_work;
 
1018
#endif
 
1019
 
731
1020
    ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
732
1021
 
733
 
#endif
734
 
 
735
 
    sched_waiting_sys(no, rq);
736
 
 
737
 
#if ERTS_SCHED_SLEEP_SPINCOUNT != 0
738
 
    erts_smp_atomic_inc(&rq->spin_waiter);
739
 
    erts_smp_runq_unlock(rq);
740
 
 
741
 
    erl_sys_schedule(1); /* Might give us something to do */
742
 
 
743
 
    dt = do_time_read_and_reset();
744
 
    if (dt) bump_timer(dt);
745
 
 
746
 
    while (spincount-- > 0) {
747
 
        val = erts_smp_atomic_read(&rq->spin_wake);
748
 
        ASSERT(val >= 0);
749
 
        if (val != 0) {
750
 
            erts_smp_runq_lock(rq);
751
 
            val = erts_smp_atomic_read(&rq->spin_wake);
752
 
            ASSERT(val >= 0);
753
 
            if (val != 0)
754
 
                goto woken;
755
 
            if (spincount == 0)
756
 
                goto sleep;
757
 
            erts_smp_runq_unlock(rq);
 
1022
    erts_smp_spin_lock(&rq->sleepers.lock);
 
1023
    flgs = sched_prep_spin_wait(ssi);
 
1024
    if (flgs & ERTS_SSI_FLG_SUSPENDED) {
 
1025
        /* Go suspend instead... */
 
1026
        erts_smp_spin_unlock(&rq->sleepers.lock);
 
1027
        return;
 
1028
    }
 
1029
 
 
1030
    ssi->prev = NULL;
 
1031
    ssi->next = rq->sleepers.list;
 
1032
    if (rq->sleepers.list)
 
1033
        rq->sleepers.list->prev = ssi;
 
1034
    rq->sleepers.list = ssi;
 
1035
    erts_smp_spin_unlock(&rq->sleepers.lock);
 
1036
 
 
1037
    /*
 
1038
     * If all schedulers are waiting, one of them *should*
 
1039
     * be waiting in erl_sys_schedule()
 
1040
     */
 
1041
 
 
1042
    if (!prepare_for_sys_schedule()) {
 
1043
 
 
1044
        sched_waiting(esdp->no, rq);
 
1045
 
 
1046
        erts_smp_runq_unlock(rq);
 
1047
 
 
1048
        spincount = ERTS_SCHED_TSE_SLEEP_SPINCOUNT;
 
1049
 
 
1050
    tse_wait:
 
1051
 
 
1052
#ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
 
1053
        aux_work = erts_smp_atomic32_read(&ssi->aux_work);
 
1054
    tse_blockable_aux_work:
 
1055
        aux_work = blockable_aux_work(esdp, ssi, aux_work);
 
1056
#endif
 
1057
        erts_smp_activity_begin(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
 
1058
 
 
1059
        while (1) {
 
1060
 
 
1061
#ifdef ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK
 
1062
#ifndef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
 
1063
            aux_work = erts_smp_atomic32_read(&ssi->aux_work);
 
1064
#endif
 
1065
            nonblockable_aux_work(esdp, ssi, aux_work);
 
1066
#endif
 
1067
 
 
1068
            flgs = sched_spin_wait(ssi, spincount);
 
1069
            if (flgs & ERTS_SSI_FLG_SLEEPING) {
 
1070
                ASSERT(flgs & ERTS_SSI_FLG_WAITING);
 
1071
                flgs = sched_set_sleeptype(ssi, ERTS_SSI_FLG_TSE_SLEEPING);
 
1072
                if (flgs & ERTS_SSI_FLG_SLEEPING) {
 
1073
                    int res;
 
1074
                    ASSERT(flgs & ERTS_SSI_FLG_TSE_SLEEPING);
 
1075
                    ASSERT(flgs & ERTS_SSI_FLG_WAITING);
 
1076
                    do {
 
1077
                        res = erts_tse_wait(ssi->event);
 
1078
                    } while (res == EINTR);
 
1079
                }
 
1080
            }
 
1081
 
 
1082
            if (!(flgs & ERTS_SSI_FLG_WAITING)) {
 
1083
                ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
 
1084
                break;
 
1085
            }
 
1086
 
 
1087
            flgs = sched_prep_cont_spin_wait(ssi);
 
1088
            spincount = ERTS_SCHED_TSE_SLEEP_SPINCOUNT;
 
1089
 
 
1090
            if (!(flgs & ERTS_SSI_FLG_WAITING)) {
 
1091
                ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
 
1092
                break;
 
1093
            }
 
1094
 
 
1095
#ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
 
1096
            aux_work = erts_smp_atomic32_read(&ssi->aux_work);
 
1097
            if (aux_work & ERTS_SSI_BLOCKABLE_AUX_WORK_MASK) {
 
1098
                erts_smp_activity_end(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
 
1099
                goto tse_blockable_aux_work;
 
1100
            }
 
1101
#endif
 
1102
 
758
1103
        }
759
 
    }
760
 
 
761
 
    erts_smp_runq_lock(rq);
762
 
    val = erts_smp_atomic_read(&rq->spin_wake);
763
 
    ASSERT(val >= 0);
764
 
    if (val != 0) {
765
 
    woken:
766
 
        erts_smp_atomic_dec(&rq->spin_wake);
767
 
        ASSERT(erts_smp_atomic_read(&rq->spin_wake) >= 0);
768
 
        erts_smp_atomic_dec(&rq->spin_waiter);
769
 
        ASSERT(erts_smp_atomic_read(&rq->spin_waiter) >= 0);
 
1104
 
 
1105
        erts_smp_activity_end(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
 
1106
 
 
1107
        if (flgs & ~ERTS_SSI_FLG_SUSPENDED)
 
1108
            erts_smp_atomic32_band(&ssi->flags, ERTS_SSI_FLG_SUSPENDED);
 
1109
 
 
1110
        erts_smp_runq_lock(rq);
 
1111
        sched_active(esdp->no, rq);
 
1112
 
770
1113
    }
771
1114
    else {
772
 
    sleep:
773
 
        erts_smp_atomic_dec(&rq->spin_waiter);
774
 
        ASSERT(erts_smp_atomic_read(&rq->spin_waiter) >= 0);
 
1115
        erts_aint_t dt;
 
1116
 
 
1117
        erts_smp_atomic32_set(&function_calls, 0);
 
1118
        *fcalls = 0;
 
1119
 
 
1120
        sched_waiting_sys(esdp->no, rq);
 
1121
 
 
1122
        erts_smp_runq_unlock(rq);
 
1123
 
 
1124
        spincount = ERTS_SCHED_SYS_SLEEP_SPINCOUNT;
 
1125
 
 
1126
        while (spincount-- > 0) {
 
1127
 
 
1128
        sys_poll_aux_work:
 
1129
 
 
1130
            ASSERT(!erts_port_task_have_outstanding_io_tasks());
 
1131
 
 
1132
            erl_sys_schedule(1); /* Might give us something to do */
 
1133
 
 
1134
            dt = erts_do_time_read_and_reset();
 
1135
            if (dt) erts_bump_timer(dt);
 
1136
 
 
1137
        sys_aux_work:
 
1138
 
 
1139
#ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
 
1140
            aux_work = erts_smp_atomic32_read(&ssi->aux_work);
 
1141
            aux_work = blockable_aux_work(esdp, ssi, aux_work);
 
1142
#endif
 
1143
#ifdef ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK
 
1144
#ifndef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
 
1145
            aux_work = erts_smp_atomic32_read(&ssi->aux_work);
 
1146
#endif
 
1147
            nonblockable_aux_work(esdp, ssi, aux_work);
 
1148
#endif
 
1149
 
 
1150
            flgs = erts_smp_atomic32_read(&ssi->flags);
 
1151
            if (!(flgs & ERTS_SSI_FLG_WAITING)) {
 
1152
                ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
 
1153
                goto sys_woken;
 
1154
            }
 
1155
            if (!(flgs & ERTS_SSI_FLG_SLEEPING)) {
 
1156
                flgs = sched_prep_cont_spin_wait(ssi);
 
1157
                if (!(flgs & ERTS_SSI_FLG_WAITING)) {
 
1158
                    ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
 
1159
                    goto sys_woken;
 
1160
                }
 
1161
            }
 
1162
 
 
1163
            /*
 
1164
             * If we got new I/O tasks we aren't allowed to
 
1165
             * call erl_sys_schedule() until it is handled.
 
1166
             */
 
1167
            if (erts_port_task_have_outstanding_io_tasks()) {
 
1168
                clear_sys_scheduling();
 
1169
                /*
 
1170
                 * Got to check that we still got I/O tasks; otherwise
 
1171
                 * we have to continue checking for I/O...
 
1172
                 */
 
1173
                if (!prepare_for_sys_schedule()) {
 
1174
                    spincount *= ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT;
 
1175
                    goto tse_wait;
 
1176
                }
 
1177
            }
 
1178
        }
 
1179
 
 
1180
        erts_smp_runq_lock(rq);
 
1181
 
775
1182
        /*
776
1183
         * If we got new I/O tasks we aren't allowed to
777
1184
         * sleep in erl_sys_schedule().
778
1185
         */
779
 
        if (!erts_port_task_have_outstanding_io_tasks()) {
780
 
#endif
781
 
 
 
1186
        if (erts_port_task_have_outstanding_io_tasks()) {
 
1187
            clear_sys_scheduling();
 
1188
 
 
1189
            /*
 
1190
             * Got to check that we still got I/O tasks; otherwise
 
1191
             * we have to wait in erl_sys_schedule() after all...
 
1192
             */
 
1193
            if (prepare_for_sys_schedule())
 
1194
                goto do_sys_schedule;
 
1195
 
 
1196
            /*
 
1197
             * Not allowed to wait in erl_sys_schedule;
 
1198
             * do tse wait instead...
 
1199
             */
 
1200
            sched_change_waiting_sys_to_waiting(esdp->no, rq);
 
1201
            erts_smp_runq_unlock(rq);
 
1202
            spincount = 0;
 
1203
            goto tse_wait;
 
1204
        }
 
1205
        else {
 
1206
        do_sys_schedule:
782
1207
            erts_sys_schedule_interrupt(0);
 
1208
            flgs = sched_set_sleeptype(ssi, ERTS_SSI_FLG_POLL_SLEEPING);
 
1209
            if (!(flgs & ERTS_SSI_FLG_SLEEPING)) {
 
1210
                if (!(flgs & ERTS_SSI_FLG_WAITING))
 
1211
                    goto sys_locked_woken;
 
1212
                erts_smp_runq_unlock(rq);
 
1213
                flgs = sched_prep_cont_spin_wait(ssi);
 
1214
                if (!(flgs & ERTS_SSI_FLG_WAITING)) {
 
1215
                    ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
 
1216
                    goto sys_woken;
 
1217
                }
 
1218
                ASSERT(!erts_port_task_have_outstanding_io_tasks());
 
1219
                goto sys_poll_aux_work;
 
1220
            }
 
1221
 
 
1222
            ASSERT(flgs & ERTS_SSI_FLG_POLL_SLEEPING);
 
1223
            ASSERT(flgs & ERTS_SSI_FLG_WAITING);
 
1224
 
783
1225
            erts_smp_runq_unlock(rq);
784
1226
 
 
1227
            ASSERT(!erts_port_task_have_outstanding_io_tasks());
 
1228
 
785
1229
            erl_sys_schedule(0);
786
1230
 
787
 
            dt = do_time_read_and_reset();
788
 
            if (dt) bump_timer(dt);
789
 
 
 
1231
            dt = erts_do_time_read_and_reset();
 
1232
            if (dt) erts_bump_timer(dt);
 
1233
 
 
1234
            flgs = sched_prep_cont_spin_wait(ssi);
 
1235
            if (flgs & ERTS_SSI_FLG_WAITING)
 
1236
                goto sys_aux_work;
 
1237
 
 
1238
        sys_woken:
790
1239
            erts_smp_runq_lock(rq);
791
 
 
792
 
#if ERTS_SCHED_SLEEP_SPINCOUNT != 0
 
1240
        sys_locked_woken:
 
1241
            clear_sys_scheduling();
 
1242
            if (flgs & ~ERTS_SSI_FLG_SUSPENDED)
 
1243
                erts_smp_atomic32_band(&ssi->flags, ERTS_SSI_FLG_SUSPENDED);
 
1244
            sched_active_sys(esdp->no, rq);
793
1245
        }
794
1246
    }
795
 
#endif
796
 
 
797
 
    sched_active_sys(no, rq);
 
1247
 
 
1248
    ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
 
1249
}
 
1250
 
 
1251
static ERTS_INLINE erts_aint32_t
 
1252
ssi_flags_set_wake(ErtsSchedulerSleepInfo *ssi)
 
1253
{
 
1254
    /* reset all flags but suspended */
 
1255
    erts_aint32_t oflgs;
 
1256
    erts_aint32_t nflgs = 0;
 
1257
    erts_aint32_t xflgs = ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING;
 
1258
    while (1) {
 
1259
        oflgs = erts_smp_atomic32_cmpxchg(&ssi->flags, nflgs, xflgs);
 
1260
        if (oflgs == xflgs)
 
1261
            return oflgs;
 
1262
        nflgs = oflgs & ERTS_SSI_FLG_SUSPENDED;
 
1263
        xflgs = oflgs;
 
1264
    }
798
1265
}
799
1266
 
800
1267
static void
801
 
sched_cnd_wait(Uint no, ErtsRunQueue *rq)
 
1268
wake_scheduler(ErtsRunQueue *rq, int incq, int one)
802
1269
{
803
 
#if ERTS_SCHED_SLEEP_SPINCOUNT != 0
804
 
    int val;
805
 
    int spincount = ERTS_SCHED_SLEEP_SPINCOUNT;
806
 
    ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
807
 
#endif
808
 
 
809
 
    sched_waiting(no, rq);
810
 
    erts_smp_activity_begin(ERTS_ACTIVITY_WAIT,
811
 
                            prepare_for_block,
812
 
                            resume_after_block,
813
 
                            (void *) rq);
814
 
 
815
 
#if ERTS_SCHED_SLEEP_SPINCOUNT == 0
816
 
    erts_smp_cnd_wait(&rq->cnd, &rq->mtx);
817
 
#else
818
 
    erts_smp_atomic_inc(&rq->spin_waiter);
819
 
    erts_smp_mtx_unlock(&rq->mtx);
820
 
 
821
 
    while (spincount-- > 0) {
822
 
        val = erts_smp_atomic_read(&rq->spin_wake);
823
 
        ASSERT(val >= 0);
824
 
        if (val != 0) {
825
 
            erts_smp_mtx_lock(&rq->mtx);
826
 
            val = erts_smp_atomic_read(&rq->spin_wake);
827
 
            ASSERT(val >= 0);
828
 
            if (val != 0)
829
 
                goto woken;
830
 
            if (spincount == 0)
831
 
                goto sleep;
832
 
            erts_smp_mtx_unlock(&rq->mtx);
 
1270
    int res;
 
1271
    ErtsSchedulerSleepInfo *ssi;
 
1272
    ErtsSchedulerSleepList *sl;
 
1273
 
 
1274
    /*
 
1275
     * The unlocked run queue is not strictly necessary
 
1276
     * from a thread safety or deadlock prevention
 
1277
     * perspective. It will, however, cost us performance
 
1278
     * if it is locked during wakup of another scheduler,
 
1279
     * so all code *should* handle this without having
 
1280
     * the lock on the run queue.
 
1281
     */
 
1282
    ERTS_SMP_LC_ASSERT(!erts_smp_lc_runq_is_locked(rq));
 
1283
 
 
1284
    sl = &rq->sleepers;
 
1285
 
 
1286
    erts_smp_spin_lock(&sl->lock);
 
1287
    ssi = sl->list;
 
1288
    if (!ssi)
 
1289
        erts_smp_spin_unlock(&sl->lock);
 
1290
    else if (one) {
 
1291
        erts_aint32_t flgs;
 
1292
        if (ssi->prev)
 
1293
            ssi->prev->next = ssi->next;
 
1294
        else {
 
1295
            ASSERT(sl->list == ssi);
 
1296
            sl->list = ssi->next;
833
1297
        }
834
 
    }
835
 
 
836
 
    erts_smp_mtx_lock(&rq->mtx);
837
 
    val = erts_smp_atomic_read(&rq->spin_wake);
838
 
    ASSERT(val >= 0);
839
 
    if (val == 0) {
840
 
    sleep:
841
 
        erts_smp_atomic_dec(&rq->spin_waiter);
842
 
        ASSERT(erts_smp_atomic_read(&rq->spin_waiter) >= 0);
843
 
        erts_smp_cnd_wait(&rq->cnd, &rq->mtx);
 
1298
        if (ssi->next)
 
1299
            ssi->next->prev = ssi->prev;
 
1300
 
 
1301
        res = sl->list != NULL;
 
1302
        erts_smp_spin_unlock(&sl->lock);
 
1303
 
 
1304
        ERTS_THR_MEMORY_BARRIER;
 
1305
        flgs = ssi_flags_set_wake(ssi);
 
1306
        erts_sched_finish_poke(ssi, flgs);
 
1307
 
 
1308
        if (incq && !erts_common_run_queue && (flgs & ERTS_SSI_FLG_WAITING))
 
1309
            non_empty_runq(rq);
844
1310
    }
845
1311
    else {
846
 
    woken:
847
 
        erts_smp_atomic_dec(&rq->spin_wake);
848
 
        ASSERT(erts_smp_atomic_read(&rq->spin_wake) >= 0);
849
 
        erts_smp_atomic_dec(&rq->spin_waiter);
850
 
        ASSERT(erts_smp_atomic_read(&rq->spin_waiter) >= 0);
851
 
    }
852
 
#endif
853
 
 
854
 
    erts_smp_activity_end(ERTS_ACTIVITY_WAIT,
855
 
                          prepare_for_block,
856
 
                          resume_after_block,
857
 
                          (void *) rq);
858
 
 
859
 
    sched_active(no, rq);
860
 
}
861
 
 
862
 
static void
863
 
wake_one_scheduler(void)
864
 
{
865
 
    ASSERT(erts_common_run_queue);
866
 
    ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(erts_common_run_queue));
867
 
    if (erts_common_run_queue->waiting) {
868
 
        if (!sched_spin_wake(erts_common_run_queue)) {
869
 
            if (erts_common_run_queue->waiting == -1) /* One scheduler waiting
870
 
                                                         and doing so in
871
 
                                                         sys_schedule */
872
 
                erts_sys_schedule_interrupt(1);
873
 
            else
874
 
                erts_smp_cnd_signal(&erts_common_run_queue->cnd);
875
 
        }
876
 
    }
877
 
}
878
 
 
879
 
static void
880
 
wake_scheduler(ErtsRunQueue *rq, int incq)
881
 
{
882
 
    ASSERT(!erts_common_run_queue);
883
 
    ASSERT(-1 <= rq->waiting && rq->waiting <= 1);
884
 
    ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
885
 
    if (rq->waiting && !rq->woken) {
886
 
        if (!sched_spin_wake(rq)) {
887
 
            if (rq->waiting < 0)
888
 
                erts_sys_schedule_interrupt(1);
889
 
            else
890
 
                erts_smp_cnd_signal(&rq->cnd);
891
 
        }
892
 
        rq->woken = 1;
893
 
        if (incq)
894
 
            non_empty_runq(rq);
 
1312
        sl->list = NULL;
 
1313
        erts_smp_spin_unlock(&sl->lock);
 
1314
 
 
1315
        ERTS_THR_MEMORY_BARRIER;
 
1316
        do {
 
1317
            ErtsSchedulerSleepInfo *wake_ssi = ssi;
 
1318
            ssi = ssi->next;
 
1319
            erts_sched_finish_poke(wake_ssi, ssi_flags_set_wake(wake_ssi));
 
1320
        } while (ssi);
895
1321
    }
896
1322
}
897
1323
 
898
1324
static void
899
1325
wake_all_schedulers(void)
900
1326
{
901
 
    if (erts_common_run_queue) {
902
 
        erts_smp_runq_lock(erts_common_run_queue);
903
 
        if (erts_common_run_queue->waiting) {
904
 
            if (erts_common_run_queue->waiting < 0)
905
 
                erts_sys_schedule_interrupt(1);
906
 
            sched_spin_wake_all(erts_common_run_queue);
907
 
            erts_smp_cnd_broadcast(&erts_common_run_queue->cnd);
908
 
        }
909
 
        erts_smp_runq_unlock(erts_common_run_queue);
910
 
    }
 
1327
    if (erts_common_run_queue)
 
1328
        wake_scheduler(erts_common_run_queue, 0, 0);
911
1329
    else {
912
1330
        int ix;
913
1331
        for (ix = 0; ix < erts_no_run_queues; ix++) {
914
1332
            ErtsRunQueue *rq = ERTS_RUNQ_IX(ix);
915
 
            erts_smp_runq_lock(rq);
916
 
            wake_scheduler(rq, 0);
917
 
            erts_smp_runq_unlock(rq);
 
1333
            wake_scheduler(rq, 0, 1);
918
1334
        }
919
1335
    }
920
1336
}
922
1338
static ERTS_INLINE int
923
1339
chk_wake_sched(ErtsRunQueue *crq, int ix, int activate)
924
1340
{
925
 
    long iflgs;
 
1341
    erts_aint32_t iflgs;
926
1342
    ErtsRunQueue *wrq;
927
1343
    if (crq->ix == ix)
928
1344
        return 0;
929
1345
    wrq = ERTS_RUNQ_IX(ix);
930
 
    iflgs = erts_smp_atomic_read(&wrq->info_flags);
 
1346
    iflgs = erts_smp_atomic32_read(&wrq->info_flags);
931
1347
    if (!(iflgs & (ERTS_RUNQ_IFLG_SUSPENDED|ERTS_RUNQ_IFLG_NONEMPTY))) {
932
 
        erts_smp_xrunq_lock(crq, wrq);
933
1348
        if (activate) {
934
 
            if (ix == erts_smp_atomic_cmpxchg(&balance_info.active_runqs, ix+1, ix)) {
 
1349
            if (ix == erts_smp_atomic32_cmpxchg(&balance_info.active_runqs,
 
1350
                                                ix+1,
 
1351
                                                ix)) {
 
1352
                erts_smp_xrunq_lock(crq, wrq);
935
1353
                wrq->flags &= ~ERTS_RUNQ_FLG_INACTIVE;
 
1354
                erts_smp_xrunq_unlock(crq, wrq);
936
1355
            }
937
1356
        }
938
 
        wake_scheduler(wrq, 0);
939
 
        erts_smp_xrunq_unlock(crq, wrq);
 
1357
        wake_scheduler(wrq, 0, 1);
940
1358
        return 1;
941
1359
    }
942
1360
    return 0;
947
1365
{
948
1366
    int ix = crq->ix;
949
1367
    int stop_ix = ix;
950
 
    int active_ix = erts_smp_atomic_read(&balance_info.active_runqs);
951
 
    int balance_ix = erts_smp_atomic_read(&balance_info.used_runqs);
 
1368
    int active_ix = erts_smp_atomic32_read(&balance_info.active_runqs);
 
1369
    int balance_ix = erts_smp_atomic32_read(&balance_info.used_runqs);
952
1370
 
953
1371
    if (active_ix > balance_ix)
954
1372
        active_ix = balance_ix;
982
1400
smp_notify_inc_runq(ErtsRunQueue *runq)
983
1401
{
984
1402
#ifdef ERTS_SMP
985
 
    if (erts_common_run_queue)
986
 
        wake_one_scheduler();
987
 
    else
988
 
        wake_scheduler(runq, 1);
 
1403
    if (runq)
 
1404
        wake_scheduler(runq, 1, 1);
989
1405
#endif
990
1406
}
991
1407
 
992
1408
void
993
 
erts_smp_notify_inc_runq__(ErtsRunQueue *runq)
 
1409
erts_smp_notify_inc_runq(ErtsRunQueue *runq)
994
1410
{
995
1411
    smp_notify_inc_runq(runq);
996
1412
}
997
1413
 
 
1414
void
 
1415
erts_sched_notify_check_cpu_bind(void)
 
1416
{
 
1417
#ifdef ERTS_SMP
 
1418
    int ix;
 
1419
    if (erts_common_run_queue) {
 
1420
        for (ix = 0; ix < erts_no_schedulers; ix++)
 
1421
            erts_smp_atomic32_set(&ERTS_SCHEDULER_IX(ix)->chk_cpu_bind, 1);
 
1422
        wake_all_schedulers();
 
1423
    }
 
1424
    else {
 
1425
        for (ix = 0; ix < erts_no_run_queues; ix++) {
 
1426
            ErtsRunQueue *rq = ERTS_RUNQ_IX(ix);
 
1427
            erts_smp_runq_lock(rq);
 
1428
            rq->flags |= ERTS_RUNQ_FLG_CHK_CPU_BIND;
 
1429
            erts_smp_runq_unlock(rq);
 
1430
            wake_scheduler(rq, 0, 1);
 
1431
        };
 
1432
    }
 
1433
#else
 
1434
    erts_sched_check_cpu_bind(erts_get_scheduler_data());
 
1435
#endif
 
1436
}
 
1437
 
 
1438
 
998
1439
#ifdef ERTS_SMP
999
1440
 
1000
1441
ErtsRunQueue *
1136
1577
evacuate_run_queue(ErtsRunQueue *evac_rq, ErtsRunQueue *rq)
1137
1578
{
1138
1579
    Port *prt;
 
1580
    int notify_to_rq = 0;
1139
1581
    int prio;
1140
1582
    int prt_locked = 0;
1141
1583
    int rq_locked = 0;
1142
1584
    int evac_rq_locked = 1;
 
1585
    ErtsMigrateResult mres;
1143
1586
 
1144
1587
    erts_smp_runq_lock(evac_rq);
1145
1588
 
 
1589
    erts_smp_atomic32_bor(&evac_rq->scheduler->ssi->flags,
 
1590
                          ERTS_SSI_FLG_SUSPENDED);
 
1591
 
1146
1592
    evac_rq->flags &= ~ERTS_RUNQ_FLGS_IMMIGRATE_QMASK;
1147
1593
    evac_rq->flags |= (ERTS_RUNQ_FLGS_EMIGRATE_QMASK
1148
1594
                       | ERTS_RUNQ_FLGS_EVACUATE_QMASK
1149
1595
                       | ERTS_RUNQ_FLG_SUSPENDED);
1150
1596
 
1151
 
    erts_smp_atomic_bor(&evac_rq->info_flags, ERTS_RUNQ_IFLG_SUSPENDED);
1152
 
 
 
1597
    erts_smp_atomic32_bor(&evac_rq->info_flags, ERTS_RUNQ_IFLG_SUSPENDED);
1153
1598
    /*
1154
1599
     * Need to set up evacuation paths first since we
1155
1600
     * may release the run queue lock on evac_rq
1177
1622
    /* Evacuate scheduled ports */
1178
1623
    prt = evac_rq->ports.start;
1179
1624
    while (prt) {
1180
 
        (void) erts_port_migrate(prt, &prt_locked,
 
1625
        mres = erts_port_migrate(prt, &prt_locked,
1181
1626
                                 evac_rq, &evac_rq_locked,
1182
1627
                                 rq, &rq_locked);
 
1628
        if (mres == ERTS_MIGRATE_SUCCESS)
 
1629
            notify_to_rq = 1;
1183
1630
        if (prt_locked)
1184
1631
            erts_smp_port_unlock(prt);
1185
1632
        if (!evac_rq_locked) {
1208
1655
                        goto end_of_proc;
1209
1656
                }
1210
1657
 
1211
 
                (void) erts_proc_migrate(proc, &proc_locks,
 
1658
                mres = erts_proc_migrate(proc, &proc_locks,
1212
1659
                                         evac_rq, &evac_rq_locked,
1213
1660
                                         rq, &rq_locked);
 
1661
                if (mres == ERTS_MIGRATE_SUCCESS)
 
1662
                    notify_to_rq = 1;
1214
1663
                if (proc_locks)
1215
1664
                    erts_smp_proc_unlock(proc, proc_locks);
1216
1665
                if (!evac_rq_locked) {
1242
1691
    if (rq_locked)
1243
1692
        erts_smp_runq_unlock(rq);
1244
1693
 
1245
 
    if (!evac_rq_locked)
1246
 
        erts_smp_runq_lock(evac_rq);
1247
 
    wake_scheduler(evac_rq, 0);
1248
 
    erts_smp_runq_unlock(evac_rq);
 
1694
    if (evac_rq_locked)
 
1695
        erts_smp_runq_unlock(evac_rq);
 
1696
 
 
1697
    if (notify_to_rq)
 
1698
        smp_notify_inc_runq(rq);
 
1699
 
 
1700
    wake_scheduler(evac_rq, 0, 1);
1249
1701
}
1250
1702
 
1251
1703
static int
1391
1843
check_possible_steal_victim(ErtsRunQueue *rq, int *rq_lockedp, int vix)
1392
1844
{
1393
1845
    ErtsRunQueue *vrq = ERTS_RUNQ_IX(vix);
1394
 
    long iflgs = erts_smp_atomic_read(&vrq->info_flags);
 
1846
    erts_aint32_t iflgs = erts_smp_atomic32_read(&vrq->info_flags);
1395
1847
    if (iflgs & ERTS_RUNQ_IFLG_NONEMPTY)
1396
1848
        return try_steal_task_from_victim(rq, rq_lockedp, vrq);
1397
1849
    else
1421
1873
 
1422
1874
    ERTS_SMP_LC_CHK_RUNQ_LOCK(rq, rq_locked);
1423
1875
 
1424
 
    active_rqs = erts_smp_atomic_read(&balance_info.active_runqs);
1425
 
    blnc_rqs = erts_smp_atomic_read(&balance_info.used_runqs);
 
1876
    active_rqs = erts_smp_atomic32_read(&balance_info.active_runqs);
 
1877
    blnc_rqs = erts_smp_atomic32_read(&balance_info.used_runqs);
1426
1878
 
1427
1879
    if (active_rqs > blnc_rqs)
1428
1880
        active_rqs = blnc_rqs;
1433
1885
        if (active_rqs < blnc_rqs) {
1434
1886
            int no = blnc_rqs - active_rqs;
1435
1887
            int stop_ix = vix = active_rqs + rq->ix % no;
1436
 
            while (erts_smp_atomic_read(&no_empty_run_queues) < blnc_rqs) {
 
1888
            while (erts_smp_atomic32_read(&no_empty_run_queues) < blnc_rqs) {
1437
1889
                res = check_possible_steal_victim(rq, &rq_locked, vix);
1438
1890
                if (res)
1439
1891
                    goto done;
1448
1900
        vix = rq->ix;
1449
1901
 
1450
1902
        /* ... then try to steal a job from another active queue... */
1451
 
        while (erts_smp_atomic_read(&no_empty_run_queues) < blnc_rqs) {
 
1903
        while (erts_smp_atomic32_read(&no_empty_run_queues) < blnc_rqs) {
1452
1904
            vix++;
1453
1905
            if (vix >= active_rqs)
1454
1906
                vix = 0;
1473
1925
    return res;
1474
1926
}
1475
1927
 
1476
 
#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
1477
 
void
1478
 
erts_smp_notify_check_children_needed(void)
1479
 
{
1480
 
    int i;
1481
 
    for (i = 0; i < erts_no_schedulers; i++) {
1482
 
        erts_smp_runq_lock(ERTS_SCHEDULER_IX(i)->run_queue);
1483
 
        ERTS_SCHEDULER_IX(i)->check_children = 1;
1484
 
        if (!erts_common_run_queue)
1485
 
            wake_scheduler(ERTS_SCHEDULER_IX(i)->run_queue, 0);
1486
 
        erts_smp_runq_unlock(ERTS_SCHEDULER_IX(i)->run_queue);
1487
 
    }
1488
 
    if (ongoing_multi_scheduling_block()) {
1489
 
        /* Also blocked schedulers need to check children */
1490
 
        erts_smp_mtx_lock(&schdlr_sspnd.mtx);
1491
 
        for (i = 0; i < erts_no_schedulers; i++)
1492
 
            ERTS_SCHEDULER_IX(i)->blocked_check_children = 1;
1493
 
        erts_smp_cnd_broadcast(&schdlr_sspnd.cnd);
1494
 
        erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
1495
 
    }
1496
 
    if (erts_common_run_queue)
1497
 
        wake_all_schedulers();
1498
 
}
1499
 
#endif
1500
 
 
1501
1928
/* Run queue balancing */
1502
1929
 
1503
1930
typedef struct {
1561
1988
static void
1562
1989
check_balance(ErtsRunQueue *c_rq)
1563
1990
{
 
1991
#if ERTS_MAX_PROCESSES >= (1 << 27)
 
1992
#  error check_balance() assumes ERTS_MAX_PROCESS < (1 << 27)
 
1993
#endif
1564
1994
    ErtsRunQueueBalance avg = {0};
1565
1995
    Sint64 scheds_reds, full_scheds_reds;
1566
1996
    int forced, active, current_active, oowc, half_full_scheds, full_scheds,
1567
1997
        mmax_len, blnc_no_rqs, qix, pix, freds_hist_ix;
1568
1998
 
1569
 
    if (erts_smp_atomic_xchg(&balance_info.checking_balance, 1)) {
 
1999
    if (erts_smp_atomic32_xchg(&balance_info.checking_balance, 1)) {
1570
2000
        c_rq->check_balance_reds = INT_MAX;
1571
2001
        return;
1572
2002
    }
1573
2003
 
1574
 
    blnc_no_rqs = (int) erts_smp_atomic_read(&balance_info.used_runqs);
 
2004
    blnc_no_rqs = (int) erts_smp_atomic32_read(&balance_info.used_runqs);
1575
2005
    if (blnc_no_rqs == 1) {
1576
2006
        c_rq->check_balance_reds = INT_MAX;
1577
 
        erts_smp_atomic_set(&balance_info.checking_balance, 0);
 
2007
        erts_smp_atomic32_set(&balance_info.checking_balance, 0);
1578
2008
        return;
1579
2009
    }
1580
2010
 
1582
2012
 
1583
2013
    if (balance_info.halftime) {        
1584
2014
        balance_info.halftime = 0;
1585
 
        erts_smp_atomic_set(&balance_info.checking_balance, 0);
 
2015
        erts_smp_atomic32_set(&balance_info.checking_balance, 0);
1586
2016
        ERTS_FOREACH_RUNQ(rq,
1587
2017
        {
1588
2018
            if (rq->waiting)
1610
2040
    forced = balance_info.forced_check_balance;
1611
2041
    balance_info.forced_check_balance = 0;
1612
2042
 
1613
 
    blnc_no_rqs = (int) erts_smp_atomic_read(&balance_info.used_runqs);
 
2043
    blnc_no_rqs = (int) erts_smp_atomic32_read(&balance_info.used_runqs);
1614
2044
    if (blnc_no_rqs == 1) {
1615
2045
        erts_smp_mtx_unlock(&balance_info.update_mtx);
1616
2046
        erts_smp_runq_lock(c_rq);
1617
2047
        c_rq->check_balance_reds = INT_MAX;
1618
 
        erts_smp_atomic_set(&balance_info.checking_balance, 0);
 
2048
        erts_smp_atomic32_set(&balance_info.checking_balance, 0);
1619
2049
        return;
1620
2050
    }
1621
2051
 
1624
2054
    if (balance_info.full_reds_history_index >= ERTS_FULL_REDS_HISTORY_SIZE)
1625
2055
        balance_info.full_reds_history_index = 0;
1626
2056
 
1627
 
    current_active = erts_smp_atomic_read(&balance_info.active_runqs);
 
2057
    current_active = erts_smp_atomic32_read(&balance_info.active_runqs);
1628
2058
 
1629
2059
    /* Read balance information for all run queues */
1630
2060
    for (qix = 0; qix < blnc_no_rqs; qix++) {
1684
2114
                    run_queue_info[qix].prio[pix].avail = 0;
1685
2115
            }
1686
2116
            else {
1687
 
                int xreds = 0;
1688
 
                int procreds = treds;
1689
 
                procreds -= run_queue_info[qix].prio[ERTS_PORT_PRIO_LEVEL].reds;
 
2117
                Sint64 xreds = 0;
 
2118
                Sint64 procreds = treds;
 
2119
                procreds -= 
 
2120
                    ((Sint64)
 
2121
                     run_queue_info[qix].prio[ERTS_PORT_PRIO_LEVEL].reds);
1690
2122
 
1691
2123
                for (pix = 0; pix < ERTS_NO_PROC_PRIO_LEVELS; pix++) {
1692
 
                    int av;
 
2124
                    Sint64 av;
1693
2125
 
1694
2126
                    if (xreds == 0)
1695
2127
                        av = 100;
1700
2132
                        if (av == 0)
1701
2133
                            av = 1;
1702
2134
                    }
1703
 
                    run_queue_info[qix].prio[pix].avail = av;
 
2135
                    run_queue_info[qix].prio[pix].avail = (int) av;
 
2136
                    ASSERT(run_queue_info[qix].prio[pix].avail >= 0);
1704
2137
                    if (pix < PRIORITY_NORMAL) /* ie., max or high */
1705
 
                        xreds += run_queue_info[qix].prio[pix].reds;
 
2138
                        xreds += (Sint64) run_queue_info[qix].prio[pix].reds;
1706
2139
                }
1707
2140
                run_queue_info[qix].prio[ERTS_PORT_PRIO_LEVEL].avail = 100;
1708
2141
            }
1807
2240
            if (max_len != 0) {
1808
2241
                int avail = avg.prio[pix].avail;
1809
2242
                if (avail != 0) {
1810
 
                    max_len = ((100*max_len - 1) / avail) + 1;
 
2243
                    max_len = (int) ((100*((Sint64) max_len) - 1)
 
2244
                                     / ((Sint64) avail)) + 1;
1811
2245
                    avg.prio[pix].max_len = max_len;
1812
2246
                    ASSERT(max_len >= 0);
1813
2247
                }
1824
2258
                    || run_queue_info[qix].prio[pix].avail == 0)
1825
2259
                    limit = 0;
1826
2260
                else
1827
 
                    limit = (((avg.prio[pix].max_len
1828
 
                               * run_queue_info[qix].prio[pix].avail) - 1)
1829
 
                             / 100 + 1);
 
2261
                    limit = (int) (((((Sint64) avg.prio[pix].max_len)
 
2262
                                     * ((Sint64) run_queue_info[qix].prio[pix].avail))
 
2263
                                    - 1)
 
2264
                                   / 100 + 1);
1830
2265
                run_queue_info[qix].prio[pix].migration_limit = limit;
1831
2266
            }
1832
2267
        }
1954
2389
    }
1955
2390
 
1956
2391
    balance_info.last_active_runqs = active;
1957
 
    erts_smp_atomic_set(&balance_info.active_runqs, active);
 
2392
    erts_smp_atomic32_set(&balance_info.active_runqs, active);
1958
2393
 
1959
2394
    balance_info.halftime = 1;
1960
 
    erts_smp_atomic_set(&balance_info.checking_balance, 0);
 
2395
    erts_smp_atomic32_set(&balance_info.checking_balance, 0);
1961
2396
 
1962
2397
    /* Write migration paths and reset balance statistics in all queues */
1963
2398
    for (qix = 0; qix < blnc_no_rqs; qix++) {
2054
2489
void
2055
2490
erts_early_init_scheduling(void)
2056
2491
{
2057
 
    early_cpu_bind_init();
2058
 
}
 
2492
    wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_MEDIUM;
 
2493
}
 
2494
 
 
2495
int
 
2496
erts_sched_set_wakeup_limit(char *str)
 
2497
{
 
2498
    if (sys_strcmp(str, "very_high") == 0)
 
2499
        wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_HIGH;
 
2500
    else if (sys_strcmp(str, "high") == 0)
 
2501
        wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_HIGH;
 
2502
    else if (sys_strcmp(str, "medium") == 0)
 
2503
        wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_MEDIUM;
 
2504
    else if (sys_strcmp(str, "low") == 0)
 
2505
        wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_LOW;
 
2506
    else if (sys_strcmp(str, "very_low") == 0)
 
2507
        wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_LOW;
 
2508
    else
 
2509
        return EINVAL;
 
2510
    return 0;
 
2511
}
 
2512
        
2059
2513
 
2060
2514
void
2061
2515
erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online)
2076
2530
 
2077
2531
    n = (int) (mrq ? no_schedulers : 1);
2078
2532
 
2079
 
    erts_aligned_run_queues = erts_alloc(ERTS_ALC_T_RUNQS,
2080
 
                                         (sizeof(ErtsAlignedRunQueue)*(n+1)));
2081
 
    if ((((Uint) erts_aligned_run_queues) & ERTS_CACHE_LINE_MASK) == 0)
2082
 
        erts_aligned_run_queues = ((ErtsAlignedRunQueue *)
2083
 
                                   ((((Uint) erts_aligned_run_queues)
2084
 
                                     & ~ERTS_CACHE_LINE_MASK)
2085
 
                                    + ERTS_CACHE_LINE_SIZE));
2086
 
 
 
2533
    erts_aligned_run_queues = 
 
2534
        erts_alloc_permanent_cache_aligned(ERTS_ALC_T_RUNQS,
 
2535
                                           sizeof(ErtsAlignedRunQueue) * n);
2087
2536
#ifdef ERTS_SMP
2088
 
    erts_smp_atomic_init(&no_empty_run_queues, 0);
 
2537
    erts_smp_atomic32_init(&no_empty_run_queues, 0);
2089
2538
#endif
2090
2539
 
 
2540
    erts_no_run_queues = n;
 
2541
 
2091
2542
    for (ix = 0; ix < n; ix++) {
2092
2543
        int pix, rix;
2093
2544
        ErtsRunQueue *rq = ERTS_RUNQ_IX(ix);
2094
2545
 
2095
2546
        rq->ix = ix;
2096
 
        erts_smp_atomic_init(&rq->info_flags, ERTS_RUNQ_IFLG_NONEMPTY);
2097
 
 
2098
 
        erts_smp_mtx_init(&rq->mtx, "run_queue");
 
2547
        erts_smp_atomic32_init(&rq->info_flags, ERTS_RUNQ_IFLG_NONEMPTY);
 
2548
 
 
2549
        /* make sure that the "extra" id correponds to the schedulers
 
2550
         * id if the esdp->no <-> ix+1 mapping change.
 
2551
         */
 
2552
 
 
2553
        erts_smp_mtx_init_x(&rq->mtx, "run_queue", make_small(ix + 1));
2099
2554
        erts_smp_cnd_init(&rq->cnd);
2100
2555
 
2101
 
        erts_smp_atomic_init(&rq->spin_waiter, 0);
2102
 
        erts_smp_atomic_init(&rq->spin_wake, 0);
 
2556
#ifdef ERTS_SMP
 
2557
        erts_smp_spinlock_init(&rq->sleepers.lock, "run_queue_sleep_list");
 
2558
        rq->sleepers.list = NULL;
 
2559
#endif
2103
2560
 
2104
2561
        rq->waiting = 0;
2105
2562
        rq->woken = 0;
2150
2607
    }
2151
2608
 
2152
2609
    erts_common_run_queue = !mrq ? ERTS_RUNQ_IX(0) : NULL;
2153
 
    erts_no_run_queues = n;
2154
2610
 
2155
2611
#ifdef ERTS_SMP
2156
2612
 
2165
2621
 
2166
2622
#endif
2167
2623
 
 
2624
    n = (int) no_schedulers;
 
2625
    erts_no_schedulers = n;
 
2626
 
 
2627
#ifdef ERTS_SMP
 
2628
    /* Create and initialize scheduler sleep info */
 
2629
 
 
2630
    aligned_sched_sleep_info =
 
2631
        erts_alloc_permanent_cache_aligned(ERTS_ALC_T_SCHDLR_SLP_INFO,
 
2632
                                           n * sizeof(ErtsAlignedSchedulerSleepInfo));
 
2633
 
 
2634
    for (ix = 0; ix < n; ix++) {
 
2635
        ErtsSchedulerSleepInfo *ssi = ERTS_SCHED_SLEEP_INFO_IX(ix);
 
2636
#if 0 /* no need to initialize these... */
 
2637
        ssi->next = NULL;
 
2638
        ssi->prev = NULL;
 
2639
#endif
 
2640
        erts_smp_atomic32_init(&ssi->flags, 0);
 
2641
        ssi->event = NULL; /* initialized in sched_thread_func */
 
2642
        erts_smp_atomic32_init(&ssi->aux_work, 0);
 
2643
    }
 
2644
#endif
 
2645
 
2168
2646
    /* Create and initialize scheduler specific data */
2169
2647
 
2170
 
    n = (int) no_schedulers;
2171
 
    erts_aligned_scheduler_data = erts_alloc(ERTS_ALC_T_SCHDLR_DATA,
2172
 
                                             (sizeof(ErtsAlignedSchedulerData)
2173
 
                                              *(n+1)));
2174
 
    if ((((Uint) erts_aligned_scheduler_data) & ERTS_CACHE_LINE_MASK) == 0)
2175
 
        erts_aligned_scheduler_data = ((ErtsAlignedSchedulerData *)
2176
 
                                       ((((Uint) erts_aligned_scheduler_data)
2177
 
                                         & ~ERTS_CACHE_LINE_MASK)
2178
 
                                        + ERTS_CACHE_LINE_SIZE));
 
2648
    erts_aligned_scheduler_data = 
 
2649
        erts_alloc_permanent_cache_aligned(ERTS_ALC_T_SCHDLR_DATA,
 
2650
                                           n*sizeof(ErtsAlignedSchedulerData));                                    
 
2651
 
2179
2652
    for (ix = 0; ix < n; ix++) {
2180
2653
        ErtsSchedulerData *esdp = ERTS_SCHEDULER_IX(ix);
2181
2654
#ifdef ERTS_SMP
2182
2655
        erts_bits_init_state(&esdp->erl_bits_state);
2183
2656
        esdp->match_pseudo_process = NULL;
 
2657
        esdp->ssi = ERTS_SCHED_SLEEP_INFO_IX(ix);
2184
2658
        esdp->free_process = NULL;
 
2659
#if HALFWORD_HEAP
 
2660
        /* Registers need to be heap allocated (correct memory range) for tracing to work */
 
2661
        esdp->save_reg = erts_alloc(ERTS_ALC_T_BEAM_REGISTER, ERTS_X_REGS_ALLOCATED * sizeof(Eterm));
 
2662
#endif
 
2663
#endif
 
2664
#if !HEAP_ON_C_STACK
 
2665
        esdp->num_tmp_heap_used = 0;
2185
2666
#endif
2186
2667
        esdp->no = (Uint) ix+1;
2187
2668
        esdp->current_process = NULL;
2202
2683
        }
2203
2684
 
2204
2685
#ifdef ERTS_SMP
2205
 
#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
2206
 
        esdp->check_children = 0;
2207
 
        esdp->blocked_check_children = 0;
2208
 
#endif
2209
 
        erts_smp_atomic_init(&esdp->suspended, 0);
2210
 
        erts_smp_atomic_init(&esdp->chk_cpu_bind, 0);
 
2686
        erts_smp_atomic32_init(&esdp->chk_cpu_bind, 0);
2211
2687
#endif
2212
2688
    }
2213
2689
 
2215
2691
    erts_smp_mtx_init(&schdlr_sspnd.mtx, "schdlr_sspnd");
2216
2692
    erts_smp_cnd_init(&schdlr_sspnd.cnd);
2217
2693
 
2218
 
    schdlr_sspnd.changing = 0;
 
2694
    erts_smp_atomic32_init(&schdlr_sspnd.changing, 0);
2219
2695
    schdlr_sspnd.online = no_schedulers_online;
2220
2696
    schdlr_sspnd.curr_online = no_schedulers;
2221
 
    erts_smp_atomic_init(&schdlr_sspnd.msb.ongoing, 0);
2222
 
    erts_smp_atomic_init(&schdlr_sspnd.active, no_schedulers);
 
2697
    erts_smp_atomic32_init(&schdlr_sspnd.msb.ongoing, 0);
 
2698
    erts_smp_atomic32_init(&schdlr_sspnd.active, no_schedulers);
2223
2699
    schdlr_sspnd.msb.procs = NULL;
2224
 
    erts_smp_atomic_set(&balance_info.used_runqs,
2225
 
                        erts_common_run_queue ? 1 : no_schedulers_online);
2226
 
    erts_smp_atomic_init(&balance_info.active_runqs, no_schedulers);
 
2700
    erts_smp_atomic32_set(&balance_info.used_runqs,
 
2701
                          erts_common_run_queue ? 1 : no_schedulers_online);
 
2702
    erts_smp_atomic32_init(&balance_info.active_runqs, no_schedulers);
2227
2703
    balance_info.last_active_runqs = no_schedulers;
2228
2704
    erts_smp_mtx_init(&balance_info.update_mtx, "migration_info_update");
2229
2705
    balance_info.forced_check_balance = 0;
2230
2706
    balance_info.halftime = 1;
2231
2707
    balance_info.full_reds_history_index = 0;
2232
 
    erts_smp_atomic_init(&balance_info.checking_balance, 0);
 
2708
    erts_smp_atomic32_init(&balance_info.checking_balance, 0);
2233
2709
    balance_info.prev_rise.active_runqs = 0;
2234
2710
    balance_info.prev_rise.max_len = 0;
2235
2711
    balance_info.prev_rise.reds = 0;
2238
2714
    if (no_schedulers_online < no_schedulers) {
2239
2715
        if (erts_common_run_queue) {
2240
2716
            for (ix = no_schedulers_online; ix < no_schedulers; ix++)
2241
 
                erts_smp_atomic_set(&(ERTS_SCHEDULER_IX(ix)->suspended), 1);
 
2717
                erts_smp_atomic32_bor(&ERTS_SCHED_SLEEP_INFO_IX(ix)->flags,
 
2718
                                      ERTS_SSI_FLG_SUSPENDED);
2242
2719
        }
2243
2720
        else {
2244
2721
            for (ix = no_schedulers_online; ix < erts_no_run_queues; ix++)
2249
2726
 
2250
2727
    schdlr_sspnd.wait_curr_online = no_schedulers_online;
2251
2728
    schdlr_sspnd.curr_online *= 2; /* Boot strapping... */
2252
 
    schdlr_sspnd.changing = ERTS_SCHED_CHANGING_ONLINE;
2253
 
 
2254
 
    erts_smp_atomic_init(&doing_sys_schedule, 0);
 
2729
    ERTS_SCHDLR_SSPND_CHNG_SET((ERTS_SCHDLR_SSPND_CHNG_ONLN
 
2730
                                | ERTS_SCHDLR_SSPND_CHNG_WAITER), 0);
 
2731
 
 
2732
    erts_smp_atomic32_init(&doing_sys_schedule, 0);
 
2733
 
 
2734
    init_misc_aux_work();
2255
2735
 
2256
2736
#else /* !ERTS_SMP */
2257
2737
    {
2265
2745
    erts_no_schedulers = 1;
2266
2746
#endif
2267
2747
 
2268
 
    erts_smp_atomic_init(&function_calls, 0);
 
2748
    erts_smp_atomic32_init(&function_calls, 0);
2269
2749
 
2270
2750
    /* init port tasks */
2271
2751
    erts_port_task_init();
2272
2752
 
2273
 
    late_cpu_bind_init();
 
2753
#ifndef ERTS_SMP
 
2754
#ifdef ERTS_DO_VERIFY_UNUSED_TEMP_ALLOC
 
2755
    erts_scheduler_data->verify_unused_temp_alloc
 
2756
        = erts_alloc_get_verify_unused_temp_alloc(
 
2757
            &erts_scheduler_data->verify_unused_temp_alloc_data);
 
2758
    ERTS_VERIFY_UNUSED_TEMP_ALLOC(NULL);
 
2759
#endif
 
2760
#endif
2274
2761
}
2275
2762
 
2276
2763
ErtsRunQueue *
2382
2869
    p->rstatus = P_FREE;    
2383
2870
}
2384
2871
 
 
2872
int
 
2873
erts_get_max_no_executing_schedulers(void)
 
2874
{
 
2875
#ifdef ERTS_SMP
 
2876
    if (erts_smp_atomic32_read(&schdlr_sspnd.changing))
 
2877
        return (int) erts_no_schedulers;
 
2878
    ERTS_THR_MEMORY_BARRIER;
 
2879
    return (int) erts_smp_atomic32_read(&schdlr_sspnd.active);
 
2880
#else
 
2881
    return 1;
 
2882
#endif
 
2883
}
 
2884
 
2385
2885
#ifdef ERTS_SMP
2386
2886
 
2387
2887
static void
2397
2897
}
2398
2898
 
2399
2899
static void
 
2900
scheduler_ix_resume_wake(Uint ix)
 
2901
{
 
2902
    ErtsSchedulerSleepInfo *ssi = ERTS_SCHED_SLEEP_INFO_IX(ix);
 
2903
    erts_aint32_t xflgs = (ERTS_SSI_FLG_SLEEPING
 
2904
                           | ERTS_SSI_FLG_TSE_SLEEPING
 
2905
                           | ERTS_SSI_FLG_WAITING
 
2906
                           | ERTS_SSI_FLG_SUSPENDED);
 
2907
    erts_aint32_t oflgs;
 
2908
    do {
 
2909
        oflgs = erts_smp_atomic32_cmpxchg(&ssi->flags, 0, xflgs);
 
2910
        if (oflgs == xflgs) {
 
2911
            erts_sched_finish_poke(ssi, oflgs);
 
2912
            break;
 
2913
        }
 
2914
        xflgs = oflgs;
 
2915
    } while (oflgs & ERTS_SSI_FLG_SUSPENDED);
 
2916
}
 
2917
 
 
2918
static erts_aint32_t
 
2919
sched_prep_spin_suspended(ErtsSchedulerSleepInfo *ssi, erts_aint32_t xpct)
 
2920
{
 
2921
    erts_aint32_t oflgs;
 
2922
    erts_aint32_t nflgs = (ERTS_SSI_FLG_SLEEPING
 
2923
                           | ERTS_SSI_FLG_WAITING
 
2924
                           | ERTS_SSI_FLG_SUSPENDED);
 
2925
    erts_aint32_t xflgs = xpct;
 
2926
 
 
2927
    do {
 
2928
        oflgs = erts_smp_atomic32_cmpxchg(&ssi->flags, nflgs, xflgs);
 
2929
        if (oflgs == xflgs)
 
2930
            return nflgs;
 
2931
        xflgs = oflgs;
 
2932
    } while (oflgs & ERTS_SSI_FLG_SUSPENDED);
 
2933
 
 
2934
    return oflgs;
 
2935
}
 
2936
 
 
2937
static erts_aint32_t
 
2938
sched_spin_suspended(ErtsSchedulerSleepInfo *ssi, int spincount)
 
2939
{
 
2940
    int until_yield = ERTS_SCHED_SPIN_UNTIL_YIELD;
 
2941
    int sc = spincount;
 
2942
    erts_aint32_t flgs;
 
2943
 
 
2944
    do {
 
2945
        flgs = erts_smp_atomic32_read(&ssi->flags);
 
2946
        if ((flgs & (ERTS_SSI_FLG_SLEEPING
 
2947
                     | ERTS_SSI_FLG_WAITING
 
2948
                     | ERTS_SSI_FLG_SUSPENDED))
 
2949
            != (ERTS_SSI_FLG_SLEEPING
 
2950
                | ERTS_SSI_FLG_WAITING
 
2951
                | ERTS_SSI_FLG_SUSPENDED)) {
 
2952
            break;
 
2953
        }
 
2954
        ERTS_SPIN_BODY;
 
2955
        if (--until_yield == 0) {
 
2956
            until_yield = ERTS_SCHED_SPIN_UNTIL_YIELD;
 
2957
            erts_thr_yield();
 
2958
        }
 
2959
    } while (--sc > 0);
 
2960
    return flgs;
 
2961
}
 
2962
 
 
2963
static erts_aint32_t
 
2964
sched_set_suspended_sleeptype(ErtsSchedulerSleepInfo *ssi)
 
2965
{
 
2966
    erts_aint32_t oflgs;
 
2967
    erts_aint32_t nflgs = (ERTS_SSI_FLG_SLEEPING
 
2968
                           | ERTS_SSI_FLG_TSE_SLEEPING
 
2969
                           | ERTS_SSI_FLG_WAITING
 
2970
                           | ERTS_SSI_FLG_SUSPENDED);
 
2971
    erts_aint32_t xflgs = (ERTS_SSI_FLG_SLEEPING
 
2972
                           | ERTS_SSI_FLG_WAITING
 
2973
                           | ERTS_SSI_FLG_SUSPENDED);
 
2974
 
 
2975
    erts_tse_reset(ssi->event);
 
2976
 
 
2977
    while (1) {
 
2978
        oflgs = erts_smp_atomic32_cmpxchg(&ssi->flags, nflgs, xflgs);
 
2979
        if (oflgs == xflgs)
 
2980
            return nflgs;
 
2981
        if ((oflgs & (ERTS_SSI_FLG_SLEEPING
 
2982
                      | ERTS_SSI_FLG_WAITING
 
2983
                      | ERTS_SSI_FLG_SUSPENDED))
 
2984
            != (ERTS_SSI_FLG_SLEEPING
 
2985
                | ERTS_SSI_FLG_WAITING
 
2986
                | ERTS_SSI_FLG_SUSPENDED)) {
 
2987
            return oflgs;
 
2988
        }
 
2989
        xflgs = oflgs;
 
2990
    }
 
2991
}
 
2992
 
 
2993
static void
2400
2994
suspend_scheduler(ErtsSchedulerData *esdp)
2401
2995
{
 
2996
    erts_aint32_t flgs;
 
2997
    erts_aint32_t changing;
2402
2998
    long no = (long) esdp->no;
2403
 
    ErtsRunQueue *rq = esdp->run_queue;
 
2999
    ErtsSchedulerSleepInfo *ssi = esdp->ssi;
2404
3000
    long active_schedulers;
2405
3001
    int curr_online = 1;
2406
3002
    int wake = 0;
 
3003
#if defined(ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK) \
 
3004
    || defined(ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK)
 
3005
    erts_aint32_t aux_work;
 
3006
#endif
2407
3007
 
2408
3008
    /*
2409
3009
     * Schedulers may be suspended in two different ways:
2420
3020
 
2421
3021
    erts_smp_runq_unlock(esdp->run_queue);
2422
3022
 
2423
 
    /* Unbind from cpu */
2424
 
    erts_smp_rwmtx_rwlock(&erts_cpu_bind_rwmtx);
2425
 
    if (scheduler2cpu_map[esdp->no].bound_id >= 0
2426
 
        && erts_unbind_from_cpu(erts_cpuinfo) == 0) {
2427
 
        esdp->cpu_id = scheduler2cpu_map[esdp->no].bound_id = -1;
2428
 
    }
2429
 
    erts_smp_rwmtx_rwunlock(&erts_cpu_bind_rwmtx);
 
3023
    erts_sched_check_cpu_bind_prep_suspend(esdp);
2430
3024
 
2431
3025
    if (erts_system_profile_flags.scheduler)
2432
3026
        profile_scheduler(make_small(esdp->no), am_inactive);
2433
3027
 
2434
3028
    erts_smp_mtx_lock(&schdlr_sspnd.mtx);
2435
3029
 
2436
 
    active_schedulers = erts_smp_atomic_dectest(&schdlr_sspnd.active);
2437
 
    ASSERT(active_schedulers >= 1);
2438
 
    if (schdlr_sspnd.changing == ERTS_SCHED_CHANGING_MULTI_SCHED) {
2439
 
        if (active_schedulers == schdlr_sspnd.msb.wait_active)
2440
 
            wake = 1;
2441
 
        if (active_schedulers == 1)
2442
 
            schdlr_sspnd.changing = 0;
2443
 
    }
2444
 
 
2445
 
    while (1) {
2446
 
 
2447
 
#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
2448
 
        int check_children;
2449
 
        erts_smp_runq_lock(esdp->run_queue);
2450
 
        check_children = esdp->check_children;
2451
 
        esdp->check_children = 0;
2452
 
        erts_smp_runq_unlock(esdp->run_queue);
2453
 
        if (check_children) {
 
3030
    flgs = sched_prep_spin_suspended(ssi, ERTS_SSI_FLG_SUSPENDED);
 
3031
    if (flgs & ERTS_SSI_FLG_SUSPENDED) {
 
3032
 
 
3033
        active_schedulers = erts_smp_atomic32_dectest(&schdlr_sspnd.active);
 
3034
        ASSERT(active_schedulers >= 1);
 
3035
        changing = erts_smp_atomic32_read(&schdlr_sspnd.changing);
 
3036
        if (changing & ERTS_SCHDLR_SSPND_CHNG_MSB) {
 
3037
            if (active_schedulers == schdlr_sspnd.msb.wait_active)
 
3038
                wake = 1;
 
3039
            if (active_schedulers == 1) {
 
3040
                changing = erts_smp_atomic32_band(&schdlr_sspnd.changing,
 
3041
                                                  ~ERTS_SCHDLR_SSPND_CHNG_MSB);
 
3042
                changing &= ~ERTS_SCHDLR_SSPND_CHNG_MSB;
 
3043
            }
 
3044
        }
 
3045
 
 
3046
        while (1) {
 
3047
            if (changing & ERTS_SCHDLR_SSPND_CHNG_ONLN) {
 
3048
                int changed = 0;
 
3049
                if (no > schdlr_sspnd.online && curr_online) {
 
3050
                    schdlr_sspnd.curr_online--;
 
3051
                    curr_online = 0;
 
3052
                    changed = 1;
 
3053
                }
 
3054
                else if (no <= schdlr_sspnd.online && !curr_online) {
 
3055
                    schdlr_sspnd.curr_online++;
 
3056
                    curr_online = 1;
 
3057
                    changed = 1;
 
3058
                }
 
3059
                if (changed
 
3060
                    && schdlr_sspnd.curr_online == schdlr_sspnd.wait_curr_online)
 
3061
                    wake = 1;
 
3062
                if (schdlr_sspnd.online == schdlr_sspnd.curr_online) {
 
3063
                    changing = erts_smp_atomic32_band(&schdlr_sspnd.changing,
 
3064
                                                      ~ERTS_SCHDLR_SSPND_CHNG_ONLN);
 
3065
                    changing &= ~ERTS_SCHDLR_SSPND_CHNG_ONLN;
 
3066
                }
 
3067
            }
 
3068
 
 
3069
            if (wake) {
 
3070
                erts_smp_cnd_signal(&schdlr_sspnd.cnd);
 
3071
                wake = 0;
 
3072
            }
 
3073
 
 
3074
            flgs = erts_smp_atomic32_read(&ssi->flags);
 
3075
            if (!(flgs & ERTS_SSI_FLG_SUSPENDED))
 
3076
                break;
2454
3077
            erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
2455
 
            erts_check_children();
 
3078
 
 
3079
 
 
3080
#ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
 
3081
            aux_work = erts_smp_atomic32_read(&ssi->aux_work);
 
3082
        blockable_aux_work:
 
3083
            blockable_aux_work(esdp, ssi, aux_work);
 
3084
#endif
 
3085
 
 
3086
            erts_smp_activity_begin(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
 
3087
            while (1) {
 
3088
                erts_aint32_t flgs;
 
3089
#ifdef ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK
 
3090
#ifndef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
 
3091
                aux_work = erts_smp_atomic32_read(&ssi->aux_work);
 
3092
#endif
 
3093
                nonblockable_aux_work(esdp, ssi, aux_work);
 
3094
#endif
 
3095
 
 
3096
                flgs = sched_spin_suspended(ssi,
 
3097
                                            ERTS_SCHED_SUSPEND_SLEEP_SPINCOUNT);
 
3098
                if (flgs == (ERTS_SSI_FLG_SLEEPING
 
3099
                             | ERTS_SSI_FLG_WAITING
 
3100
                             | ERTS_SSI_FLG_SUSPENDED)) {
 
3101
                    flgs = sched_set_suspended_sleeptype(ssi);
 
3102
                    if (flgs == (ERTS_SSI_FLG_SLEEPING
 
3103
                                 | ERTS_SSI_FLG_TSE_SLEEPING
 
3104
                                 | ERTS_SSI_FLG_WAITING
 
3105
                                 | ERTS_SSI_FLG_SUSPENDED)) {
 
3106
                        int res;
 
3107
                        do {
 
3108
                            res = erts_tse_wait(ssi->event);
 
3109
                        } while (res == EINTR);
 
3110
                    }
 
3111
                }
 
3112
 
 
3113
                flgs = sched_prep_spin_suspended(ssi, (ERTS_SSI_FLG_WAITING
 
3114
                                                       | ERTS_SSI_FLG_SUSPENDED));
 
3115
                if (!(flgs & ERTS_SSI_FLG_SUSPENDED))
 
3116
                    break;
 
3117
                changing = erts_smp_atomic32_read(&schdlr_sspnd.changing);
 
3118
                if (changing & ~ERTS_SCHDLR_SSPND_CHNG_WAITER)
 
3119
                    break;
 
3120
 
 
3121
 
 
3122
#ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
 
3123
                aux_work = erts_smp_atomic32_read(&ssi->aux_work);
 
3124
                if (aux_work & ERTS_SSI_BLOCKABLE_AUX_WORK_MASK) {
 
3125
                    erts_smp_activity_end(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
 
3126
                    goto blockable_aux_work;
 
3127
                }
 
3128
#endif
 
3129
 
 
3130
            }
 
3131
 
 
3132
            erts_smp_activity_end(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
 
3133
 
2456
3134
            erts_smp_mtx_lock(&schdlr_sspnd.mtx);
2457
 
        }
2458
 
#endif
2459
 
 
2460
 
        if (schdlr_sspnd.changing == ERTS_SCHED_CHANGING_ONLINE) {
2461
 
            int changed = 0;
2462
 
            if (no > schdlr_sspnd.online && curr_online) {
2463
 
                schdlr_sspnd.curr_online--;
2464
 
                curr_online = 0;
2465
 
                changed = 1;
2466
 
            }
2467
 
            else if (no <= schdlr_sspnd.online && !curr_online) {
2468
 
                schdlr_sspnd.curr_online++;
2469
 
                curr_online = 1;
2470
 
                changed = 1;
2471
 
            }
2472
 
            if (changed
2473
 
                && schdlr_sspnd.curr_online == schdlr_sspnd.wait_curr_online)
2474
 
                wake = 1;
2475
 
            if (schdlr_sspnd.online == schdlr_sspnd.curr_online)
2476
 
                schdlr_sspnd.changing = 0;
2477
 
        }
2478
 
 
2479
 
        if (wake) {
2480
 
            erts_smp_cnd_broadcast(&schdlr_sspnd.cnd);
2481
 
            wake = 0;
2482
 
        }
2483
 
 
2484
 
 
2485
 
        if (!(rq->flags & (ERTS_RUNQ_FLG_SHARED_RUNQ|ERTS_RUNQ_FLG_SUSPENDED)))
2486
 
            break;
2487
 
        if ((rq->flags & ERTS_RUNQ_FLG_SHARED_RUNQ)
2488
 
            && !erts_smp_atomic_read(&esdp->suspended))
2489
 
            break;
2490
 
 
2491
 
        erts_smp_activity_begin(ERTS_ACTIVITY_WAIT,
2492
 
                                susp_sched_prep_block,
2493
 
                                susp_sched_resume_block,
2494
 
                                NULL);
2495
 
        while (1) {
2496
 
 
2497
 
#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
2498
 
            if (esdp->blocked_check_children)
2499
 
                break;
2500
 
#endif
2501
 
 
2502
 
            erts_smp_cnd_wait(&schdlr_sspnd.cnd, &schdlr_sspnd.mtx);
2503
 
 
2504
 
            if (schdlr_sspnd.changing == ERTS_SCHED_CHANGING_ONLINE)
2505
 
                break;
2506
 
 
2507
 
            if (!(rq->flags & (ERTS_RUNQ_FLG_SHARED_RUNQ
2508
 
                               | ERTS_RUNQ_FLG_SUSPENDED)))
2509
 
                break;
2510
 
            if ((rq->flags & ERTS_RUNQ_FLG_SHARED_RUNQ)
2511
 
                && !erts_smp_atomic_read(&esdp->suspended))
2512
 
                break;
2513
 
        }
2514
 
 
2515
 
#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
2516
 
        esdp->blocked_check_children = 0;
2517
 
#endif
2518
 
 
2519
 
        erts_smp_activity_end(ERTS_ACTIVITY_WAIT,
2520
 
                              susp_sched_prep_block,
2521
 
                              susp_sched_resume_block,
2522
 
                              NULL);
 
3135
            changing = erts_smp_atomic32_read(&schdlr_sspnd.changing);
 
3136
        }
 
3137
 
 
3138
        active_schedulers = erts_smp_atomic32_inctest(&schdlr_sspnd.active);
 
3139
        changing = erts_smp_atomic32_read(&schdlr_sspnd.changing);
 
3140
        if ((changing & ERTS_SCHDLR_SSPND_CHNG_MSB)
 
3141
            && schdlr_sspnd.online == active_schedulers) {
 
3142
            erts_smp_atomic32_band(&schdlr_sspnd.changing,
 
3143
                                   ~ERTS_SCHDLR_SSPND_CHNG_MSB);
 
3144
        }
 
3145
 
 
3146
        ASSERT(no <= schdlr_sspnd.online);
 
3147
        ASSERT(!erts_smp_atomic32_read(&schdlr_sspnd.msb.ongoing));
 
3148
 
2523
3149
    }
2524
3150
 
2525
 
    erts_smp_atomic_inc(&schdlr_sspnd.active);
2526
 
 
2527
3151
    erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
2528
3152
 
 
3153
    ASSERT(curr_online);
 
3154
 
2529
3155
    if (erts_system_profile_flags.scheduler)
2530
3156
        profile_scheduler(make_small(esdp->no), am_active);
2531
3157
 
2532
3158
    erts_smp_runq_lock(esdp->run_queue);
2533
3159
    non_empty_runq(esdp->run_queue);
2534
3160
 
2535
 
    /* Make sure we check if we should bind to a cpu or not... */
2536
 
    if (rq->flags & ERTS_RUNQ_FLG_SHARED_RUNQ)
2537
 
        erts_smp_atomic_set(&esdp->chk_cpu_bind, 1);
2538
 
    else
2539
 
        rq->flags |= ERTS_RUNQ_FLG_CHK_CPU_BIND;
 
3161
    erts_sched_check_cpu_bind_post_suspend(esdp);
2540
3162
}
2541
3163
 
2542
3164
#define ERTS_RUNQ_RESET_SUSPEND_INFO(RQ, DBG_ID)                        \
2551
3173
    (RQ)->flags |= (ERTS_RUNQ_FLG_OUT_OF_WORK                           \
2552
3174
                    | ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK);              \
2553
3175
    (RQ)->check_balance_reds = ERTS_RUNQ_CALL_CHECK_BALANCE_REDS;       \
2554
 
    erts_smp_atomic_band(&(RQ)->info_flags, ~ERTS_RUNQ_IFLG_SUSPENDED); \
 
3176
    erts_smp_atomic32_band(&(RQ)->info_flags, ~ERTS_RUNQ_IFLG_SUSPENDED);\
2555
3177
    for (pix__ = 0; pix__ < ERTS_NO_PROC_PRIO_LEVELS; pix__++) {        \
2556
3178
        (RQ)->procs.prio_info[pix__].max_len = 0;                       \
2557
3179
        (RQ)->procs.prio_info[pix__].reds = 0;                          \
2593
3215
                      int yield_allowed)
2594
3216
{
2595
3217
    int res;
 
3218
    erts_aint32_t changing;
2596
3219
    erts_smp_mtx_lock(&schdlr_sspnd.mtx);
2597
 
    if (yield_allowed && schdlr_sspnd.changing)
 
3220
    changing = erts_smp_atomic32_read(&schdlr_sspnd.changing);
 
3221
    if (yield_allowed && (changing & ~ERTS_SCHDLR_SSPND_CHNG_WAITER))
2598
3222
        res = ERTS_SCHDLR_SSPND_YIELD_RESTART;
2599
3223
    else {
2600
3224
        *active = *online = schdlr_sspnd.online;
2614
3238
                           Sint *old_no)
2615
3239
{
2616
3240
    int ix, res, no, have_unlocked_plocks;
 
3241
    erts_aint32_t changing;
2617
3242
 
2618
3243
    if (new_no < 1 || erts_no_schedulers < new_no)
2619
3244
        return ERTS_SCHDLR_SSPND_EINVAL;
2623
3248
    have_unlocked_plocks = 0;
2624
3249
    no = (int) new_no;
2625
3250
 
2626
 
    if (schdlr_sspnd.changing) {
 
3251
    changing = erts_smp_atomic32_read(&schdlr_sspnd.changing);
 
3252
    if (changing) {
2627
3253
        res = ERTS_SCHDLR_SSPND_YIELD_RESTART;
2628
3254
    }
2629
3255
    else {
2632
3258
            res = ERTS_SCHDLR_SSPND_DONE;
2633
3259
        }
2634
3260
        else {
2635
 
            schdlr_sspnd.changing = ERTS_SCHED_CHANGING_ONLINE;
 
3261
            ERTS_SCHDLR_SSPND_CHNG_SET((ERTS_SCHDLR_SSPND_CHNG_ONLN
 
3262
                                        | ERTS_SCHDLR_SSPND_CHNG_WAITER), 0);
2636
3263
            schdlr_sspnd.online = no;
2637
3264
            if (no > online) {
2638
3265
                int ix;
2639
3266
                schdlr_sspnd.wait_curr_online = no;
2640
 
                if (ongoing_multi_scheduling_block())
2641
 
                    /* No schedulers to resume */;
 
3267
                if (ongoing_multi_scheduling_block()) {
 
3268
                    for (ix = online; ix < no; ix++)
 
3269
                        erts_sched_poke(ERTS_SCHED_SLEEP_INFO_IX(ix));
 
3270
                }
2642
3271
                else if (erts_common_run_queue) {
2643
3272
                    for (ix = online; ix < no; ix++)
2644
 
                        erts_smp_atomic_set(&ERTS_SCHEDULER_IX(ix)->suspended,
2645
 
                                            0);
 
3273
                        scheduler_ix_resume_wake(ix);
2646
3274
                }
2647
3275
                else {
2648
3276
                    if (plocks) {
2656
3284
                        erts_smp_runq_lock(rq);
2657
3285
                        ERTS_RUNQ_RESET_SUSPEND_INFO(rq, 0x5);
2658
3286
                        erts_smp_runq_unlock(rq);
 
3287
                        scheduler_ix_resume_wake(ix);
2659
3288
                    }
2660
3289
                    /*
2661
3290
                     * Spread evacuation paths among all online
2666
3295
                        ErtsRunQueue *to_rq = ERTS_RUNQ_IX(ix % no);
2667
3296
                        evacuate_run_queue(from_rq, to_rq);
2668
3297
                    }
2669
 
                    erts_smp_atomic_set(&balance_info.used_runqs, no);
 
3298
                    erts_smp_atomic32_set(&balance_info.used_runqs, no);
2670
3299
                    erts_smp_mtx_unlock(&balance_info.update_mtx);
2671
3300
                    erts_smp_mtx_lock(&schdlr_sspnd.mtx);
2672
3301
                }
2673
 
                erts_smp_cnd_broadcast(&schdlr_sspnd.cnd);
2674
3302
                res = ERTS_SCHDLR_SSPND_DONE;
2675
3303
            }
2676
3304
            else /* if (no < online) */ {
2687
3315
                    schdlr_sspnd.wait_curr_online = no+1;
2688
3316
                }
2689
3317
 
2690
 
                if (ongoing_multi_scheduling_block())
2691
 
                    erts_smp_cnd_broadcast(&schdlr_sspnd.cnd);
2692
 
                else if (erts_common_run_queue) {
 
3318
                if (ongoing_multi_scheduling_block()) {
2693
3319
                    for (ix = no; ix < online; ix++)
2694
 
                        erts_smp_atomic_set(&ERTS_SCHEDULER_IX(ix)->suspended,
2695
 
                                            1);
 
3320
                        erts_sched_poke(ERTS_SCHED_SLEEP_INFO_IX(ix));
 
3321
                }
 
3322
                else if (erts_common_run_queue) {
 
3323
                    for (ix = no; ix < online; ix++) {
 
3324
                        ErtsSchedulerSleepInfo *ssi;
 
3325
                        ssi = ERTS_SCHED_SLEEP_INFO_IX(ix);
 
3326
                        erts_smp_atomic32_bor(&ssi->flags,
 
3327
                                              ERTS_SSI_FLG_SUSPENDED);
 
3328
                    }
2696
3329
                    wake_all_schedulers();
2697
3330
                }
2698
3331
                else {
2716
3349
                    for (ix = erts_no_run_queues-1; ix >= no; ix--)
2717
3350
                        evacuate_run_queue(ERTS_RUNQ_IX(ix),
2718
3351
                                           ERTS_RUNQ_IX(ix % no));
2719
 
                    erts_smp_atomic_set(&balance_info.used_runqs, no);
 
3352
                    erts_smp_atomic32_set(&balance_info.used_runqs, no);
2720
3353
                    erts_smp_mtx_unlock(&balance_info.update_mtx);
2721
3354
                    erts_smp_mtx_lock(&schdlr_sspnd.mtx);
2722
 
                    ERTS_FOREACH_OP_RUNQ(rq, wake_scheduler(rq, 0));
 
3355
                    for (ix = no; ix < online; ix++) {
 
3356
                        ErtsRunQueue *rq = ERTS_RUNQ_IX(ix);
 
3357
                        wake_scheduler(rq, 0, 1);
 
3358
                    }
2723
3359
                }
2724
3360
            }
2725
3361
 
2733
3369
                                  susp_sched_prep_block,
2734
3370
                                  susp_sched_resume_block,
2735
3371
                                  NULL);
 
3372
            ASSERT(res != ERTS_SCHDLR_SSPND_DONE
 
3373
                   ? (ERTS_SCHDLR_SSPND_CHNG_WAITER
 
3374
                      & erts_smp_atomic32_read(&schdlr_sspnd.changing))
 
3375
                   : (ERTS_SCHDLR_SSPND_CHNG_WAITER
 
3376
                      == erts_smp_atomic32_read(&schdlr_sspnd.changing)));
 
3377
            erts_smp_atomic32_band(&schdlr_sspnd.changing,
 
3378
                                   ~ERTS_SCHDLR_SSPND_CHNG_WAITER);
2736
3379
        }
2737
3380
    }
2738
3381
 
2747
3390
erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all)
2748
3391
{
2749
3392
    int ix, res, have_unlocked_plocks = 0;
 
3393
    erts_aint32_t changing;
2750
3394
    ErtsProcList *plp;
2751
3395
 
2752
3396
    erts_smp_mtx_lock(&schdlr_sspnd.mtx);
2753
 
    if (on) {
2754
 
        if (schdlr_sspnd.changing) {
2755
 
            res = ERTS_SCHDLR_SSPND_YIELD_RESTART; /* Yield */
2756
 
        }
2757
 
        else if (erts_is_multi_scheduling_blocked()) {
 
3397
    changing = erts_smp_atomic32_read(&schdlr_sspnd.changing);
 
3398
    if (changing) {
 
3399
        res = ERTS_SCHDLR_SSPND_YIELD_RESTART; /* Yield */
 
3400
    }
 
3401
    else if (on) { /* ------ BLOCK ------ */
 
3402
        if (schdlr_sspnd.msb.procs) {
2758
3403
            plp = proclist_create(p);
2759
3404
            plp->next = schdlr_sspnd.msb.procs;
2760
3405
            schdlr_sspnd.msb.procs = plp;
2761
3406
            p->flags |= F_HAVE_BLCKD_MSCHED;
2762
 
            ASSERT(erts_smp_atomic_read(&schdlr_sspnd.active) == 1);
 
3407
            ASSERT(erts_smp_atomic32_read(&schdlr_sspnd.active) == 1);
2763
3408
            ASSERT(p->scheduler_data->no == 1);
2764
 
            res = 1;
 
3409
            res = ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED;
2765
3410
        }
2766
3411
        else {
 
3412
            int online = schdlr_sspnd.online;
2767
3413
            p->flags |= F_HAVE_BLCKD_MSCHED;
2768
3414
            if (plocks) {
2769
3415
                have_unlocked_plocks = 1;
2770
3416
                erts_smp_proc_unlock(p, plocks);
2771
3417
            }
2772
 
            erts_smp_atomic_set(&schdlr_sspnd.msb.ongoing, 1);
2773
 
            if (schdlr_sspnd.online == 1) {
 
3418
            ASSERT(0 == erts_smp_atomic32_read(&schdlr_sspnd.msb.ongoing));
 
3419
            erts_smp_atomic32_set(&schdlr_sspnd.msb.ongoing, 1);
 
3420
            if (online == 1) {
2774
3421
                res = ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED;
2775
 
                ASSERT(erts_smp_atomic_read(&schdlr_sspnd.active) == 1);
 
3422
                ASSERT(erts_smp_atomic32_read(&schdlr_sspnd.active) == 1);
2776
3423
                ASSERT(p->scheduler_data->no == 1);
2777
3424
            }
2778
3425
            else {
2779
 
                schdlr_sspnd.changing = ERTS_SCHED_CHANGING_MULTI_SCHED;
 
3426
                ERTS_SCHDLR_SSPND_CHNG_SET((ERTS_SCHDLR_SSPND_CHNG_MSB
 
3427
                                            | ERTS_SCHDLR_SSPND_CHNG_WAITER), 0);
2780
3428
                if (p->scheduler_data->no == 1) {
2781
3429
                    res = ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED;
2782
3430
                    schdlr_sspnd.msb.wait_active = 1;
2790
3438
                    schdlr_sspnd.msb.wait_active = 2;
2791
3439
                }
2792
3440
                if (erts_common_run_queue) {
2793
 
                    for (ix = 1; ix < schdlr_sspnd.online; ix++)
2794
 
                        erts_smp_atomic_set(&ERTS_SCHEDULER_IX(ix)->suspended, 1);
 
3441
                    for (ix = 1; ix < online; ix++)
 
3442
                        erts_smp_atomic32_bor(&ERTS_SCHED_SLEEP_INFO_IX(ix)->flags,
 
3443
                                              ERTS_SSI_FLG_SUSPENDED);
2795
3444
                    wake_all_schedulers();
2796
3445
                }
2797
3446
                else {
2798
3447
                    erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
2799
3448
                    erts_smp_mtx_lock(&balance_info.update_mtx);
2800
 
                    erts_smp_atomic_set(&balance_info.used_runqs, 1);
2801
 
                    for (ix = 0; ix < schdlr_sspnd.online; ix++) {
 
3449
                    erts_smp_atomic32_set(&balance_info.used_runqs, 1);
 
3450
                    for (ix = 0; ix < online; ix++) {
2802
3451
                        ErtsRunQueue *rq = ERTS_RUNQ_IX(ix);
2803
3452
                        erts_smp_runq_lock(rq);
 
3453
                        ASSERT(!(rq->flags & ERTS_RUNQ_FLG_SUSPENDED));
2804
3454
                        ERTS_RUNQ_RESET_MIGRATION_PATHS(rq, 0x7);
2805
3455
                        erts_smp_runq_unlock(rq);
2806
3456
                    }
2818
3468
                                        susp_sched_prep_block,
2819
3469
                                        susp_sched_resume_block,
2820
3470
                                        NULL);
2821
 
                while (erts_smp_atomic_read(&schdlr_sspnd.active)
 
3471
                while (erts_smp_atomic32_read(&schdlr_sspnd.active)
2822
3472
                       != schdlr_sspnd.msb.wait_active)
2823
3473
                    erts_smp_cnd_wait(&schdlr_sspnd.cnd, &schdlr_sspnd.mtx);
2824
3474
                erts_smp_activity_end(ERTS_ACTIVITY_WAIT,
2825
3475
                                      susp_sched_prep_block,
2826
3476
                                      susp_sched_resume_block,
2827
3477
                                      NULL);
 
3478
                ASSERT(res != ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED
 
3479
                       ? (ERTS_SCHDLR_SSPND_CHNG_WAITER
 
3480
                          & erts_smp_atomic32_read(&schdlr_sspnd.changing))
 
3481
                       : (ERTS_SCHDLR_SSPND_CHNG_WAITER
 
3482
                          == erts_smp_atomic32_read(&schdlr_sspnd.changing)));
 
3483
                erts_smp_atomic32_band(&schdlr_sspnd.changing,
 
3484
                                       ~ERTS_SCHDLR_SSPND_CHNG_WAITER);
2828
3485
            }
2829
3486
            plp = proclist_create(p);
2830
3487
            plp->next = schdlr_sspnd.msb.procs;
2842
3499
        }
2843
3500
    }
2844
3501
    else if (!ongoing_multi_scheduling_block()) {
 
3502
        /* unblock not ongoing */
2845
3503
        ASSERT(!schdlr_sspnd.msb.procs);
2846
3504
        res = ERTS_SCHDLR_SSPND_DONE;
2847
3505
    }
2848
 
    else {
 
3506
    else {  /* ------ UNBLOCK ------ */
2849
3507
        if (p->flags & F_HAVE_BLCKD_MSCHED) {
2850
3508
            ErtsProcList **plpp = &schdlr_sspnd.msb.procs;
2851
3509
            plp = schdlr_sspnd.msb.procs;
2867
3525
        if (schdlr_sspnd.msb.procs)
2868
3526
            res = ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED;
2869
3527
        else {
2870
 
            schdlr_sspnd.changing = ERTS_SCHED_CHANGING_MULTI_SCHED;
 
3528
            ERTS_SCHDLR_SSPND_CHNG_SET(ERTS_SCHDLR_SSPND_CHNG_MSB, 0);
2871
3529
#ifdef DEBUG
2872
3530
            ERTS_FOREACH_RUNQ(rq,
2873
3531
            {
2890
3548
            });
2891
3549
#endif
2892
3550
            p->flags &= ~F_HAVE_BLCKD_MSCHED;
2893
 
            erts_smp_atomic_set(&schdlr_sspnd.msb.ongoing, 0);
2894
 
            if (schdlr_sspnd.online == 1)
2895
 
                /* No schedulers to resume */;
 
3551
            erts_smp_atomic32_set(&schdlr_sspnd.msb.ongoing, 0);
 
3552
            if (schdlr_sspnd.online == 1) {
 
3553
                /* No schedulers to resume */
 
3554
                ASSERT(erts_smp_atomic32_read(&schdlr_sspnd.active) == 1);
 
3555
                ERTS_SCHDLR_SSPND_CHNG_SET(0, ERTS_SCHDLR_SSPND_CHNG_MSB);
 
3556
            }
2896
3557
            else if (erts_common_run_queue) {
2897
3558
                for (ix = 1; ix < schdlr_sspnd.online; ix++)
2898
 
                    erts_smp_atomic_set(&ERTS_SCHEDULER_IX(ix)->suspended, 0);
 
3559
                    erts_smp_atomic32_band(&ERTS_SCHED_SLEEP_INFO_IX(ix)->flags,
 
3560
                                           ~ERTS_SSI_FLG_SUSPENDED);
2899
3561
                wake_all_schedulers();
2900
3562
            }
2901
3563
            else {
2913
3575
                    erts_smp_runq_lock(rq);
2914
3576
                    ERTS_RUNQ_RESET_SUSPEND_INFO(rq, 0x4);
2915
3577
                    erts_smp_runq_unlock(rq);
 
3578
                    scheduler_ix_resume_wake(ix);
2916
3579
                }
2917
3580
 
2918
3581
                /* Spread evacuation paths among all online run queues */
2920
3583
                    evacuate_run_queue(ERTS_RUNQ_IX(ix),
2921
3584
                                       ERTS_RUNQ_IX(ix % online));
2922
3585
 
2923
 
                erts_smp_atomic_set(&balance_info.used_runqs, online);
 
3586
                erts_smp_atomic32_set(&balance_info.used_runqs, online);
2924
3587
                /* Make sure that we balance soon... */
2925
3588
                balance_info.forced_check_balance = 1;
2926
3589
                erts_smp_runq_lock(ERTS_RUNQ_IX(0));
2929
3592
                erts_smp_mtx_unlock(&balance_info.update_mtx);
2930
3593
                erts_smp_mtx_lock(&schdlr_sspnd.mtx);
2931
3594
            }
2932
 
            erts_smp_cnd_broadcast(&schdlr_sspnd.cnd);
2933
 
            schdlr_sspnd.changing = 0;
2934
3595
            res = ERTS_SCHDLR_SSPND_DONE;
2935
3596
        }
2936
3597
    }
2946
3607
erts_dbg_multi_scheduling_return_trap(Process *p, Eterm return_value)
2947
3608
{
2948
3609
    if (return_value == am_blocked) {
2949
 
        long active = erts_smp_atomic_read(&schdlr_sspnd.active);
 
3610
        erts_aint32_t active = erts_smp_atomic32_read(&schdlr_sspnd.active);
2950
3611
        ASSERT(1 <= active && active <= 2);
2951
3612
        ASSERT(ERTS_PROC_GET_SCHDATA(p)->no == 1);
2952
3613
    }
2956
3617
int
2957
3618
erts_is_multi_scheduling_blocked(void)
2958
3619
{
2959
 
    return (erts_smp_atomic_read(&schdlr_sspnd.msb.ongoing)
2960
 
            && erts_smp_atomic_read(&schdlr_sspnd.active) == 1);
 
3620
    int res;
 
3621
    erts_smp_mtx_lock(&schdlr_sspnd.mtx);
 
3622
    res = schdlr_sspnd.msb.procs != NULL;
 
3623
    erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
 
3624
    return res;
2961
3625
}
2962
3626
 
2963
3627
Eterm
2966
3630
    Eterm res = NIL;
2967
3631
 
2968
3632
    erts_smp_mtx_lock(&schdlr_sspnd.mtx);
2969
 
    if (erts_is_multi_scheduling_blocked()) {
 
3633
    if (schdlr_sspnd.msb.procs) {
2970
3634
        Eterm *hp, *hp_end;
2971
3635
        ErtsProcList *plp1, *plp2;
2972
3636
        Uint max_size;
2998
3662
static void *
2999
3663
sched_thread_func(void *vesdp)
3000
3664
{
 
3665
#ifdef ERTS_SMP
 
3666
    Uint no = ((ErtsSchedulerData *) vesdp)->no;
 
3667
#endif
3001
3668
#ifdef ERTS_ENABLE_LOCK_CHECK
3002
3669
    {
3003
3670
        char buf[31];
3004
 
        Uint no = ((ErtsSchedulerData *) vesdp)->no;
3005
3671
        erts_snprintf(&buf[0], 31, "scheduler %bpu", no);
3006
3672
        erts_lc_set_thread_name(&buf[0]);
3007
3673
    }
3008
3674
#endif
3009
 
    erts_alloc_reg_scheduler_id(((ErtsSchedulerData *) vesdp)->no);
 
3675
    erts_alloc_reg_scheduler_id(no);
3010
3676
    erts_tsd_set(sched_data_key, vesdp);
3011
3677
#ifdef ERTS_SMP
 
3678
 
 
3679
    erts_sched_init_check_cpu_bind((ErtsSchedulerData *) vesdp);
 
3680
 
3012
3681
    erts_proc_lock_prepare_proc_lock_waiter();
 
3682
    ERTS_SCHED_SLEEP_INFO_IX(no - 1)->event = erts_tse_fetch();
 
3683
 
 
3684
 
3013
3685
#endif
3014
3686
    erts_register_blockable_thread();
3015
3687
#ifdef HIPE
3018
3690
    erts_thread_init_float();
3019
3691
    erts_smp_mtx_lock(&schdlr_sspnd.mtx);
3020
3692
 
3021
 
    ASSERT(schdlr_sspnd.changing == ERTS_SCHED_CHANGING_ONLINE);
3022
 
 
3023
 
    schdlr_sspnd.curr_online--;
3024
 
 
3025
 
    if (((ErtsSchedulerData *) vesdp)->no != 1) {
3026
 
        if (schdlr_sspnd.online == schdlr_sspnd.curr_online) {
3027
 
            schdlr_sspnd.changing = 0;
3028
 
            erts_smp_cnd_broadcast(&schdlr_sspnd.cnd);
 
3693
    ASSERT(erts_smp_atomic32_read(&schdlr_sspnd.changing)
 
3694
           & ERTS_SCHDLR_SSPND_CHNG_ONLN);
 
3695
 
 
3696
    if (--schdlr_sspnd.curr_online == schdlr_sspnd.wait_curr_online) {
 
3697
        erts_smp_atomic32_band(&schdlr_sspnd.changing,
 
3698
                               ~ERTS_SCHDLR_SSPND_CHNG_ONLN);
 
3699
        if (((ErtsSchedulerData *) vesdp)->no != 1)
 
3700
            erts_smp_cnd_signal(&schdlr_sspnd.cnd);
 
3701
    }
 
3702
 
 
3703
    if (((ErtsSchedulerData *) vesdp)->no == 1) {
 
3704
        if (schdlr_sspnd.curr_online != schdlr_sspnd.wait_curr_online) {
 
3705
            erts_smp_activity_begin(ERTS_ACTIVITY_WAIT,
 
3706
                                    susp_sched_prep_block,
 
3707
                                    susp_sched_resume_block,
 
3708
                                    NULL);
 
3709
            while (schdlr_sspnd.curr_online != schdlr_sspnd.wait_curr_online)
 
3710
                erts_smp_cnd_wait(&schdlr_sspnd.cnd, &schdlr_sspnd.mtx);
 
3711
            erts_smp_activity_end(ERTS_ACTIVITY_WAIT,
 
3712
                                  susp_sched_prep_block,
 
3713
                                  susp_sched_resume_block,
 
3714
                                  NULL);
3029
3715
        }
3030
 
    }
3031
 
    else if (schdlr_sspnd.curr_online == schdlr_sspnd.wait_curr_online)
3032
 
        schdlr_sspnd.changing = 0;
3033
 
    else {
3034
 
        erts_smp_activity_begin(ERTS_ACTIVITY_WAIT,
3035
 
                                susp_sched_prep_block,
3036
 
                                susp_sched_resume_block,
3037
 
                                NULL);
3038
 
        while (schdlr_sspnd.curr_online != schdlr_sspnd.wait_curr_online)
3039
 
            erts_smp_cnd_wait(&schdlr_sspnd.cnd, &schdlr_sspnd.mtx);
3040
 
        erts_smp_activity_end(ERTS_ACTIVITY_WAIT,
3041
 
                              susp_sched_prep_block,
3042
 
                              susp_sched_resume_block,
3043
 
                              NULL);
3044
 
        ASSERT(!schdlr_sspnd.changing);
 
3716
        ERTS_SCHDLR_SSPND_CHNG_SET(0, ERTS_SCHDLR_SSPND_CHNG_WAITER);
3045
3717
    }
3046
3718
    erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
3047
3719
 
 
3720
#ifdef ERTS_DO_VERIFY_UNUSED_TEMP_ALLOC
 
3721
    ((ErtsSchedulerData *) vesdp)->verify_unused_temp_alloc
 
3722
        = erts_alloc_get_verify_unused_temp_alloc(
 
3723
            &((ErtsSchedulerData *) vesdp)->verify_unused_temp_alloc_data);
 
3724
    ERTS_VERIFY_UNUSED_TEMP_ALLOC(NULL);
 
3725
#endif
 
3726
 
3048
3727
    process_main();
3049
3728
    /* No schedulers should *ever* terminate */
3050
3729
    erl_exit(ERTS_ABORT_EXIT, "Scheduler thread number %bpu terminated\n",
3077
3756
        ErtsSchedulerData *esdp = ERTS_SCHEDULER_IX(actual);
3078
3757
        actual++;
3079
3758
        ASSERT(actual == esdp->no);
3080
 
#ifdef ERTS_ENABLE_LOCK_COUNT
3081
 
        res = erts_lcnt_thr_create(&esdp->tid,sched_thread_func,(void*)esdp,&opts);
3082
 
#else
3083
3759
        res = ethr_thr_create(&esdp->tid,sched_thread_func,(void*)esdp,&opts);
3084
 
#endif
3085
3760
        if (res != 0) {
3086
3761
            actual--;
3087
3762
            break;
3110
3785
 
3111
3786
#endif /* ERTS_SMP */
3112
3787
 
3113
 
static int
3114
 
int_cmp(const void *vx, const void *vy)
3115
 
{
3116
 
    return *((int *) vx) - *((int *) vy);
3117
 
}
3118
 
 
3119
 
static int
3120
 
cpu_spread_order_cmp(const void *vx, const void *vy)
3121
 
{
3122
 
    erts_cpu_topology_t *x = (erts_cpu_topology_t *) vx;
3123
 
    erts_cpu_topology_t *y = (erts_cpu_topology_t *) vy;
3124
 
 
3125
 
    if (x->thread != y->thread)
3126
 
        return x->thread - y->thread;
3127
 
    if (x->core != y->core)
3128
 
        return x->core - y->core;
3129
 
    if (x->processor_node != y->processor_node)
3130
 
        return x->processor_node - y->processor_node;
3131
 
    if (x->processor != y->processor)
3132
 
        return x->processor - y->processor;
3133
 
    if (x->node != y->node)
3134
 
        return x->node - y->node;
3135
 
    return 0;
3136
 
}
3137
 
 
3138
 
static int
3139
 
cpu_processor_spread_order_cmp(const void *vx, const void *vy)
3140
 
{
3141
 
    erts_cpu_topology_t *x = (erts_cpu_topology_t *) vx;
3142
 
    erts_cpu_topology_t *y = (erts_cpu_topology_t *) vy;
3143
 
 
3144
 
    if (x->thread != y->thread)
3145
 
        return x->thread - y->thread;
3146
 
    if (x->processor_node != y->processor_node)
3147
 
        return x->processor_node - y->processor_node;
3148
 
    if (x->core != y->core)
3149
 
        return x->core - y->core;
3150
 
    if (x->node != y->node)
3151
 
        return x->node - y->node;
3152
 
    if (x->processor != y->processor)
3153
 
        return x->processor - y->processor;
3154
 
    return 0;
3155
 
}
3156
 
 
3157
 
static int
3158
 
cpu_thread_spread_order_cmp(const void *vx, const void *vy)
3159
 
{
3160
 
    erts_cpu_topology_t *x = (erts_cpu_topology_t *) vx;
3161
 
    erts_cpu_topology_t *y = (erts_cpu_topology_t *) vy;
3162
 
 
3163
 
    if (x->thread != y->thread)
3164
 
        return x->thread - y->thread;
3165
 
    if (x->node != y->node)
3166
 
        return x->node - y->node;
3167
 
    if (x->processor != y->processor)
3168
 
        return x->processor - y->processor;
3169
 
    if (x->processor_node != y->processor_node)
3170
 
        return x->processor_node - y->processor_node;
3171
 
    if (x->core != y->core)
3172
 
        return x->core - y->core;
3173
 
    return 0;
3174
 
}
3175
 
 
3176
 
static int
3177
 
cpu_thread_no_node_processor_spread_order_cmp(const void *vx, const void *vy)
3178
 
{
3179
 
    erts_cpu_topology_t *x = (erts_cpu_topology_t *) vx;
3180
 
    erts_cpu_topology_t *y = (erts_cpu_topology_t *) vy;
3181
 
 
3182
 
    if (x->thread != y->thread)
3183
 
        return x->thread - y->thread;
3184
 
    if (x->node != y->node)
3185
 
        return x->node - y->node;
3186
 
    if (x->core != y->core)
3187
 
        return x->core - y->core;
3188
 
    if (x->processor != y->processor)
3189
 
        return x->processor - y->processor;
3190
 
    return 0;
3191
 
}
3192
 
 
3193
 
static int
3194
 
cpu_no_node_processor_spread_order_cmp(const void *vx, const void *vy)
3195
 
{
3196
 
    erts_cpu_topology_t *x = (erts_cpu_topology_t *) vx;
3197
 
    erts_cpu_topology_t *y = (erts_cpu_topology_t *) vy;
3198
 
 
3199
 
    if (x->node != y->node)
3200
 
        return x->node - y->node;
3201
 
    if (x->thread != y->thread)
3202
 
        return x->thread - y->thread;
3203
 
    if (x->core != y->core)
3204
 
        return x->core - y->core;
3205
 
    if (x->processor != y->processor)
3206
 
        return x->processor - y->processor;
3207
 
    return 0;
3208
 
}
3209
 
 
3210
 
static int
3211
 
cpu_no_node_thread_spread_order_cmp(const void *vx, const void *vy)
3212
 
{
3213
 
    erts_cpu_topology_t *x = (erts_cpu_topology_t *) vx;
3214
 
    erts_cpu_topology_t *y = (erts_cpu_topology_t *) vy;
3215
 
 
3216
 
    if (x->node != y->node)
3217
 
        return x->node - y->node;
3218
 
    if (x->thread != y->thread)
3219
 
        return x->thread - y->thread;
3220
 
    if (x->processor != y->processor)
3221
 
        return x->processor - y->processor;
3222
 
    if (x->core != y->core)
3223
 
        return x->core - y->core;
3224
 
    return 0;
3225
 
}
3226
 
 
3227
 
static int
3228
 
cpu_no_spread_order_cmp(const void *vx, const void *vy)
3229
 
{
3230
 
    erts_cpu_topology_t *x = (erts_cpu_topology_t *) vx;
3231
 
    erts_cpu_topology_t *y = (erts_cpu_topology_t *) vy;
3232
 
 
3233
 
    if (x->node != y->node)
3234
 
        return x->node - y->node;
3235
 
    if (x->processor != y->processor)
3236
 
        return x->processor - y->processor;
3237
 
    if (x->processor_node != y->processor_node)
3238
 
        return x->processor_node - y->processor_node;
3239
 
    if (x->core != y->core)
3240
 
        return x->core - y->core;
3241
 
    if (x->thread != y->thread)
3242
 
        return x->thread - y->thread;
3243
 
    return 0;
3244
 
}
3245
 
 
3246
 
static ERTS_INLINE void
3247
 
make_cpudata_id_seq(erts_cpu_topology_t *cpudata, int size, int no_node)
3248
 
{
3249
 
    int ix;
3250
 
    int node = -1;
3251
 
    int processor = -1;
3252
 
    int processor_node = -1;
3253
 
    int processor_node_node = -1;
3254
 
    int core = -1;
3255
 
    int thread = -1;
3256
 
    int old_node = -1;
3257
 
    int old_processor = -1;
3258
 
    int old_processor_node = -1;
3259
 
    int old_core = -1;
3260
 
    int old_thread = -1;
3261
 
 
3262
 
    for (ix = 0; ix < size; ix++) {
3263
 
        if (!no_node || cpudata[ix].node >= 0) {
3264
 
            if (old_node == cpudata[ix].node)
3265
 
                cpudata[ix].node = node;
3266
 
            else {
3267
 
                old_node = cpudata[ix].node;
3268
 
                old_processor = processor = -1;
3269
 
                if (!no_node)
3270
 
                    old_processor_node = processor_node = -1;
3271
 
                old_core = core = -1;
3272
 
                old_thread = thread = -1;
3273
 
                if (no_node || cpudata[ix].node >= 0)
3274
 
                    cpudata[ix].node = ++node;
3275
 
            }
3276
 
        }
3277
 
        if (old_processor == cpudata[ix].processor)
3278
 
            cpudata[ix].processor = processor;
3279
 
        else {
3280
 
            old_processor = cpudata[ix].processor;
3281
 
            if (!no_node)
3282
 
                processor_node_node = old_processor_node = processor_node = -1;
3283
 
            old_core = core = -1;
3284
 
            old_thread = thread = -1;
3285
 
            cpudata[ix].processor = ++processor;
3286
 
        }
3287
 
        if (no_node && cpudata[ix].processor_node < 0)
3288
 
            old_processor_node = -1;
3289
 
        else {
3290
 
            if (old_processor_node == cpudata[ix].processor_node) {
3291
 
                if (no_node)
3292
 
                    cpudata[ix].node = cpudata[ix].processor_node = node;
3293
 
                else {
3294
 
                    if (processor_node_node >= 0)
3295
 
                        cpudata[ix].node = processor_node_node;
3296
 
                    cpudata[ix].processor_node = processor_node;
3297
 
                }
3298
 
            }
3299
 
            else {
3300
 
                old_processor_node = cpudata[ix].processor_node;
3301
 
                old_core = core = -1;
3302
 
                old_thread = thread = -1;
3303
 
                if (no_node)
3304
 
                    cpudata[ix].node = cpudata[ix].processor_node = ++node;
3305
 
                else {
3306
 
                    cpudata[ix].node = processor_node_node = ++node;
3307
 
                    cpudata[ix].processor_node = ++processor_node;
3308
 
                }
3309
 
            }
3310
 
        }
3311
 
        if (!no_node && cpudata[ix].processor_node < 0)
3312
 
            cpudata[ix].processor_node = 0;
3313
 
        if (old_core == cpudata[ix].core)
3314
 
            cpudata[ix].core = core;
3315
 
        else {
3316
 
            old_core = cpudata[ix].core;
3317
 
            old_thread = thread = -1;
3318
 
            cpudata[ix].core = ++core;
3319
 
        }
3320
 
        if (old_thread == cpudata[ix].thread)
3321
 
            cpudata[ix].thread = thread;
3322
 
        else
3323
 
            old_thread = cpudata[ix].thread = ++thread;
3324
 
    }
3325
 
}
3326
 
 
3327
 
static void
3328
 
cpu_bind_order_sort(erts_cpu_topology_t *cpudata,
3329
 
                    int size,
3330
 
                    ErtsCpuBindOrder bind_order,
3331
 
                    int mk_seq)
3332
 
{
3333
 
    if (size > 1) {
3334
 
        int no_node = 0;
3335
 
        int (*cmp_func)(const void *, const void *);
3336
 
        switch (bind_order) {
3337
 
        case ERTS_CPU_BIND_SPREAD:
3338
 
            cmp_func = cpu_spread_order_cmp;
3339
 
            break;
3340
 
        case ERTS_CPU_BIND_PROCESSOR_SPREAD:
3341
 
            cmp_func = cpu_processor_spread_order_cmp;
3342
 
            break;
3343
 
        case ERTS_CPU_BIND_THREAD_SPREAD:
3344
 
            cmp_func = cpu_thread_spread_order_cmp;
3345
 
            break;
3346
 
        case ERTS_CPU_BIND_THREAD_NO_NODE_PROCESSOR_SPREAD:
3347
 
            no_node = 1;
3348
 
            cmp_func = cpu_thread_no_node_processor_spread_order_cmp;
3349
 
            break;
3350
 
        case ERTS_CPU_BIND_NO_NODE_PROCESSOR_SPREAD:
3351
 
            no_node = 1;
3352
 
            cmp_func = cpu_no_node_processor_spread_order_cmp;
3353
 
            break;
3354
 
        case ERTS_CPU_BIND_NO_NODE_THREAD_SPREAD:
3355
 
            no_node = 1;
3356
 
            cmp_func = cpu_no_node_thread_spread_order_cmp;
3357
 
            break;
3358
 
        case ERTS_CPU_BIND_NO_SPREAD:
3359
 
            cmp_func = cpu_no_spread_order_cmp;
3360
 
            break;
3361
 
        default:
3362
 
            cmp_func = NULL;
3363
 
            erl_exit(ERTS_ABORT_EXIT,
3364
 
                     "Bad cpu bind type: %d\n",
3365
 
                     (int) cpu_bind_order);
3366
 
            break;
3367
 
        }
3368
 
 
3369
 
        if (mk_seq)
3370
 
            make_cpudata_id_seq(cpudata, size, no_node);
3371
 
 
3372
 
        qsort(cpudata, size, sizeof(erts_cpu_topology_t), cmp_func);
3373
 
    }
3374
 
}
3375
 
 
3376
 
static int
3377
 
processor_order_cmp(const void *vx, const void *vy)
3378
 
{
3379
 
    erts_cpu_topology_t *x = (erts_cpu_topology_t *) vx;
3380
 
    erts_cpu_topology_t *y = (erts_cpu_topology_t *) vy;
3381
 
 
3382
 
    if (x->processor != y->processor)
3383
 
        return x->processor - y->processor;
3384
 
    if (x->node != y->node)
3385
 
        return x->node - y->node;
3386
 
    if (x->processor_node != y->processor_node)
3387
 
        return x->processor_node - y->processor_node;
3388
 
    if (x->core != y->core)
3389
 
        return x->core - y->core;
3390
 
    if (x->thread != y->thread)
3391
 
        return x->thread - y->thread;
3392
 
    return 0;
3393
 
}
3394
 
 
3395
 
static void
3396
 
check_cpu_bind(ErtsSchedulerData *esdp)
3397
 
{
3398
 
    int res;
3399
 
    int cpu_id;
3400
 
    erts_smp_runq_unlock(esdp->run_queue);
3401
 
    erts_smp_rwmtx_rwlock(&erts_cpu_bind_rwmtx);
3402
 
    cpu_id = scheduler2cpu_map[esdp->no].bind_id;
3403
 
    if (cpu_id >= 0 && cpu_id != scheduler2cpu_map[esdp->no].bound_id) {
3404
 
        res = erts_bind_to_cpu(erts_cpuinfo, cpu_id);
3405
 
        if (res == 0)
3406
 
            esdp->cpu_id = scheduler2cpu_map[esdp->no].bound_id = cpu_id;
3407
 
        else {
3408
 
            erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
3409
 
            erts_dsprintf(dsbufp, "Scheduler %d failed to bind to cpu %d: %s\n",
3410
 
                          (int) esdp->no, cpu_id, erl_errno_id(-res));
3411
 
            erts_send_error_to_logger_nogl(dsbufp);
3412
 
            if (scheduler2cpu_map[esdp->no].bound_id >= 0)
3413
 
                goto unbind;
3414
 
        }
3415
 
    }
3416
 
    else if (cpu_id < 0 && scheduler2cpu_map[esdp->no].bound_id >= 0) {
3417
 
    unbind:
3418
 
        /* Get rid of old binding */
3419
 
        res = erts_unbind_from_cpu(erts_cpuinfo);
3420
 
        if (res == 0)
3421
 
            esdp->cpu_id = scheduler2cpu_map[esdp->no].bound_id = -1;
3422
 
        else {
3423
 
            erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
3424
 
            erts_dsprintf(dsbufp, "Scheduler %d failed to unbind from cpu %d: %s\n",
3425
 
                          (int) esdp->no, cpu_id, erl_errno_id(-res));
3426
 
            erts_send_error_to_logger_nogl(dsbufp);
3427
 
        }
3428
 
    }
3429
 
    erts_smp_runq_lock(esdp->run_queue);
3430
 
#ifdef ERTS_SMP
3431
 
    if (erts_common_run_queue)
3432
 
        erts_smp_atomic_set(&esdp->chk_cpu_bind, 0);
3433
 
    else {
3434
 
        esdp->run_queue->flags &= ~ERTS_RUNQ_FLG_CHK_CPU_BIND;
3435
 
    }
3436
 
#endif
3437
 
    erts_smp_rwmtx_rwunlock(&erts_cpu_bind_rwmtx);
3438
 
 
3439
 
}
3440
 
 
3441
 
static void
3442
 
signal_schedulers_bind_change(erts_cpu_topology_t *cpudata, int size)
3443
 
{
3444
 
    int s_ix = 1;
3445
 
    int cpu_ix;
3446
 
 
3447
 
    if (cpu_bind_order != ERTS_CPU_BIND_NONE) {
3448
 
 
3449
 
        cpu_bind_order_sort(cpudata, size, cpu_bind_order, 1);
3450
 
 
3451
 
        for (cpu_ix = 0; cpu_ix < size && cpu_ix < erts_no_schedulers; cpu_ix++)
3452
 
            if (erts_is_cpu_available(erts_cpuinfo, cpudata[cpu_ix].logical))
3453
 
                scheduler2cpu_map[s_ix++].bind_id = cpudata[cpu_ix].logical;
3454
 
    }
3455
 
 
3456
 
    if (s_ix <= erts_no_schedulers)
3457
 
        for (; s_ix <= erts_no_schedulers; s_ix++)
3458
 
            scheduler2cpu_map[s_ix].bind_id = -1;
3459
 
 
3460
 
#ifdef ERTS_SMP
3461
 
    if (erts_common_run_queue) {
3462
 
        for (s_ix = 0; s_ix < erts_no_schedulers; s_ix++)
3463
 
            erts_smp_atomic_set(&ERTS_SCHEDULER_IX(s_ix)->chk_cpu_bind, 1);
3464
 
        wake_all_schedulers();
3465
 
    }
3466
 
    else {
3467
 
        ERTS_FOREACH_RUNQ(rq,
3468
 
        {
3469
 
            rq->flags |= ERTS_RUNQ_FLG_CHK_CPU_BIND;
3470
 
            wake_scheduler(rq, 0);
3471
 
        });
3472
 
    }
3473
 
#else
3474
 
    check_cpu_bind(erts_get_scheduler_data());
3475
 
#endif
3476
 
}
3477
 
 
3478
 
int
3479
 
erts_init_scheduler_bind_type(char *how)
3480
 
{
3481
 
    if (erts_bind_to_cpu(erts_cpuinfo, -1) == -ENOTSUP)
3482
 
        return ERTS_INIT_SCHED_BIND_TYPE_NOT_SUPPORTED;
3483
 
 
3484
 
    if (!system_cpudata && !user_cpudata)
3485
 
        return ERTS_INIT_SCHED_BIND_TYPE_ERROR_NO_CPU_TOPOLOGY;
3486
 
 
3487
 
    if (sys_strcmp(how, "s") == 0)
3488
 
        cpu_bind_order = ERTS_CPU_BIND_SPREAD;
3489
 
    else if (sys_strcmp(how, "ps") == 0)
3490
 
        cpu_bind_order = ERTS_CPU_BIND_PROCESSOR_SPREAD;
3491
 
    else if (sys_strcmp(how, "ts") == 0)
3492
 
        cpu_bind_order = ERTS_CPU_BIND_THREAD_SPREAD;
3493
 
    else if (sys_strcmp(how, "db") == 0
3494
 
             || sys_strcmp(how, "tnnps") == 0)
3495
 
        cpu_bind_order = ERTS_CPU_BIND_THREAD_NO_NODE_PROCESSOR_SPREAD;
3496
 
    else if (sys_strcmp(how, "nnps") == 0)
3497
 
        cpu_bind_order = ERTS_CPU_BIND_NO_NODE_PROCESSOR_SPREAD;
3498
 
    else if (sys_strcmp(how, "nnts") == 0)
3499
 
        cpu_bind_order = ERTS_CPU_BIND_NO_NODE_THREAD_SPREAD;
3500
 
    else if (sys_strcmp(how, "ns") == 0)
3501
 
        cpu_bind_order = ERTS_CPU_BIND_NO_SPREAD;
3502
 
    else if (sys_strcmp(how, "u") == 0)
3503
 
        cpu_bind_order = ERTS_CPU_BIND_NONE;
3504
 
    else
3505
 
        return ERTS_INIT_SCHED_BIND_TYPE_ERROR_NO_BAD_TYPE;
3506
 
 
3507
 
    return ERTS_INIT_SCHED_BIND_TYPE_SUCCESS;
3508
 
}
3509
 
 
3510
 
typedef struct {
3511
 
    int *id;
3512
 
    int used;
3513
 
    int size;
3514
 
} ErtsCpuTopIdSeq;
3515
 
 
3516
 
typedef struct {
3517
 
    ErtsCpuTopIdSeq logical;
3518
 
    ErtsCpuTopIdSeq thread;
3519
 
    ErtsCpuTopIdSeq core;
3520
 
    ErtsCpuTopIdSeq processor_node;
3521
 
    ErtsCpuTopIdSeq processor;
3522
 
    ErtsCpuTopIdSeq node;
3523
 
} ErtsCpuTopEntry;
3524
 
 
3525
 
static void
3526
 
init_cpu_top_entry(ErtsCpuTopEntry *cte)
3527
 
{
3528
 
    int size = 10;
3529
 
    cte->logical.id = erts_alloc(ERTS_ALC_T_TMP_CPU_IDS,
3530
 
                                 sizeof(int)*size);
3531
 
    cte->logical.size = size;
3532
 
    cte->thread.id = erts_alloc(ERTS_ALC_T_TMP_CPU_IDS,
3533
 
                                sizeof(int)*size);
3534
 
    cte->thread.size = size;
3535
 
    cte->core.id = erts_alloc(ERTS_ALC_T_TMP_CPU_IDS,
3536
 
                              sizeof(int)*size);
3537
 
    cte->core.size = size;
3538
 
    cte->processor_node.id = erts_alloc(ERTS_ALC_T_TMP_CPU_IDS,
3539
 
                                        sizeof(int)*size);
3540
 
    cte->processor_node.size = size;
3541
 
    cte->processor.id = erts_alloc(ERTS_ALC_T_TMP_CPU_IDS,
3542
 
                                   sizeof(int)*size);
3543
 
    cte->processor.size = size;
3544
 
    cte->node.id = erts_alloc(ERTS_ALC_T_TMP_CPU_IDS,
3545
 
                              sizeof(int)*size);
3546
 
    cte->node.size = size;
3547
 
}
3548
 
 
3549
 
static void
3550
 
destroy_cpu_top_entry(ErtsCpuTopEntry *cte)
3551
 
{
3552
 
    erts_free(ERTS_ALC_T_TMP_CPU_IDS, cte->logical.id);
3553
 
    erts_free(ERTS_ALC_T_TMP_CPU_IDS, cte->thread.id);
3554
 
    erts_free(ERTS_ALC_T_TMP_CPU_IDS, cte->core.id);
3555
 
    erts_free(ERTS_ALC_T_TMP_CPU_IDS, cte->processor_node.id);
3556
 
    erts_free(ERTS_ALC_T_TMP_CPU_IDS, cte->processor.id);
3557
 
    erts_free(ERTS_ALC_T_TMP_CPU_IDS, cte->node.id);
3558
 
}
3559
 
 
3560
 
static int
3561
 
get_cput_value_or_range(int *v, int *vr, char **str)
3562
 
{
3563
 
    long l;
3564
 
    char *c = *str;
3565
 
    errno = 0;
3566
 
    if (!isdigit((unsigned char)*c))
3567
 
        return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID;
3568
 
    l = strtol(c, &c, 10);
3569
 
    if (errno != 0 || l < 0 || ERTS_MAX_CPU_TOPOLOGY_ID < l)
3570
 
        return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID;
3571
 
    *v = (int) l;
3572
 
    if (*c == '-') {
3573
 
        c++;
3574
 
        if (!isdigit((unsigned char)*c))
3575
 
            return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_RANGE;
3576
 
        l = strtol(c, &c, 10);
3577
 
        if (errno != 0 || l < 0 || ERTS_MAX_CPU_TOPOLOGY_ID < l)
3578
 
            return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_RANGE;
3579
 
        *vr = (int) l;
3580
 
    }
3581
 
    *str = c;
3582
 
    return ERTS_INIT_CPU_TOPOLOGY_OK;
3583
 
}
3584
 
 
3585
 
static int
3586
 
get_cput_id_seq(ErtsCpuTopIdSeq *idseq, char **str)
3587
 
{
3588
 
    int ix = 0;
3589
 
    int need_size = 0;
3590
 
    char *c = *str;
3591
 
 
3592
 
    while (1) {
3593
 
        int res;
3594
 
        int val;
3595
 
        int nids;
3596
 
        int val_range = -1;
3597
 
        res = get_cput_value_or_range(&val, &val_range, &c);
3598
 
        if (res != ERTS_INIT_CPU_TOPOLOGY_OK)
3599
 
            return res;
3600
 
        if (val_range < 0 || val_range == val)
3601
 
            nids = 1;
3602
 
        else {
3603
 
            if (val_range > val)
3604
 
                nids = val_range - val + 1;
3605
 
            else
3606
 
                nids = val - val_range + 1;
3607
 
        }
3608
 
        need_size += nids;
3609
 
        if (need_size > idseq->size) {
3610
 
            idseq->size = need_size + 10;
3611
 
            idseq->id = erts_realloc(ERTS_ALC_T_TMP_CPU_IDS,
3612
 
                                      idseq->id,
3613
 
                                      sizeof(int)*idseq->size);
3614
 
        }
3615
 
        if (nids == 1)
3616
 
            idseq->id[ix++] = val;
3617
 
        else if (val_range > val) {
3618
 
            for (; val <= val_range; val++)
3619
 
                idseq->id[ix++] = val;
3620
 
        }
3621
 
        else {
3622
 
            for (; val >= val_range; val--)
3623
 
                idseq->id[ix++] = val;
3624
 
        }
3625
 
        if (*c != ',')
3626
 
            break;
3627
 
        c++;
3628
 
    }
3629
 
    *str = c;
3630
 
    idseq->used = ix;
3631
 
    return ERTS_INIT_CPU_TOPOLOGY_OK;
3632
 
}
3633
 
 
3634
 
static int
3635
 
get_cput_entry(ErtsCpuTopEntry *cput, char **str)
3636
 
{
3637
 
    int h;
3638
 
    char *c = *str;
3639
 
 
3640
 
    cput->logical.used = 0;
3641
 
    cput->thread.id[0] = 0;
3642
 
    cput->thread.used = 1;
3643
 
    cput->core.id[0] = 0;
3644
 
    cput->core.used = 1;
3645
 
    cput->processor_node.id[0] = -1;
3646
 
    cput->processor_node.used = 1;
3647
 
    cput->processor.id[0] = 0;
3648
 
    cput->processor.used = 1;
3649
 
    cput->node.id[0] = -1;
3650
 
    cput->node.used = 1;
3651
 
 
3652
 
    h = ERTS_TOPOLOGY_MAX_DEPTH;
3653
 
    while (*c != ':' && *c != '\0') {
3654
 
        int res;
3655
 
        ErtsCpuTopIdSeq *idseqp;
3656
 
        switch (*c++) {
3657
 
        case 'L':
3658
 
            if (h <= ERTS_TOPOLOGY_LOGICAL)
3659
 
                return ERTS_INIT_CPU_TOPOLOGY_INVALID_HIERARCHY;
3660
 
            idseqp = &cput->logical;
3661
 
            h = ERTS_TOPOLOGY_LOGICAL;
3662
 
            break;
3663
 
        case 't':
3664
 
        case 'T':
3665
 
            if (h <= ERTS_TOPOLOGY_THREAD)
3666
 
                return ERTS_INIT_CPU_TOPOLOGY_INVALID_HIERARCHY;
3667
 
            idseqp = &cput->thread;
3668
 
            h = ERTS_TOPOLOGY_THREAD;
3669
 
            break;
3670
 
        case 'c':
3671
 
        case 'C':
3672
 
            if (h <= ERTS_TOPOLOGY_CORE)
3673
 
                return ERTS_INIT_CPU_TOPOLOGY_INVALID_HIERARCHY;
3674
 
            idseqp = &cput->core;
3675
 
            h = ERTS_TOPOLOGY_CORE;
3676
 
            break;
3677
 
        case 'p':
3678
 
        case 'P':
3679
 
            if (h <= ERTS_TOPOLOGY_PROCESSOR)
3680
 
                return ERTS_INIT_CPU_TOPOLOGY_INVALID_HIERARCHY;
3681
 
            idseqp = &cput->processor;
3682
 
            h = ERTS_TOPOLOGY_PROCESSOR;
3683
 
            break;
3684
 
        case 'n':
3685
 
        case 'N':
3686
 
            if (h <= ERTS_TOPOLOGY_PROCESSOR) {
3687
 
            do_node:
3688
 
                if (h <= ERTS_TOPOLOGY_NODE)
3689
 
                    return ERTS_INIT_CPU_TOPOLOGY_INVALID_HIERARCHY;
3690
 
                idseqp = &cput->node;
3691
 
                h = ERTS_TOPOLOGY_NODE;
3692
 
            }
3693
 
            else {
3694
 
                int p_node = 0;
3695
 
                char *p_chk = c;
3696
 
                while (*p_chk != '\0' && *p_chk != ':') {
3697
 
                    if (*p_chk == 'p' || *p_chk == 'P') {
3698
 
                        p_node = 1;
3699
 
                        break;
3700
 
                    }
3701
 
                    p_chk++;
3702
 
                }
3703
 
                if (!p_node)
3704
 
                    goto do_node;
3705
 
                if (h <= ERTS_TOPOLOGY_PROCESSOR_NODE)
3706
 
                    return ERTS_INIT_CPU_TOPOLOGY_INVALID_HIERARCHY;
3707
 
                idseqp = &cput->processor_node;
3708
 
                h = ERTS_TOPOLOGY_PROCESSOR_NODE;
3709
 
            }
3710
 
            break;
3711
 
        default:
3712
 
            return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_TYPE;
3713
 
        }
3714
 
        res = get_cput_id_seq(idseqp, &c);
3715
 
        if (res != ERTS_INIT_CPU_TOPOLOGY_OK)
3716
 
                return res;
3717
 
    }
3718
 
 
3719
 
    if (cput->logical.used < 1)
3720
 
        return ERTS_INIT_CPU_TOPOLOGY_MISSING_LID;
3721
 
 
3722
 
    if (*c == ':') {
3723
 
        c++;
3724
 
    }
3725
 
 
3726
 
    if (cput->thread.used != 1
3727
 
        && cput->thread.used != cput->logical.used)
3728
 
        return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_RANGE;
3729
 
    if (cput->core.used != 1
3730
 
        && cput->core.used != cput->logical.used)
3731
 
        return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_RANGE;
3732
 
    if (cput->processor_node.used != 1
3733
 
        && cput->processor_node.used != cput->logical.used)
3734
 
        return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_RANGE;
3735
 
    if (cput->processor.used != 1
3736
 
        && cput->processor.used != cput->logical.used)
3737
 
        return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_RANGE;
3738
 
    if (cput->node.used != 1
3739
 
        && cput->node.used != cput->logical.used)
3740
 
        return ERTS_INIT_CPU_TOPOLOGY_INVALID_ID_RANGE;
3741
 
 
3742
 
    *str = c;
3743
 
    return ERTS_INIT_CPU_TOPOLOGY_OK;
3744
 
}
3745
 
 
3746
 
static int
3747
 
verify_topology(erts_cpu_topology_t *cpudata, int size)
3748
 
{
3749
 
    if (size > 0) {
3750
 
        int *logical;
3751
 
        int node, processor, no_nodes, i;
3752
 
 
3753
 
        /* Verify logical ids */
3754
 
        logical = erts_alloc(ERTS_ALC_T_TMP, sizeof(int)*size);
3755
 
 
3756
 
        for (i = 0; i < user_cpudata_size; i++)
3757
 
            logical[i] = user_cpudata[i].logical;
3758
 
 
3759
 
        qsort(logical, user_cpudata_size, sizeof(int), int_cmp);
3760
 
        for (i = 0; i < user_cpudata_size-1; i++) {
3761
 
            if (logical[i] == logical[i+1]) {
3762
 
                erts_free(ERTS_ALC_T_TMP, logical);
3763
 
                return ERTS_INIT_CPU_TOPOLOGY_NOT_UNIQUE_LIDS;
3764
 
            }
3765
 
        }
3766
 
 
3767
 
        erts_free(ERTS_ALC_T_TMP, logical);
3768
 
 
3769
 
        qsort(cpudata, size, sizeof(erts_cpu_topology_t), processor_order_cmp);
3770
 
 
3771
 
        /* Verify unique entities */
3772
 
 
3773
 
        for (i = 1; i < user_cpudata_size; i++) {
3774
 
            if (user_cpudata[i-1].processor == user_cpudata[i].processor
3775
 
                && user_cpudata[i-1].node == user_cpudata[i].node
3776
 
                && (user_cpudata[i-1].processor_node
3777
 
                    == user_cpudata[i].processor_node)
3778
 
                && user_cpudata[i-1].core == user_cpudata[i].core
3779
 
                && user_cpudata[i-1].thread == user_cpudata[i].thread) {
3780
 
                return ERTS_INIT_CPU_TOPOLOGY_NOT_UNIQUE_ENTITIES;
3781
 
            }
3782
 
        }
3783
 
 
3784
 
        /* Verify numa nodes */
3785
 
        node = cpudata[0].node;
3786
 
        processor = cpudata[0].processor;
3787
 
        no_nodes = cpudata[0].node < 0 && cpudata[0].processor_node < 0;
3788
 
        for (i = 1; i < size; i++) {
3789
 
            if (no_nodes) {
3790
 
                if (cpudata[i].node >= 0 || cpudata[i].processor_node >= 0)
3791
 
                    return ERTS_INIT_CPU_TOPOLOGY_INVALID_NODES;
3792
 
            }
3793
 
            else {
3794
 
                if (cpudata[i].processor == processor && cpudata[i].node != node)
3795
 
                    return ERTS_INIT_CPU_TOPOLOGY_INVALID_NODES;
3796
 
                node = cpudata[i].node;
3797
 
                processor = cpudata[i].processor;
3798
 
                if (node >= 0 && cpudata[i].processor_node >= 0)
3799
 
                    return ERTS_INIT_CPU_TOPOLOGY_INVALID_NODES;
3800
 
                if (node < 0 && cpudata[i].processor_node < 0)
3801
 
                    return ERTS_INIT_CPU_TOPOLOGY_INVALID_NODES;
3802
 
            }
3803
 
        }
3804
 
    }
3805
 
 
3806
 
    return ERTS_INIT_CPU_TOPOLOGY_OK;
3807
 
}
3808
 
 
3809
 
int
3810
 
erts_init_cpu_topology(char *topology_str)
3811
 
{
3812
 
    ErtsCpuTopEntry cput;
3813
 
    int need_size;
3814
 
    char *c;
3815
 
    int ix;
3816
 
    int error = ERTS_INIT_CPU_TOPOLOGY_OK;
3817
 
 
3818
 
    if (user_cpudata)
3819
 
        erts_free(ERTS_ALC_T_CPUDATA, user_cpudata);
3820
 
    user_cpudata_size = 10;
3821
 
 
3822
 
    user_cpudata = erts_alloc(ERTS_ALC_T_CPUDATA,
3823
 
                              (sizeof(erts_cpu_topology_t)
3824
 
                               * user_cpudata_size));
3825
 
 
3826
 
    init_cpu_top_entry(&cput);
3827
 
 
3828
 
    ix = 0;
3829
 
    need_size = 0;
3830
 
 
3831
 
    c = topology_str;
3832
 
    if (*c == '\0') {
3833
 
        error = ERTS_INIT_CPU_TOPOLOGY_MISSING;
3834
 
        goto fail;
3835
 
    }
3836
 
    do {
3837
 
        int r;
3838
 
        error = get_cput_entry(&cput, &c);
3839
 
        if (error != ERTS_INIT_CPU_TOPOLOGY_OK)
3840
 
            goto fail;
3841
 
        need_size += cput.logical.used;
3842
 
        if (user_cpudata_size < need_size) {
3843
 
            user_cpudata_size = need_size + 10;
3844
 
            user_cpudata = erts_realloc(ERTS_ALC_T_CPUDATA,
3845
 
                                        user_cpudata,
3846
 
                                        (sizeof(erts_cpu_topology_t)
3847
 
                                         * user_cpudata_size));
3848
 
        }
3849
 
 
3850
 
        ASSERT(cput.thread.used == 1
3851
 
               || cput.thread.used == cput.logical.used);
3852
 
        ASSERT(cput.core.used == 1
3853
 
               || cput.core.used == cput.logical.used);
3854
 
        ASSERT(cput.processor_node.used == 1
3855
 
               || cput.processor_node.used == cput.logical.used);
3856
 
        ASSERT(cput.processor.used == 1
3857
 
               || cput.processor.used == cput.logical.used);
3858
 
        ASSERT(cput.node.used == 1
3859
 
               || cput.node.used == cput.logical.used);
3860
 
 
3861
 
        for (r = 0; r < cput.logical.used; r++) {
3862
 
            user_cpudata[ix].logical = cput.logical.id[r];
3863
 
            user_cpudata[ix].thread =
3864
 
                cput.thread.id[cput.thread.used == 1 ? 0 : r];
3865
 
            user_cpudata[ix].core =
3866
 
                cput.core.id[cput.core.used == 1 ? 0 : r];
3867
 
            user_cpudata[ix].processor_node =
3868
 
                cput.processor_node.id[cput.processor_node.used == 1 ? 0 : r];
3869
 
            user_cpudata[ix].processor =
3870
 
                cput.processor.id[cput.processor.used == 1 ? 0 : r];
3871
 
            user_cpudata[ix].node =
3872
 
                cput.node.id[cput.node.used == 1 ? 0 : r];
3873
 
            ix++;
3874
 
        }
3875
 
    } while (*c != '\0');
3876
 
 
3877
 
    if (user_cpudata_size != ix) {
3878
 
        user_cpudata_size = ix;
3879
 
        user_cpudata = erts_realloc(ERTS_ALC_T_CPUDATA,
3880
 
                                    user_cpudata,
3881
 
                                    (sizeof(erts_cpu_topology_t)
3882
 
                                     * user_cpudata_size));
3883
 
    }
3884
 
 
3885
 
    error = verify_topology(user_cpudata, user_cpudata_size);
3886
 
    if (error == ERTS_INIT_CPU_TOPOLOGY_OK) {
3887
 
        destroy_cpu_top_entry(&cput);
3888
 
        return ERTS_INIT_CPU_TOPOLOGY_OK;
3889
 
    }
3890
 
 
3891
 
 fail:
3892
 
    if (user_cpudata)
3893
 
        erts_free(ERTS_ALC_T_CPUDATA, user_cpudata);
3894
 
    user_cpudata_size = 0;
3895
 
    destroy_cpu_top_entry(&cput);
3896
 
    return error;
3897
 
}
3898
 
 
3899
 
#define ERTS_GET_CPU_TOPOLOGY_ERROR             -1
3900
 
#define ERTS_GET_USED_CPU_TOPOLOGY              0
3901
 
#define ERTS_GET_DETECTED_CPU_TOPOLOGY          1
3902
 
#define ERTS_GET_DEFINED_CPU_TOPOLOGY           2
3903
 
 
3904
 
static Eterm get_cpu_topology_term(Process *c_p, int type);
3905
 
 
3906
 
Eterm
3907
 
erts_set_cpu_topology(Process *c_p, Eterm term)
3908
 
{
3909
 
    erts_cpu_topology_t *cpudata = NULL;
3910
 
    int cpudata_size = 0;
3911
 
    Eterm res;
3912
 
 
3913
 
    erts_smp_rwmtx_rwlock(&erts_cpu_bind_rwmtx);
3914
 
    res = get_cpu_topology_term(c_p, ERTS_GET_USED_CPU_TOPOLOGY);
3915
 
    if (term == am_undefined) {
3916
 
        if (user_cpudata)
3917
 
            erts_free(ERTS_ALC_T_CPUDATA, user_cpudata);
3918
 
        user_cpudata = NULL;
3919
 
        user_cpudata_size = 0;
3920
 
 
3921
 
        if (cpu_bind_order != ERTS_CPU_BIND_NONE && system_cpudata) {
3922
 
            cpudata_size = system_cpudata_size;
3923
 
            cpudata = erts_alloc(ERTS_ALC_T_TMP,
3924
 
                                 (sizeof(erts_cpu_topology_t)
3925
 
                                  * cpudata_size));
3926
 
 
3927
 
            sys_memcpy((void *) cpudata,
3928
 
                       (void *) system_cpudata,
3929
 
                       sizeof(erts_cpu_topology_t)*cpudata_size);
3930
 
        }
3931
 
    }
3932
 
    else if (is_not_list(term)) {
3933
 
    error:
3934
 
        res = THE_NON_VALUE;
3935
 
        goto done;
3936
 
    }
3937
 
    else {
3938
 
        Eterm list = term;
3939
 
        int ix = 0;
3940
 
 
3941
 
        cpudata_size = 100;
3942
 
        cpudata = erts_alloc(ERTS_ALC_T_TMP,
3943
 
                             (sizeof(erts_cpu_topology_t)
3944
 
                              * cpudata_size));
3945
 
 
3946
 
        while (is_list(list)) {
3947
 
            Eterm *lp = list_val(list);
3948
 
            Eterm cpu = CAR(lp);
3949
 
            Eterm* tp;
3950
 
            Sint id;
3951
 
                
3952
 
            if (is_not_tuple(cpu))
3953
 
                goto error;
3954
 
 
3955
 
            tp = tuple_val(cpu);
3956
 
 
3957
 
            if (arityval(tp[0]) != 7 || tp[1] != am_cpu)
3958
 
                goto error;
3959
 
 
3960
 
            if (ix >= cpudata_size) {
3961
 
                cpudata_size += 100;
3962
 
                cpudata = erts_realloc(ERTS_ALC_T_TMP,
3963
 
                                       cpudata,
3964
 
                                       (sizeof(erts_cpu_topology_t)
3965
 
                                        * cpudata_size));
3966
 
            }
3967
 
 
3968
 
            id = signed_val(tp[2]);
3969
 
            if (id < -1 || ERTS_MAX_CPU_TOPOLOGY_ID < id)
3970
 
                goto error;
3971
 
            cpudata[ix].node = (int) id;
3972
 
 
3973
 
            id = signed_val(tp[3]);
3974
 
            if (id < -1 || ERTS_MAX_CPU_TOPOLOGY_ID < id)
3975
 
                goto error;
3976
 
            cpudata[ix].processor = (int) id;
3977
 
 
3978
 
            id = signed_val(tp[4]);
3979
 
            if (id < -1 || ERTS_MAX_CPU_TOPOLOGY_ID < id)
3980
 
                goto error;
3981
 
            cpudata[ix].processor_node = (int) id;
3982
 
 
3983
 
            id = signed_val(tp[5]);
3984
 
            if (id < -1 || ERTS_MAX_CPU_TOPOLOGY_ID < id)
3985
 
                goto error;
3986
 
            cpudata[ix].core = (int) id;
3987
 
 
3988
 
            id = signed_val(tp[6]);
3989
 
            if (id < -1 || ERTS_MAX_CPU_TOPOLOGY_ID < id)
3990
 
                goto error;
3991
 
            cpudata[ix].thread = (int) id;
3992
 
 
3993
 
            id = signed_val(tp[7]);
3994
 
            if (id < -1 || ERTS_MAX_CPU_TOPOLOGY_ID < id)
3995
 
                goto error;
3996
 
            cpudata[ix].logical = (int) id;
3997
 
 
3998
 
            list = CDR(lp);
3999
 
            ix++;
4000
 
        }
4001
 
 
4002
 
        if (is_not_nil(list))
4003
 
            goto error;
4004
 
        
4005
 
        cpudata_size = ix;
4006
 
 
4007
 
        if (ERTS_INIT_CPU_TOPOLOGY_OK != verify_topology(cpudata, cpudata_size))
4008
 
            goto error;
4009
 
 
4010
 
        if (user_cpudata_size != cpudata_size) {
4011
 
            if (user_cpudata)
4012
 
                erts_free(ERTS_ALC_T_CPUDATA, user_cpudata);
4013
 
            user_cpudata = erts_alloc(ERTS_ALC_T_CPUDATA,
4014
 
                                      sizeof(erts_cpu_topology_t)*cpudata_size);
4015
 
            user_cpudata_size = cpudata_size;
4016
 
        }
4017
 
 
4018
 
        sys_memcpy((void *) user_cpudata,
4019
 
                   (void *) cpudata,
4020
 
                   sizeof(erts_cpu_topology_t)*cpudata_size);
4021
 
    }
4022
 
 
4023
 
    signal_schedulers_bind_change(cpudata, cpudata_size);
4024
 
 
4025
 
 done:
4026
 
    erts_smp_rwmtx_rwunlock(&erts_cpu_bind_rwmtx);
4027
 
 
4028
 
    if (cpudata)
4029
 
        erts_free(ERTS_ALC_T_TMP, cpudata);
4030
 
 
4031
 
    return res;
4032
 
}
4033
 
 
4034
 
static Eterm
4035
 
bound_schedulers_term(ErtsCpuBindOrder order)
4036
 
{
4037
 
    switch (order) {
4038
 
    case ERTS_CPU_BIND_SPREAD: {
4039
 
        ERTS_DECL_AM(spread);
4040
 
        return AM_spread;
4041
 
    }
4042
 
    case ERTS_CPU_BIND_PROCESSOR_SPREAD: {
4043
 
        ERTS_DECL_AM(processor_spread);
4044
 
        return AM_processor_spread;
4045
 
    }
4046
 
    case ERTS_CPU_BIND_THREAD_SPREAD: {
4047
 
        ERTS_DECL_AM(thread_spread);
4048
 
        return AM_thread_spread;
4049
 
    }
4050
 
    case ERTS_CPU_BIND_THREAD_NO_NODE_PROCESSOR_SPREAD: {
4051
 
        ERTS_DECL_AM(thread_no_node_processor_spread);
4052
 
        return AM_thread_no_node_processor_spread;
4053
 
    }
4054
 
    case ERTS_CPU_BIND_NO_NODE_PROCESSOR_SPREAD: {
4055
 
        ERTS_DECL_AM(no_node_processor_spread);
4056
 
        return AM_no_node_processor_spread;
4057
 
    }
4058
 
    case ERTS_CPU_BIND_NO_NODE_THREAD_SPREAD: {
4059
 
        ERTS_DECL_AM(no_node_thread_spread);
4060
 
        return AM_no_node_thread_spread;
4061
 
    }
4062
 
    case ERTS_CPU_BIND_NO_SPREAD: {
4063
 
        ERTS_DECL_AM(no_spread);
4064
 
        return AM_no_spread;
4065
 
    }
4066
 
    case ERTS_CPU_BIND_NONE: {
4067
 
        ERTS_DECL_AM(unbound);
4068
 
        return AM_unbound;
4069
 
    }
4070
 
    default:
4071
 
        ASSERT(0);
4072
 
        return THE_NON_VALUE;
4073
 
    }
4074
 
}
4075
 
 
4076
 
Eterm
4077
 
erts_bound_schedulers_term(Process *c_p)
4078
 
{
4079
 
    ErtsCpuBindOrder order;
4080
 
    erts_smp_rwmtx_rlock(&erts_cpu_bind_rwmtx);
4081
 
    order = cpu_bind_order;
4082
 
    erts_smp_rwmtx_runlock(&erts_cpu_bind_rwmtx);
4083
 
    return bound_schedulers_term(order);
4084
 
}
4085
 
 
4086
 
static void
4087
 
create_tmp_cpu_topology_copy(erts_cpu_topology_t **cpudata, int *cpudata_size)
4088
 
{
4089
 
    if (user_cpudata) {
4090
 
        *cpudata_size = user_cpudata_size;
4091
 
        *cpudata = erts_alloc(ERTS_ALC_T_TMP,
4092
 
                              (sizeof(erts_cpu_topology_t)
4093
 
                               * (*cpudata_size)));
4094
 
        sys_memcpy((void *) *cpudata,
4095
 
                   (void *) user_cpudata,
4096
 
                   sizeof(erts_cpu_topology_t)*(*cpudata_size));
4097
 
    }
4098
 
    else if (system_cpudata) {
4099
 
        *cpudata_size = system_cpudata_size;
4100
 
        *cpudata = erts_alloc(ERTS_ALC_T_TMP,
4101
 
                              (sizeof(erts_cpu_topology_t)
4102
 
                               * (*cpudata_size)));
4103
 
        sys_memcpy((void *) *cpudata,
4104
 
                   (void *) system_cpudata,
4105
 
                   sizeof(erts_cpu_topology_t)*(*cpudata_size));
4106
 
    }
4107
 
    else {
4108
 
        *cpudata = NULL;
4109
 
        *cpudata_size = 0;
4110
 
    }
4111
 
}
4112
 
 
4113
 
static void
4114
 
destroy_tmp_cpu_topology_copy(erts_cpu_topology_t *cpudata)
4115
 
{
4116
 
    if (cpudata)
4117
 
        erts_free(ERTS_ALC_T_TMP, cpudata);
4118
 
}
4119
 
 
4120
 
Eterm
4121
 
erts_bind_schedulers(Process *c_p, Eterm how)
4122
 
{
4123
 
    Eterm res;
4124
 
    erts_cpu_topology_t *cpudata;
4125
 
    int cpudata_size;
4126
 
    ErtsCpuBindOrder old_cpu_bind_order;
4127
 
 
4128
 
    erts_smp_rwmtx_rwlock(&erts_cpu_bind_rwmtx);
4129
 
 
4130
 
    if (erts_bind_to_cpu(erts_cpuinfo, -1) == -ENOTSUP) {
4131
 
        ERTS_BIF_PREP_ERROR(res, c_p, EXC_NOTSUP);
4132
 
    }
4133
 
    else {
4134
 
 
4135
 
        old_cpu_bind_order = cpu_bind_order;
4136
 
 
4137
 
        if (ERTS_IS_ATOM_STR("spread", how))
4138
 
            cpu_bind_order = ERTS_CPU_BIND_SPREAD;
4139
 
        else if (ERTS_IS_ATOM_STR("processor_spread", how))
4140
 
            cpu_bind_order = ERTS_CPU_BIND_PROCESSOR_SPREAD;
4141
 
        else if (ERTS_IS_ATOM_STR("thread_spread", how))
4142
 
            cpu_bind_order = ERTS_CPU_BIND_THREAD_SPREAD;
4143
 
        else if (ERTS_IS_ATOM_STR("default_bind", how)
4144
 
                 || ERTS_IS_ATOM_STR("thread_no_node_processor_spread", how))
4145
 
            cpu_bind_order = ERTS_CPU_BIND_THREAD_NO_NODE_PROCESSOR_SPREAD;
4146
 
        else if (ERTS_IS_ATOM_STR("no_node_processor_spread", how))
4147
 
            cpu_bind_order = ERTS_CPU_BIND_NO_NODE_PROCESSOR_SPREAD;
4148
 
        else if (ERTS_IS_ATOM_STR("no_node_thread_spread", how))
4149
 
            cpu_bind_order = ERTS_CPU_BIND_NO_NODE_THREAD_SPREAD;
4150
 
        else if (ERTS_IS_ATOM_STR("no_spread", how))
4151
 
            cpu_bind_order = ERTS_CPU_BIND_NO_SPREAD;
4152
 
        else if (ERTS_IS_ATOM_STR("unbound", how))
4153
 
            cpu_bind_order = ERTS_CPU_BIND_NONE;
4154
 
        else {
4155
 
            cpu_bind_order = old_cpu_bind_order;
4156
 
            ERTS_BIF_PREP_ERROR(res, c_p, BADARG);
4157
 
            goto done;
4158
 
        }
4159
 
 
4160
 
        create_tmp_cpu_topology_copy(&cpudata, &cpudata_size);
4161
 
 
4162
 
        if (!cpudata) {
4163
 
            cpu_bind_order = old_cpu_bind_order;
4164
 
            ERTS_BIF_PREP_ERROR(res, c_p, BADARG);
4165
 
            goto done;
4166
 
        }
4167
 
 
4168
 
        signal_schedulers_bind_change(cpudata, cpudata_size);
4169
 
 
4170
 
        destroy_tmp_cpu_topology_copy(cpudata);
4171
 
    
4172
 
        res = bound_schedulers_term(old_cpu_bind_order);
4173
 
    }
4174
 
 
4175
 
 done:
4176
 
 
4177
 
    erts_smp_rwmtx_rwunlock(&erts_cpu_bind_rwmtx);
4178
 
 
4179
 
    return res;
4180
 
}
4181
 
 
4182
 
Eterm
4183
 
erts_fake_scheduler_bindings(Process *p, Eterm how)
4184
 
{
4185
 
    ErtsCpuBindOrder fake_cpu_bind_order;
4186
 
    erts_cpu_topology_t *cpudata;
4187
 
    int cpudata_size;
4188
 
    Eterm res;
4189
 
 
4190
 
    if (ERTS_IS_ATOM_STR("spread", how))
4191
 
        fake_cpu_bind_order = ERTS_CPU_BIND_SPREAD;
4192
 
    else if (ERTS_IS_ATOM_STR("processor_spread", how))
4193
 
        fake_cpu_bind_order = ERTS_CPU_BIND_PROCESSOR_SPREAD;
4194
 
    else if (ERTS_IS_ATOM_STR("thread_spread", how))
4195
 
        fake_cpu_bind_order = ERTS_CPU_BIND_THREAD_SPREAD;
4196
 
    else if (ERTS_IS_ATOM_STR("default_bind", how)
4197
 
             || ERTS_IS_ATOM_STR("thread_no_node_processor_spread", how))
4198
 
        fake_cpu_bind_order = ERTS_CPU_BIND_THREAD_NO_NODE_PROCESSOR_SPREAD;
4199
 
    else if (ERTS_IS_ATOM_STR("no_node_processor_spread", how))
4200
 
        fake_cpu_bind_order = ERTS_CPU_BIND_NO_NODE_PROCESSOR_SPREAD;
4201
 
    else if (ERTS_IS_ATOM_STR("no_node_thread_spread", how))
4202
 
        fake_cpu_bind_order = ERTS_CPU_BIND_NO_NODE_THREAD_SPREAD;
4203
 
    else if (ERTS_IS_ATOM_STR("no_spread", how))
4204
 
        fake_cpu_bind_order = ERTS_CPU_BIND_NO_SPREAD;
4205
 
    else if (ERTS_IS_ATOM_STR("unbound", how))
4206
 
        fake_cpu_bind_order = ERTS_CPU_BIND_NONE;
4207
 
    else {
4208
 
        ERTS_BIF_PREP_ERROR(res, p, BADARG);
4209
 
        return res;
4210
 
    }
4211
 
 
4212
 
    erts_smp_rwmtx_rlock(&erts_cpu_bind_rwmtx);
4213
 
    create_tmp_cpu_topology_copy(&cpudata, &cpudata_size);
4214
 
    erts_smp_rwmtx_runlock(&erts_cpu_bind_rwmtx);
4215
 
 
4216
 
    if (!cpudata || fake_cpu_bind_order == ERTS_CPU_BIND_NONE)
4217
 
        ERTS_BIF_PREP_RET(res, am_false);
4218
 
    else {
4219
 
        int i;
4220
 
        Eterm *hp;
4221
 
        
4222
 
        cpu_bind_order_sort(cpudata, cpudata_size, fake_cpu_bind_order, 1);
4223
 
 
4224
 
#ifdef ERTS_FAKE_SCHED_BIND_PRINT_SORTED_CPU_DATA
4225
 
 
4226
 
        erts_fprintf(stderr, "node:          ");
4227
 
        for (i = 0; i < cpudata_size; i++)
4228
 
            erts_fprintf(stderr, " %2d", cpudata[i].node);
4229
 
        erts_fprintf(stderr, "\n");
4230
 
        erts_fprintf(stderr, "processor:     ");
4231
 
        for (i = 0; i < cpudata_size; i++)
4232
 
            erts_fprintf(stderr, " %2d", cpudata[i].processor);
4233
 
        erts_fprintf(stderr, "\n");
4234
 
        if (fake_cpu_bind_order != ERTS_CPU_BIND_THREAD_NO_NODE_PROCESSOR_SPREAD
4235
 
            && fake_cpu_bind_order != ERTS_CPU_BIND_NO_NODE_PROCESSOR_SPREAD
4236
 
            && fake_cpu_bind_order != ERTS_CPU_BIND_NO_NODE_THREAD_SPREAD) {
4237
 
            erts_fprintf(stderr, "processor_node:");
4238
 
            for (i = 0; i < cpudata_size; i++)
4239
 
                erts_fprintf(stderr, " %2d", cpudata[i].processor_node);
4240
 
            erts_fprintf(stderr, "\n");
4241
 
        }
4242
 
        erts_fprintf(stderr, "core:          ");
4243
 
        for (i = 0; i < cpudata_size; i++)
4244
 
            erts_fprintf(stderr, " %2d", cpudata[i].core);
4245
 
        erts_fprintf(stderr, "\n");
4246
 
        erts_fprintf(stderr, "thread:        ");
4247
 
        for (i = 0; i < cpudata_size; i++)
4248
 
            erts_fprintf(stderr, " %2d", cpudata[i].thread);
4249
 
        erts_fprintf(stderr, "\n");
4250
 
        erts_fprintf(stderr, "logical:       ");
4251
 
        for (i = 0; i < cpudata_size; i++)
4252
 
            erts_fprintf(stderr, " %2d", cpudata[i].logical);
4253
 
        erts_fprintf(stderr, "\n");
4254
 
#endif
4255
 
 
4256
 
        hp = HAlloc(p, cpudata_size+1);
4257
 
        ERTS_BIF_PREP_RET(res, make_tuple(hp));
4258
 
        *hp++ = make_arityval((Uint) cpudata_size);
4259
 
        for (i = 0; i < cpudata_size; i++)
4260
 
            *hp++ = make_small((Uint) cpudata[i].logical);
4261
 
    }
4262
 
 
4263
 
    destroy_tmp_cpu_topology_copy(cpudata);
4264
 
 
4265
 
    return res;
4266
 
}
4267
 
 
4268
 
Eterm
4269
 
erts_get_schedulers_binds(Process *c_p)
4270
 
{
4271
 
    int ix;
4272
 
    ERTS_DECL_AM(unbound);
4273
 
    Eterm *hp = HAlloc(c_p, erts_no_schedulers+1);
4274
 
    Eterm res = make_tuple(hp);
4275
 
 
4276
 
    *(hp++) = make_arityval(erts_no_schedulers);
4277
 
    erts_smp_rwmtx_rlock(&erts_cpu_bind_rwmtx);
4278
 
    for (ix = 1; ix <= erts_no_schedulers; ix++)
4279
 
        *(hp++) = (scheduler2cpu_map[ix].bound_id >= 0
4280
 
                   ? make_small(scheduler2cpu_map[ix].bound_id)
4281
 
                   : AM_unbound);
4282
 
    erts_smp_rwmtx_runlock(&erts_cpu_bind_rwmtx);
4283
 
    return res;
4284
 
}
4285
 
 
4286
 
static Eterm
4287
 
bld_topology_term(Eterm **hpp,
4288
 
                  Uint *hszp,
4289
 
                  erts_cpu_topology_t *cpudata,
4290
 
                  int size)
4291
 
{
4292
 
    Eterm res = NIL;
4293
 
    int i;
4294
 
 
4295
 
    if (size == 0)
4296
 
        return am_undefined;
4297
 
 
4298
 
    for (i = size-1; i >= 0; i--) {
4299
 
        res = erts_bld_cons(hpp,
4300
 
                            hszp,
4301
 
                            erts_bld_tuple(hpp,
4302
 
                                           hszp,
4303
 
                                           7,
4304
 
                                           am_cpu,
4305
 
                                           make_small(cpudata[i].node),
4306
 
                                           make_small(cpudata[i].processor),
4307
 
                                           make_small(cpudata[i].processor_node),
4308
 
                                           make_small(cpudata[i].core),
4309
 
                                           make_small(cpudata[i].thread),
4310
 
                                           make_small(cpudata[i].logical)),
4311
 
                            res);
4312
 
    }
4313
 
    return res;
4314
 
}
4315
 
 
4316
 
static Eterm
4317
 
get_cpu_topology_term(Process *c_p, int type)
4318
 
{
4319
 
#ifdef DEBUG
4320
 
    Eterm *hp_end;
4321
 
#endif
4322
 
    Eterm *hp;
4323
 
    Uint hsz;
4324
 
    Eterm res = THE_NON_VALUE;
4325
 
    erts_cpu_topology_t *cpudata = NULL;
4326
 
    int size = 0;
4327
 
 
4328
 
    switch (type) {
4329
 
    case ERTS_GET_USED_CPU_TOPOLOGY:
4330
 
        if (user_cpudata)
4331
 
            goto defined;
4332
 
        else
4333
 
            goto detected;
4334
 
    case ERTS_GET_DETECTED_CPU_TOPOLOGY:
4335
 
    detected:
4336
 
        if (!system_cpudata)
4337
 
            res = am_undefined;
4338
 
        else {
4339
 
            size = system_cpudata_size;
4340
 
            cpudata = erts_alloc(ERTS_ALC_T_TMP,
4341
 
                                 (sizeof(erts_cpu_topology_t)
4342
 
                                  * size));
4343
 
            sys_memcpy((void *) cpudata,
4344
 
                       (void *) system_cpudata,
4345
 
                       sizeof(erts_cpu_topology_t)*size);
4346
 
        }
4347
 
        break;
4348
 
    case ERTS_GET_DEFINED_CPU_TOPOLOGY:
4349
 
    defined:
4350
 
        if (!user_cpudata)
4351
 
            res = am_undefined;
4352
 
        else {
4353
 
            size = user_cpudata_size;
4354
 
            cpudata = user_cpudata;
4355
 
        }
4356
 
        break;
4357
 
    default:
4358
 
        erl_exit(ERTS_ABORT_EXIT, "Bad cpu topology type: %d\n", type);
4359
 
        break;
4360
 
    }
4361
 
 
4362
 
    if (res == am_undefined) {
4363
 
        ASSERT(!cpudata);
4364
 
        return res;
4365
 
    }
4366
 
 
4367
 
    hsz = 0;
4368
 
 
4369
 
    bld_topology_term(NULL, &hsz,
4370
 
                      cpudata, size);
4371
 
 
4372
 
    hp = HAlloc(c_p, hsz);
4373
 
 
4374
 
#ifdef DEBUG
4375
 
    hp_end = hp + hsz;
4376
 
#endif
4377
 
 
4378
 
    res = bld_topology_term(&hp, NULL,
4379
 
                            cpudata, size);
4380
 
 
4381
 
    ASSERT(hp_end == hp);
4382
 
 
4383
 
    if (cpudata && cpudata != system_cpudata && cpudata != user_cpudata)
4384
 
        erts_free(ERTS_ALC_T_TMP, cpudata);
4385
 
 
4386
 
    return res;
4387
 
}
4388
 
 
4389
 
Eterm
4390
 
erts_get_cpu_topology_term(Process *c_p, Eterm which)
4391
 
{
4392
 
    Eterm res;
4393
 
    int type;
4394
 
    erts_smp_rwmtx_rlock(&erts_cpu_bind_rwmtx);
4395
 
    if (ERTS_IS_ATOM_STR("used", which))
4396
 
        type = ERTS_GET_USED_CPU_TOPOLOGY;
4397
 
    else if (ERTS_IS_ATOM_STR("detected", which))
4398
 
        type = ERTS_GET_DETECTED_CPU_TOPOLOGY;
4399
 
    else if (ERTS_IS_ATOM_STR("defined", which))
4400
 
        type = ERTS_GET_DEFINED_CPU_TOPOLOGY;
4401
 
    else
4402
 
        type = ERTS_GET_CPU_TOPOLOGY_ERROR;
4403
 
    if (type == ERTS_GET_CPU_TOPOLOGY_ERROR)
4404
 
        res = THE_NON_VALUE;
4405
 
    else
4406
 
        res = get_cpu_topology_term(c_p, type);
4407
 
    erts_smp_rwmtx_runlock(&erts_cpu_bind_rwmtx);
4408
 
    return res;
4409
 
}
4410
 
 
4411
 
static void
4412
 
early_cpu_bind_init(void)
4413
 
{
4414
 
    user_cpudata = NULL;
4415
 
    user_cpudata_size = 0;
4416
 
 
4417
 
    system_cpudata_size = erts_get_cpu_topology_size(erts_cpuinfo);
4418
 
    system_cpudata = erts_alloc(ERTS_ALC_T_CPUDATA,
4419
 
                                (sizeof(erts_cpu_topology_t)
4420
 
                                 * system_cpudata_size));
4421
 
 
4422
 
    cpu_bind_order = ERTS_CPU_BIND_NONE;
4423
 
 
4424
 
    if (!erts_get_cpu_topology(erts_cpuinfo, system_cpudata)
4425
 
        || ERTS_INIT_CPU_TOPOLOGY_OK != verify_topology(system_cpudata,
4426
 
                                                        system_cpudata_size)) {
4427
 
        erts_free(ERTS_ALC_T_CPUDATA, system_cpudata);
4428
 
        system_cpudata = NULL;
4429
 
        system_cpudata_size = 0;
4430
 
    }
4431
 
}
4432
 
 
4433
 
static void
4434
 
late_cpu_bind_init(void)
4435
 
{
4436
 
    int ix;
4437
 
 
4438
 
    erts_smp_rwmtx_init(&erts_cpu_bind_rwmtx, "cpu_bind");
4439
 
 
4440
 
    scheduler2cpu_map = erts_alloc(ERTS_ALC_T_CPUDATA,
4441
 
                                   (sizeof(ErtsCpuBindData)
4442
 
                                    * (erts_no_schedulers+1)));
4443
 
    for (ix = 1; ix <= erts_no_schedulers; ix++) {
4444
 
        scheduler2cpu_map[ix].bind_id = -1;
4445
 
        scheduler2cpu_map[ix].bound_id = -1;
4446
 
    }
4447
 
 
4448
 
    if (cpu_bind_order != ERTS_CPU_BIND_NONE) {
4449
 
        erts_cpu_topology_t *cpudata;
4450
 
        int cpudata_size;
4451
 
        create_tmp_cpu_topology_copy(&cpudata, &cpudata_size);
4452
 
        ASSERT(cpudata);
4453
 
        signal_schedulers_bind_change(cpudata, cpudata_size);
4454
 
        destroy_tmp_cpu_topology_copy(cpudata);
4455
 
    }
4456
 
}
4457
 
 
4458
3788
#ifdef ERTS_SMP
4459
3789
 
4460
3790
static void
4469
3799
                                         sizeof(ErtsPendingSuspend));
4470
3800
    psp->next = NULL;
4471
3801
#ifdef DEBUG
4472
 
#ifdef ARCH_64
 
3802
#if defined(ARCH_64) && !HALFWORD_HEAP
4473
3803
    psp->end = (ErtsPendingSuspend *) 0xdeaddeaddeaddead;
4474
3804
#else
4475
3805
    psp->end = (ErtsPendingSuspend *) 0xdeaddead;
5310
4640
}
5311
4641
 
5312
4642
/* schedule a process */
5313
 
static ERTS_INLINE void
 
4643
static ERTS_INLINE ErtsRunQueue *
5314
4644
internal_add_to_runq(ErtsRunQueue *runq, Process *p)
5315
4645
{
5316
4646
    Uint32 prev_status = p->status;
5321
4651
    ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq));
5322
4652
 
5323
4653
    if (p->status_flags & ERTS_PROC_SFLG_INRUNQ)
5324
 
        return;
 
4654
        return NULL;
5325
4655
    else if (p->runq_flags & ERTS_PROC_RUNQ_FLG_RUNNING) {
5326
4656
        ASSERT(p->status != P_SUSPENDED);
5327
4657
        ERTS_DBG_CHK_PROCS_RUNQ_NOPROC(runq, p);
5328
4658
        p->status_flags |= ERTS_PROC_SFLG_PENDADD2SCHEDQ;
5329
 
        return;
 
4659
        return NULL;
5330
4660
    }
5331
4661
    ASSERT(!p->scheduler_data);
5332
4662
#endif
5365
4695
        profile_runnable_proc(p, am_active);
5366
4696
    }
5367
4697
 
5368
 
    smp_notify_inc_runq(add_runq);
5369
 
 
5370
4698
    if (add_runq != runq)
5371
4699
        erts_smp_runq_unlock(add_runq);
 
4700
 
 
4701
    return add_runq;
5372
4702
}
5373
4703
 
5374
4704
 
5375
4705
void
5376
4706
erts_add_to_runq(Process *p)
5377
4707
{
 
4708
    ErtsRunQueue *notify_runq;
5378
4709
    ErtsRunQueue *runq = erts_get_runq_proc(p);
5379
4710
    erts_smp_runq_lock(runq);
5380
 
    internal_add_to_runq(runq, p);
 
4711
    notify_runq = internal_add_to_runq(runq, p);
5381
4712
    erts_smp_runq_unlock(runq);
 
4713
    smp_notify_inc_runq(notify_runq);
 
4714
 
5382
4715
}
5383
4716
 
5384
4717
/* Possibly remove a scheduled process we need to suspend */
5713
5046
    return old_value;
5714
5047
}
5715
5048
 
5716
 
#ifdef ERTS_SMP
5717
 
 
5718
 
static ERTS_INLINE int
5719
 
prepare_for_sys_schedule(void)
5720
 
{
5721
 
    while (!erts_port_task_have_outstanding_io_tasks()
5722
 
           && !erts_smp_atomic_xchg(&doing_sys_schedule, 1)) {
5723
 
        if (!erts_port_task_have_outstanding_io_tasks())
5724
 
            return 1;
5725
 
        erts_smp_atomic_set(&doing_sys_schedule, 0);
5726
 
    }
5727
 
    return 0;
5728
 
}
5729
 
 
5730
 
#else
5731
 
 
5732
 
static ERTS_INLINE int
5733
 
prepare_for_sys_schedule(void)
5734
 
{
5735
 
    return !erts_port_task_have_outstanding_io_tasks();
5736
 
}
5737
 
 
5738
 
#endif
5739
 
 
5740
5049
/* note that P_RUNNING is only set so that we don't try to remove
5741
5050
** running processes from the schedule queue if they exit - a running
5742
5051
** process not being in the schedule queue!! 
5766
5075
{
5767
5076
    ErtsRunQueue *rq;
5768
5077
    ErtsRunPrioQueue *rpq;
5769
 
    long dt;
 
5078
    erts_aint_t dt;
5770
5079
    ErtsSchedulerData *esdp;
5771
5080
    int context_reds;
5772
 
    long fcalls;
 
5081
    int fcalls;
5773
5082
    int input_reductions;
5774
5083
    int actual_reds;
5775
5084
    int reds;
5792
5101
        esdp = erts_get_scheduler_data();
5793
5102
        rq = erts_get_runq_current(esdp);
5794
5103
        ASSERT(esdp);
5795
 
        fcalls = erts_smp_atomic_read(&function_calls);
 
5104
        fcalls = (int) erts_smp_atomic32_read(&function_calls);
5796
5105
        actual_reds = reds = 0;
5797
5106
        erts_smp_runq_lock(rq);
5798
5107
    } else {
5810
5119
            reds = ERTS_PROC_MIN_CONTEXT_SWITCH_REDS_COST;
5811
5120
        esdp->virtual_reds = 0;
5812
5121
 
5813
 
        fcalls = erts_smp_atomic_addtest(&function_calls, reds);
 
5122
        fcalls = (int) erts_smp_atomic32_addtest(&function_calls, reds);
5814
5123
        ASSERT(esdp && esdp == erts_get_scheduler_data());
5815
5124
 
5816
5125
        rq = erts_get_runq_current(esdp);
5825
5134
        }
5826
5135
 
5827
5136
        if (IS_TRACED(p)) {
 
5137
            if (IS_TRACED_FL(p, F_TRACE_CALLS) &&  p->status != P_FREE) {
 
5138
                erts_schedule_time_break(p, ERTS_BP_CALL_TIME_SCHEDULE_OUT);
 
5139
            }
5828
5140
            switch (p->status) {
5829
5141
            case P_EXITING:
5830
5142
                if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_EXIT))
5868
5180
        p->status_flags &= ~ERTS_PROC_SFLG_RUNNING;
5869
5181
 
5870
5182
        if (p->status_flags & ERTS_PROC_SFLG_PENDADD2SCHEDQ) {
 
5183
            ErtsRunQueue *notify_runq;
5871
5184
            p->status_flags &= ~ERTS_PROC_SFLG_PENDADD2SCHEDQ;
5872
 
            internal_add_to_runq(rq, p);
 
5185
            notify_runq = internal_add_to_runq(rq, p);
 
5186
            if (notify_runq != rq)
 
5187
                smp_notify_inc_runq(notify_runq);
5873
5188
        }
5874
5189
#endif
5875
5190
 
5905
5220
 
5906
5221
        ERTS_SMP_CHK_NO_PROC_LOCKS;
5907
5222
 
5908
 
        dt = do_time_read_and_reset();
 
5223
        dt = erts_do_time_read_and_reset();
5909
5224
        if (dt) {
5910
5225
            erts_smp_runq_unlock(rq);
5911
 
            bump_timer(dt);
 
5226
            erts_bump_timer(dt);
5912
5227
            erts_smp_runq_lock(rq);
5913
5228
        }
5914
5229
        BM_STOP_TIMER(system);
5937
5252
                         | ERTS_RUNQ_FLG_CHK_CPU_BIND
5938
5253
                         | ERTS_RUNQ_FLG_SUSPENDED)) {
5939
5254
            if ((rq->flags & ERTS_RUNQ_FLG_SUSPENDED)
5940
 
                || erts_smp_atomic_read(&esdp->suspended)) {
 
5255
                || (erts_smp_atomic32_read(&esdp->ssi->flags)
 
5256
                    & ERTS_SSI_FLG_SUSPENDED)) {
 
5257
                ASSERT(erts_smp_atomic32_read(&esdp->ssi->flags)
 
5258
                       & ERTS_SSI_FLG_SUSPENDED);
5941
5259
                suspend_scheduler(esdp);
5942
5260
            }
5943
5261
            if ((rq->flags & ERTS_RUNQ_FLG_CHK_CPU_BIND)
5944
 
                || erts_smp_atomic_read(&esdp->chk_cpu_bind)) {
5945
 
                check_cpu_bind(esdp);
 
5262
                || erts_smp_atomic32_read(&esdp->chk_cpu_bind)) {
 
5263
                erts_sched_check_cpu_bind(esdp);
5946
5264
            }
5947
5265
        }
5948
5266
 
5949
 
#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
5950
 
        if (esdp->check_children) {
5951
 
            esdp->check_children = 0;
5952
 
            erts_smp_runq_unlock(rq);
5953
 
            erts_check_children();
5954
 
            erts_smp_runq_lock(rq);
 
5267
#if defined(ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK) \
 
5268
        || defined(ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK)
 
5269
        {
 
5270
            ErtsSchedulerSleepInfo *ssi = esdp->ssi;
 
5271
            erts_aint32_t aux_work = erts_smp_atomic32_read(&ssi->aux_work);
 
5272
            if (aux_work) {
 
5273
                erts_smp_runq_unlock(rq);
 
5274
#ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
 
5275
                aux_work = blockable_aux_work(esdp, ssi, aux_work);
 
5276
#endif
 
5277
#ifdef ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK
 
5278
                nonblockable_aux_work(esdp, ssi, aux_work);
 
5279
#endif
 
5280
                erts_smp_runq_lock(rq);
 
5281
            }
5955
5282
        }
5956
5283
#endif
5957
5284
 
5983
5310
            if (rq->flags & (ERTS_RUNQ_FLG_SHARED_RUNQ
5984
5311
                             | ERTS_RUNQ_FLG_SUSPENDED)) {
5985
5312
                if ((rq->flags & ERTS_RUNQ_FLG_SUSPENDED)
5986
 
                    || erts_smp_atomic_read(&esdp->suspended)) {
 
5313
                    || (erts_smp_atomic32_read(&esdp->ssi->flags)
 
5314
                        & ERTS_SSI_FLG_SUSPENDED)) {
 
5315
                    ASSERT(erts_smp_atomic32_read(&esdp->ssi->flags)
 
5316
                           & ERTS_SSI_FLG_SUSPENDED);
5987
5317
                    non_empty_runq(rq);
5988
5318
                    goto continue_check_activities_to_run;
5989
5319
                }
6000
5330
                }
6001
5331
            }
6002
5332
 
6003
 
            if (prepare_for_sys_schedule()) {
6004
 
                erts_smp_atomic_set(&function_calls, 0);
6005
 
                fcalls = 0;
6006
 
                sched_sys_wait(esdp->no, rq);
6007
 
                erts_smp_atomic_set(&doing_sys_schedule, 0);
6008
 
            }
6009
 
            else {
6010
 
                /* If all schedulers are waiting, one of them *should*
6011
 
                   be waiting in erl_sys_schedule() */
6012
 
                sched_cnd_wait(esdp->no, rq);
6013
 
            }
 
5333
            scheduler_wait(&fcalls, esdp, rq);
6014
5334
 
6015
5335
            non_empty_runq(rq);
6016
5336
 
6034
5354
             * Schedule system-level activities.
6035
5355
             */
6036
5356
 
6037
 
            erts_smp_atomic_set(&function_calls, 0);
 
5357
            erts_smp_atomic32_set(&function_calls, 0);
6038
5358
            fcalls = 0;
 
5359
 
6039
5360
            ASSERT(!erts_port_task_have_outstanding_io_tasks());
 
5361
 
6040
5362
#ifdef ERTS_SMP
6041
5363
            /* erts_sys_schedule_interrupt(0); */
6042
5364
#endif
6043
5365
            erts_smp_runq_unlock(rq);
6044
5366
            erl_sys_schedule(runnable);
6045
 
            dt = do_time_read_and_reset();
6046
 
            if (dt) bump_timer(dt);
 
5367
            dt = erts_do_time_read_and_reset();
 
5368
            if (dt) erts_bump_timer(dt);
6047
5369
#ifdef ERTS_SMP
6048
5370
            erts_smp_runq_lock(rq);
6049
 
            erts_smp_atomic_set(&doing_sys_schedule, 0);
 
5371
            clear_sys_scheduling();
6050
5372
            goto continue_check_activities_to_run;
6051
5373
#else
6052
5374
            if (!runnable)
6067
5389
                    if (rq->wakeup_other < 0)
6068
5390
                        rq->wakeup_other = 0;
6069
5391
                }
6070
 
                else if (rq->wakeup_other < ERTS_WAKEUP_OTHER_LIMIT)
 
5392
                else if (rq->wakeup_other < wakeup_other_limit)
6071
5393
                    rq->wakeup_other += rq->len*wo_reds + ERTS_WAKEUP_OTHER_FIXED_INC;
6072
5394
                else {
6073
5395
                    if (erts_common_run_queue) {
6074
5396
                        if (erts_common_run_queue->waiting)
6075
 
                            wake_one_scheduler();
 
5397
                            wake_scheduler(erts_common_run_queue, 0, 1);
6076
5398
                    }
6077
 
                    else if (erts_smp_atomic_read(&no_empty_run_queues) != 0) {
 
5399
                    else if (erts_smp_atomic32_read(&no_empty_run_queues) != 0) {
6078
5400
                        wake_scheduler_on_empty_runq(rq);
6079
5401
                        rq->wakeup_other = 0;
6080
5402
                    }
6217
5539
        erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS);
6218
5540
 
6219
5541
        if (erts_sched_stat.enabled) {
6220
 
            Uint old = ERTS_PROC_SCHED_ID(p,
 
5542
            UWord old = ERTS_PROC_SCHED_ID(p,
6221
5543
                                          (ERTS_PROC_LOCK_MAIN
6222
5544
                                           | ERTS_PROC_LOCK_STATUS),
6223
 
                                          esdp->no);
 
5545
                                          (UWord) esdp->no);
6224
5546
            int migrated = old && old != esdp->no;
6225
5547
 
6226
5548
            erts_smp_spin_lock(&erts_sched_stat.lock);
6261
5583
                    trace_virtual_sched(p, am_in);
6262
5584
                break;
6263
5585
            }
 
5586
            if (IS_TRACED_FL(p, F_TRACE_CALLS)) {
 
5587
                erts_schedule_time_break(p, ERTS_BP_CALL_TIME_SCHEDULE_IN);
 
5588
            }
6264
5589
        }
 
5590
 
6265
5591
        if (p->status != P_EXITING)
6266
5592
            p->status = P_RUNNING;
6267
5593
 
6272
5598
            erts_check_my_tracer_proc(p);
6273
5599
#endif
6274
5600
 
6275
 
        if ((FLAGS(p) & F_FORCE_GC) || (MSO(p).overhead >= BIN_VHEAP_SZ(p))) {
 
5601
        if (!ERTS_PROC_IS_EXITING(p)
 
5602
            && ((FLAGS(p) & F_FORCE_GC)
 
5603
                || (MSO(p).overhead > BIN_VHEAP_SZ(p)))) {
6276
5604
            reds -= erts_garbage_collect(p, 0, p->arg_reg, p->arity);
6277
5605
            if (reds < 0) {
6278
5606
                reds = 1;
6362
5690
    ErtsRunQueue *rq = erts_get_runq_current(NULL);
6363
5691
    ErtsMiscOpList *molp = misc_op_list_alloc();
6364
5692
 
 
5693
    if (!rq) {
 
5694
        /*
 
5695
         * This can only happen when the sys msg dispatcher
 
5696
         * thread schedules misc ops (this happens *very*
 
5697
         * seldom; only when trace drivers are unloaded).
 
5698
         */
 
5699
        rq =  ERTS_RUNQ_IX(0);
 
5700
    }
 
5701
 
6365
5702
    erts_smp_runq_lock(rq);
6366
5703
 
6367
5704
    while (rq->misc.evac_runq) {
6381
5718
    else
6382
5719
        rq->misc.start = molp;
6383
5720
    rq->misc.end = molp;
 
5721
    erts_smp_runq_unlock(rq);
6384
5722
    smp_notify_inc_runq(rq);
6385
 
    erts_smp_runq_unlock(rq);
6386
5723
}
6387
5724
 
6388
5725
static void
6516
5853
 
6517
5854
Uint erts_process_count(void)
6518
5855
{
6519
 
    long res = erts_smp_atomic_read(&process_count);
 
5856
    erts_aint32_t res = erts_smp_atomic32_read(&process_count);
6520
5857
    ASSERT(res >= 0);
6521
5858
    return (Uint) res;
6522
5859
}
6565
5902
    ASSERT(!process_tab[p_next]);
6566
5903
 
6567
5904
    process_tab[p_next] = p;
6568
 
    erts_smp_atomic_inc(&process_count);
 
5905
    erts_smp_atomic32_inc(&process_count);
6569
5906
    p->id = make_internal_pid(p_serial << p_serial_shift | p_next);
6570
5907
    if (p->id == ERTS_INVALID_PID) {
6571
5908
        /* Do not use the invalid pid; change serial */
6624
5961
                   Eterm args,  /* Arguments for function (must be well-formed list). */
6625
5962
                   ErlSpawnOpts* so) /* Options for spawn. */
6626
5963
{
6627
 
    ErtsRunQueue *rq;
 
5964
    ErtsRunQueue *rq, *notify_runq;
6628
5965
    Process *p;
6629
5966
    Sint arity;                 /* Number of arguments. */
6630
5967
#ifndef HYBRID
6683
6020
     * noone except us has access to the process.
6684
6021
     */
6685
6022
    if (so->flags & SPO_USE_ARGS) {
6686
 
        p->min_heap_size = so->min_heap_size;
6687
 
        p->prio = so->priority;
6688
 
        p->max_gen_gcs = so->max_gen_gcs;
 
6023
        p->min_heap_size  = so->min_heap_size;
 
6024
        p->min_vheap_size = so->min_vheap_size;
 
6025
        p->prio           = so->priority;
 
6026
        p->max_gen_gcs    = so->max_gen_gcs;
6689
6027
    } else {
6690
 
        p->min_heap_size = H_MIN_SIZE;
6691
 
        p->prio = PRIORITY_NORMAL;
6692
 
        p->max_gen_gcs = (Uint16) erts_smp_atomic_read(&erts_max_gen_gcs);
 
6028
        p->min_heap_size  = H_MIN_SIZE;
 
6029
        p->min_vheap_size = BIN_VH_MIN_SIZE;
 
6030
        p->prio           = PRIORITY_NORMAL;
 
6031
        p->max_gen_gcs    = (Uint16) erts_smp_atomic32_read(&erts_max_gen_gcs);
6693
6032
    }
6694
6033
    p->skipped = 0;
6695
6034
    ASSERT(p->min_heap_size == erts_next_heap_size(p->min_heap_size, 0));
6701
6040
    /*
6702
6041
     * Must initialize binary lists here before copying binaries to process.
6703
6042
     */
6704
 
    p->off_heap.mso = NULL;
6705
 
#ifndef HYBRID /* FIND ME! */
6706
 
    p->off_heap.funs = NULL;
6707
 
#endif
6708
 
    p->off_heap.externals = NULL;
 
6043
    p->off_heap.first = NULL;
6709
6044
    p->off_heap.overhead = 0;
6710
6045
 
6711
6046
    heap_need +=
6736
6071
    p->heap_sz = sz;
6737
6072
    p->catches = 0;
6738
6073
 
6739
 
    p->bin_vheap_sz = H_MIN_SIZE;
6740
 
    p->bin_old_vheap_sz = H_MIN_SIZE;
6741
 
    p->bin_old_vheap = 0;
 
6074
    p->bin_vheap_sz     = p->min_vheap_size;
 
6075
    p->bin_old_vheap_sz = p->min_vheap_size;
 
6076
    p->bin_old_vheap    = 0;
 
6077
    p->bin_vheap_mature = 0;
6742
6078
 
6743
6079
    /* No need to initialize p->fcalls. */
6744
6080
 
6745
6081
    p->current = p->initial+INITIAL_MOD;
6746
6082
 
6747
 
    p->i = (Eterm *) beam_apply;
6748
 
    p->cp = (Eterm *) beam_apply+1;
 
6083
    p->i = (BeamInstr *) beam_apply;
 
6084
    p->cp = (BeamInstr *) beam_apply+1;
6749
6085
 
6750
6086
    p->arg_reg = p->def_arg_reg;
6751
6087
    p->max_arg_reg = sizeof(p->def_arg_reg)/sizeof(p->def_arg_reg[0]);
6795
6131
        p->group_leader =
6796
6132
            IS_CONST(parent->group_leader)
6797
6133
            ? parent->group_leader
6798
 
            : STORE_NC(&p->htop, &p->off_heap.externals, parent->group_leader);
 
6134
            : STORE_NC(&p->htop, &p->off_heap, parent->group_leader);
6799
6135
    }
6800
6136
 
6801
6137
    erts_get_default_tracing(&p->trace_flags, &p->tracer_proc);
6939
6275
#endif
6940
6276
 
6941
6277
    p->status = P_WAITING;
6942
 
    internal_add_to_runq(rq, p);
 
6278
    notify_runq = internal_add_to_runq(rq, p);
6943
6279
 
6944
6280
    erts_smp_runq_unlock(rq);
6945
6281
 
 
6282
    smp_notify_inc_runq(notify_runq);
 
6283
 
6946
6284
    res = p->id;
6947
6285
    erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL);
6948
6286
 
6969
6307
    p->gen_gcs = 0;
6970
6308
    p->max_gen_gcs = 0;
6971
6309
    p->min_heap_size = 0;
 
6310
    p->min_vheap_size = 0;
6972
6311
    p->status = P_RUNABLE;
6973
6312
    p->gcstatus = P_RUNABLE;
6974
6313
    p->rstatus = P_RUNABLE;
6985
6324
    p->ftrace = NIL;
6986
6325
    p->fcalls = 0;
6987
6326
 
6988
 
    p->bin_vheap_sz=H_MIN_SIZE;
6989
 
    p->bin_old_vheap_sz=H_MIN_SIZE;
 
6327
    p->bin_vheap_sz = BIN_VH_MIN_SIZE;
 
6328
    p->bin_old_vheap_sz = BIN_VH_MIN_SIZE;
6990
6329
    p->bin_old_vheap = 0;
 
6330
    p->bin_vheap_mature = 0;
6991
6331
#ifdef ERTS_SMP
6992
6332
    p->u.ptimer = NULL;
6993
6333
    p->bound_runq = NULL;
6995
6335
    memset(&(p->u.tm), 0, sizeof(ErlTimer));
6996
6336
#endif
6997
6337
    p->next = NULL;
6998
 
    p->off_heap.mso = NULL;
6999
 
#ifndef HYBRID /* FIND ME! */
7000
 
    p->off_heap.funs = NULL;
7001
 
#endif
7002
 
    p->off_heap.externals = NULL;
 
6338
    p->off_heap.first = NULL;
7003
6339
    p->off_heap.overhead = 0;
7004
6340
    p->reg = NULL;
7005
6341
    p->heap_sz = 0;
7146
6482
 
7147
6483
    /* Thing that erts_cleanup_empty_process() cleans up */
7148
6484
 
7149
 
    ASSERT(p->off_heap.mso == NULL);
7150
 
#ifndef HYBRID /* FIND ME! */
7151
 
    ASSERT(p->off_heap.funs == NULL);
7152
 
#endif
7153
 
    ASSERT(p->off_heap.externals == NULL);
 
6485
    ASSERT(p->off_heap.first == NULL);
7154
6486
    ASSERT(p->off_heap.overhead == 0);
7155
6487
 
7156
6488
    ASSERT(p->mbuf == NULL);
7161
6493
void
7162
6494
erts_cleanup_empty_process(Process* p)
7163
6495
{
7164
 
    ErlHeapFragment* mbufp;
7165
 
 
7166
6496
    /* We only check fields that are known to be used... */
7167
6497
 
7168
6498
    erts_cleanup_offheap(&p->off_heap);
7169
 
    p->off_heap.mso = NULL;
7170
 
#ifndef HYBRID /* FIND ME! */
7171
 
    p->off_heap.funs = NULL;
7172
 
#endif
7173
 
    p->off_heap.externals = NULL;
 
6499
    p->off_heap.first = NULL;
7174
6500
    p->off_heap.overhead = 0;
7175
6501
 
7176
 
    mbufp = p->mbuf;
7177
 
    while (mbufp) {
7178
 
        ErlHeapFragment *next = mbufp->next;
7179
 
        free_message_buffer(mbufp);
7180
 
        mbufp = next;
 
6502
    if (p->mbuf != NULL) {
 
6503
        free_message_buffer(p->mbuf);
 
6504
        p->mbuf = NULL;
7181
6505
    }
7182
 
    p->mbuf = NULL;
7183
6506
#if defined(ERTS_ENABLE_LOCK_COUNT) && defined(ERTS_SMP)
7184
6507
    erts_lcnt_proc_lock_destroy(p);
7185
6508
#endif
7195
6518
delete_process(Process* p)
7196
6519
{
7197
6520
    ErlMessage* mp;
7198
 
    ErlHeapFragment* bp;
7199
6521
 
7200
6522
    VERBOSE(DEBUG_PROCESSES, ("Removing process: %T\n",p->id));
7201
6523
 
7211
6533
     * The mso list should not be used anymore, but if it is, make sure that
7212
6534
     * we'll notice.
7213
6535
     */
7214
 
    p->off_heap.mso = (void *) 0x8DEFFACD;
 
6536
    p->off_heap.first = (void *) 0x8DEFFACD;
7215
6537
 
7216
6538
    if (p->arg_reg != p->def_arg_reg) {
7217
6539
        erts_free(ERTS_ALC_T_ARG_REG, p->arg_reg);
7245
6567
    /*
7246
6568
     * Free all pending message buffers.
7247
6569
     */
7248
 
    bp = p->mbuf;
7249
 
    while (bp != NULL) {
7250
 
        ErlHeapFragment* next_bp = bp->next;
7251
 
        free_message_buffer(bp);
7252
 
        bp = next_bp;
 
6570
    if (p->mbuf != NULL) {      
 
6571
        free_message_buffer(p->mbuf);
7253
6572
    }
7254
6573
 
7255
6574
    erts_erase_dicts(p);
7329
6648
    p->freason = EXTAG_EXIT;
7330
6649
    KILL_CATCHES(p);
7331
6650
    cancel_timer(p);
7332
 
    p->i = (Eterm *) beam_exit;
 
6651
    p->i = (BeamInstr *) beam_exit;
7333
6652
}
7334
6653
 
7335
6654
 
7759
7078
            erts_port_release(prt); 
7760
7079
        } else if (is_internal_pid(mon->pid)) {/* local by name or pid */
7761
7080
            Eterm watched;
7762
 
            Eterm lhp[3];
 
7081
            DeclareTmpHeapNoproc(lhp,3);
7763
7082
            ErtsProcLocks rp_locks = (ERTS_PROC_LOCK_LINK
7764
7083
                                      | ERTS_PROC_LOCKS_MSG_SEND);
7765
7084
            rp = erts_pid2proc(NULL, 0, mon->pid, rp_locks);
7766
7085
            if (rp == NULL) {
7767
7086
                goto done;
7768
7087
            }
 
7088
            UseTmpHeapNoproc(3);
7769
7089
            rmon = erts_remove_monitor(&(rp->monitors),mon->ref);
7770
7090
            if (rmon) {
7771
7091
                erts_destroy_monitor(rmon);
7776
7096
                erts_queue_monitor_message(rp, &rp_locks, mon->ref, am_process, 
7777
7097
                                           watched, pcontext->reason);
7778
7098
            }
 
7099
            UnUseTmpHeapNoproc(3);
7779
7100
            /* else: demonitor while we exited, i.e. do nothing... */
7780
7101
            erts_smp_proc_unlock(rp, rp_locks);
7781
7102
        } else { /* external by pid or name */
8006
7327
    ERTS_SMP_MSGQ_MV_INQ2PRIVQ(p);
8007
7328
#endif
8008
7329
 
8009
 
    if (IS_TRACED_FL(p,F_TRACE_PROCS))
8010
 
        trace_proc(p, p, am_exit, reason);
 
7330
    if (IS_TRACED(p)) {
 
7331
        if (IS_TRACED_FL(p, F_TRACE_CALLS))
 
7332
            erts_schedule_time_break(p, ERTS_BP_CALL_TIME_SCHEDULE_EXITING);
 
7333
 
 
7334
        if (IS_TRACED_FL(p,F_TRACE_PROCS))
 
7335
            trace_proc(p, p, am_exit, reason);
 
7336
    }
8011
7337
 
8012
7338
    erts_trace_check_exiting(p->id);
8013
7339
 
8024
7350
    if (p->bif_timers)
8025
7351
        erts_cancel_bif_timers(p, ERTS_PROC_LOCKS_ALL);
8026
7352
 
8027
 
#ifdef ERTS_SMP
8028
 
    if (p->flags & F_HAVE_BLCKD_MSCHED)
8029
 
        erts_block_multi_scheduling(p, ERTS_PROC_LOCKS_ALL, 0, 1);
8030
 
#endif
8031
 
 
8032
7353
    erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL_MINOR);
8033
7354
 
8034
7355
#ifdef ERTS_SMP
8061
7382
    Eterm reason = p->fvalue;
8062
7383
    DistEntry *dep;
8063
7384
    struct saved_calls *scb;
 
7385
    process_breakpoint_time_t *pbt;
 
7386
 
8064
7387
#ifdef DEBUG
8065
7388
    int yield_allowed = 1;
8066
7389
#endif
8073
7396
    erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
8074
7397
#endif
8075
7398
 
 
7399
#ifdef ERTS_SMP
 
7400
    if (p->flags & F_HAVE_BLCKD_MSCHED) {
 
7401
        ErtsSchedSuspendResult ssr;
 
7402
        ssr = erts_block_multi_scheduling(p, ERTS_PROC_LOCK_MAIN, 0, 1);
 
7403
        switch (ssr) {
 
7404
        case ERTS_SCHDLR_SSPND_YIELD_RESTART:
 
7405
            goto yield;
 
7406
        case ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED:
 
7407
        case ERTS_SCHDLR_SSPND_YIELD_DONE_MSCHED_BLOCKED:
 
7408
        case ERTS_SCHDLR_SSPND_DONE:
 
7409
        case ERTS_SCHDLR_SSPND_YIELD_DONE:
 
7410
            p->flags &= ~F_HAVE_BLCKD_MSCHED;
 
7411
            break;
 
7412
        case ERTS_SCHDLR_SSPND_EINVAL:
 
7413
        default:
 
7414
            erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error: %d\n",
 
7415
                     __FILE__, __LINE__, (int) ssr);
 
7416
        }
 
7417
    }
 
7418
#endif
 
7419
 
8076
7420
    if (p->flags & F_USING_DB) {
8077
7421
        if (erts_db_process_exiting(p, ERTS_PROC_LOCK_MAIN))
8078
7422
            goto yield;
8141
7485
        p->status_flags = 0;
8142
7486
#endif
8143
7487
        process_tab[pix] = NULL; /* Time of death! */
8144
 
        ASSERT(erts_smp_atomic_read(&process_count) > 0);
8145
 
        erts_smp_atomic_dec(&process_count);
 
7488
        ASSERT(erts_smp_atomic32_read(&process_count) > 0);
 
7489
        erts_smp_atomic32_dec(&process_count);
8146
7490
 
8147
7491
#ifdef ERTS_SMP
8148
7492
        erts_pix_unlock(pix_lock);
8179
7523
           ? ERTS_PROC_SET_DIST_ENTRY(p, ERTS_PROC_LOCKS_ALL, NULL)
8180
7524
           : NULL);
8181
7525
    scb = ERTS_PROC_SET_SAVED_CALLS_BUF(p, ERTS_PROC_LOCKS_ALL, NULL);
 
7526
    pbt = ERTS_PROC_SET_CALL_TIME(p, ERTS_PROC_LOCKS_ALL, NULL);
8182
7527
 
8183
7528
    erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL);
8184
7529
    processes_busy--;
8193
7538
     * Pre-build the EXIT tuple if there are any links.
8194
7539
     */
8195
7540
    if (lnk) {
8196
 
        Eterm tmp_heap[4];
 
7541
        DeclareTmpHeap(tmp_heap,4,p);
8197
7542
        Eterm exit_tuple;
8198
7543
        Uint exit_tuple_sz;
8199
7544
        Eterm* hp;
8200
7545
 
 
7546
        UseTmpHeap(4,p);
8201
7547
        hp = &tmp_heap[0];
8202
7548
 
8203
7549
        exit_tuple = TUPLE3(hp, am_EXIT, p->id, reason);
8208
7554
            ExitLinkContext context = {p, reason, exit_tuple, exit_tuple_sz};
8209
7555
            erts_sweep_links(lnk, &doit_exit_link, &context);
8210
7556
        }
 
7557
        UnUseTmpHeap(4,p);
8211
7558
    }
8212
7559
 
8213
7560
    {
8214
7561
        ExitMonitorContext context = {reason, p};
8215
 
        erts_sweep_monitors(mon,&doit_exit_monitor,&context);
 
7562
        erts_sweep_monitors(mon,&doit_exit_monitor,&context); /* Allocates TmpHeap, but we
 
7563
                                                                 have none here */
8216
7564
    }
8217
7565
 
8218
7566
    if (scb)
8219
7567
        erts_free(ERTS_ALC_T_CALLS_BUF, (void *) scb);
8220
7568
 
 
7569
    if (pbt)
 
7570
        erts_free(ERTS_ALC_T_BPD, (void *) pbt);
 
7571
 
8221
7572
    delete_process(p);
8222
7573
 
8223
7574
    erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
8236
7587
 
8237
7588
    ASSERT(p->status == P_EXITING);
8238
7589
 
8239
 
    p->i = (Eterm *) beam_continue_exit;
 
7590
    p->i = (BeamInstr *) beam_continue_exit;
8240
7591
 
8241
7592
    if (!(curr_locks & ERTS_PROC_LOCK_STATUS)) {
8242
7593
        erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS);
8256
7607
static void
8257
7608
timeout_proc(Process* p)
8258
7609
{
8259
 
    p->i = (Eterm *) p->def_arg_reg[0];
 
7610
    p->i = *((BeamInstr **) (UWord) p->def_arg_reg);
8260
7611
    p->flags |= F_TIMO;
8261
7612
    p->flags &= ~F_INSLPQUEUE;
8262
7613
 
8275
7626
#ifdef ERTS_SMP
8276
7627
    erts_cancel_smp_ptimer(p->u.ptimer);
8277
7628
#else
8278
 
    erl_cancel_timer(&p->u.tm);
 
7629
    erts_cancel_timer(&p->u.tm);
8279
7630
#endif
8280
7631
}
8281
7632
 
8301
7652
                           (ErlTimeoutProc) timeout_proc,
8302
7653
                           timeout);
8303
7654
#else
8304
 
    erl_set_timer(&p->u.tm,
 
7655
    erts_set_timer(&p->u.tm,
8305
7656
                  (ErlTimeoutProc) timeout_proc,
8306
7657
                  NULL,
8307
7658
                  (void*) p,
8355
7706
}
8356
7707
 
8357
7708
static void
8358
 
print_function_from_pc(int to, void *to_arg, Eterm* x)
 
7709
print_function_from_pc(int to, void *to_arg, BeamInstr* x)
8359
7710
{
8360
 
    Eterm* addr = find_function_from_pc(x);
 
7711
    BeamInstr* addr = find_function_from_pc(x);
8361
7712
    if (addr == NULL) {
8362
7713
        if (x == beam_exit) {
8363
7714
            erts_print(to, to_arg, "<terminate process>");
8391
7742
    }
8392
7743
 
8393
7744
    if (is_CP(x)) {
8394
 
        erts_print(to, to_arg, "Return addr %p (", (Eterm *) x);
 
7745
        erts_print(to, to_arg, "Return addr %p (", (Eterm *) EXPAND_POINTER(x));
8395
7746
        print_function_from_pc(to, to_arg, cp_val(x));
8396
7747
        erts_print(to, to_arg, ")\n");
8397
7748
        yreg = 0;
9220
8571
    processes_trap_export.code[0] = am_erlang;
9221
8572
    processes_trap_export.code[1] = am_processes_trap;
9222
8573
    processes_trap_export.code[2] = 2;
9223
 
    processes_trap_export.code[3] = (Eterm) em_apply_bif;
9224
 
    processes_trap_export.code[4] = (Eterm) &processes_trap;
 
8574
    processes_trap_export.code[3] = (BeamInstr) em_apply_bif;
 
8575
    processes_trap_export.code[4] = (BeamInstr) &processes_trap;
9225
8576
 
9226
8577
#if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_TERM_PROC_LIST
9227
8578
    erts_get_emu_time(&debug_tv_start);