~ubuntu-branches/debian/squeeze/erlang/squeeze

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Erlang Packagers, Sergei Golovan
  • Date: 2006-12-03 17:07:44 UTC
  • mfrom: (2.1.11 feisty)
  • Revision ID: james.westby@ubuntu.com-20061203170744-rghjwupacqlzs6kv
Tags: 1:11.b.2-4
[ Sergei Golovan ]
Fixed erlang-base and erlang-base-hipe prerm scripts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
#  include "config.h"
21
21
#endif
22
22
 
 
23
#define ERTS_DO_INCL_GLB_INLINE_FUNC_DEF
 
24
 
23
25
#include "sys.h"
24
26
#include "erl_vm.h"
25
27
#include "global.h"
27
29
#include "big.h"
28
30
#include "bif.h"
29
31
#include "erl_binary.h"
 
32
#include "erl_bits.h"
 
33
#define ERTS_WANT_DB_INTERNAL__
30
34
#include "erl_db.h"
31
35
#include "erl_threads.h"
32
36
#include "register.h"
33
 
#include "erl_vector.h"
34
37
#include "dist.h"
 
38
#include "erl_printf.h"
 
39
#include "erl_threads.h"
 
40
#include "erl_smp.h"
 
41
#include "erl_time.h"
35
42
 
36
43
#undef M_TRIM_THRESHOLD
37
44
#undef M_TOP_PAD
47
54
#define HAVE_MALLOPT 0
48
55
#endif
49
56
 
50
 
/* Forward */
51
 
static int is_printable_string(Eterm);
52
 
 
53
 
static Eterm*
54
 
do_alloc(Process* p, Eterm* last_htop, Uint need)
 
57
Eterm*
 
58
erts_heap_alloc(Process* p, Uint need)
55
59
{
56
60
    ErlHeapFragment* bp;
57
61
    Uint n;
58
 
#ifdef DEBUG
 
62
#if defined(DEBUG) || defined(CHECK_FOR_HOLES)
59
63
    Uint i;
60
64
#endif
61
65
 
 
66
#if defined(HEAP_FRAG_ELIM_TEST)
 
67
    n = need;
 
68
#else
62
69
    /*
63
70
     * Check if there is any space left in the previous heap fragment.
64
71
     */
72
79
    }
73
80
 
74
81
    /*
75
 
     * Allocate a new arith heap.
76
 
     */
77
 
 
78
 
#ifdef SHARED_HEAP
79
 
    n = need;
80
 
#else
81
 
    /*
82
 
     * Find a new suitable size.
83
 
     */
84
 
 
85
 
    n = need;
 
82
     * Allocate a new arith heap; first find a suitable size.
 
83
     */
 
84
 
 
85
    n = need;
 
86
 
86
87
    if (ARITH_AVAIL(p) < 16 || n < 64) {
 
88
#if defined(HYBRID) || defined(CHECK_FOR_HOLES)
 
89
        /*
 
90
         * Fill the rest of the current arith heap.
 
91
         */
 
92
        while(ARITH_AVAIL(p) != 0) {
 
93
            *ARITH_HEAP(p)++ = NIL;
 
94
            ARITH_AVAIL(p)--;
 
95
        }
 
96
#endif
87
97
        ARITH_AVAIL(p) = 0;
88
98
        n = p->min_heap_size/2 + need;
89
99
        if (n > 16*1024 && n > 2*need) {
99
109
    bp = (ErlHeapFragment*)
100
110
        ERTS_HEAP_ALLOC(ERTS_ALC_T_HEAP_FRAG,
101
111
                        sizeof(ErlHeapFragment) + ((n-1)*sizeof(Eterm)));
 
112
 
102
113
#ifdef DEBUG
103
114
    n--;
104
115
#endif
 
116
 
 
117
 
 
118
#ifndef HEAP_FRAG_ELIM_TEST
105
119
    if (ARITH_AVAIL(p) == 0) {
106
120
        ARITH_AVAIL(p) = n - need;
107
121
        ARITH_HEAP(p) = bp->mem + need;
108
122
    }
109
 
#ifdef DEBUG
 
123
#endif
 
124
 
 
125
#if defined(DEBUG)
110
126
    for (i = 0; i <= n; i++) {
111
 
        bp->mem[i] = ARITH_MARKER;
 
127
        bp->mem[i] = ERTS_HOLE_MARKER;
112
128
    }
 
129
#ifndef HEAP_FRAG_ELIM_TEST
113
130
    ARITH_CHECK_ME(p) = ARITH_HEAP(p);
114
131
#endif
 
132
#elif defined(CHECK_FOR_HOLES)
 
133
    for (i = 0; i < n; i++) {
 
134
        bp->mem[i] = ERTS_HOLE_MARKER;
 
135
    }
 
136
#endif
 
137
 
115
138
#ifdef HEAP_FRAG_ELIM_TEST
116
 
    if (ARITH_LOWEST_HTOP(p) == NULL) {
117
 
        if (SAVED_HEAP_TOP(p) != NULL) {
118
 
            last_htop = SAVED_HEAP_TOP(p);
119
 
        }
120
 
        if (last_htop != NULL) {
121
 
            ARITH_LOWEST_HTOP(p) = last_htop;
 
139
    {
 
140
        /*
 
141
         * When we have create a heap fragment, we are no longer allowed
 
142
         * to store anything more on the heap. 
 
143
         */
 
144
        Eterm* htop = HEAP_TOP(p);
 
145
        if (htop < HEAP_LIMIT(p)) {
 
146
            *htop = make_pos_bignum_header(HEAP_LIMIT(p)-htop-1);
 
147
            HEAP_TOP(p) = HEAP_LIMIT(p);
122
148
        }
123
149
    }
124
150
#endif
 
151
 
125
152
    bp->next = MBUF(p);
126
153
    MBUF(p) = bp;
127
154
    bp->size = n;
128
155
    MBUF_SIZE(p) += n;
129
156
    bp->off_heap.mso = NULL;
130
 
#ifndef SHARED_HEAP
 
157
#ifndef HYBRID /* FIND ME! */
131
158
    bp->off_heap.funs = NULL;
132
159
#endif
133
160
    bp->off_heap.externals = NULL;
134
161
    bp->off_heap.overhead = 0;
135
162
 
136
 
#ifdef HEAP_FRAG_ELIM_TEST
137
 
    /*
138
 
     * Unconditionally force a garbage collection.
139
 
     */
140
 
    MSO(p).overhead = HEAP_SIZE(p);
141
 
    BUMP_ALL_REDS(p);
142
 
#else
143
163
    /*
144
164
     * Test if time to do GC; if so bump the reduction count to force
145
165
     * a context switch.
146
166
     */
 
167
#if !defined HEAP_FRAG_ELIM_TEST
147
168
    MSO(p).overhead += (sizeof(ErlHeapFragment)/sizeof(Eterm) - 1); 
148
169
    if (((MBUF_SIZE(p) + MSO(p).overhead)*MBUF_GC_FACTOR) >= HEAP_SIZE(p)) {
149
170
        BUMP_ALL_REDS(p);
152
173
    return bp->mem;
153
174
}
154
175
 
155
 
Eterm*
156
 
erts_arith_alloc(Process* p, Eterm* last_htop, Uint need)
157
 
{
158
 
    return do_alloc(p, last_htop, need);
159
 
}
160
 
 
161
 
Eterm*
162
 
erts_heap_alloc(Process* p, Uint need)
163
 
{
164
 
    Eterm* hp;
165
 
 
166
 
#ifdef HEAP_FRAG_ELIM_TEST
167
 
    if (need <= ARITH_AVAIL(p)) {
168
 
        Eterm* hp = ARITH_HEAP(p);
169
 
 
170
 
        ARITH_HEAP(p) += need;
171
 
        ARITH_AVAIL(p) -= need;
172
 
        return hp;
173
 
    }
174
 
#endif
175
 
 
176
 
#ifdef SHARED_HEAP
177
 
    if (p->htop == NULL) {
178
 
        if (need <= global_hend - global_htop) {
179
 
            hp = global_htop;
180
 
            global_htop += need;
181
 
            return hp;
182
 
        } else if (global_htop != NULL) {
 
176
#if defined(HEAP_FRAG_ELIM_TEST)
 
177
void erts_arith_shrink(Process* p, Eterm* hp)
 
178
{
 
179
#if defined(CHECK_FOR_HOLES)
 
180
    ErlHeapFragment* hf;
 
181
 
 
182
    /*
 
183
     * We must find the heap fragment that hp points into.
 
184
     * If we are unlucky, we might have to search through
 
185
     * a large part of the list. We'll hope that will not
 
186
     * happen to often.
 
187
     */
 
188
    for (hf = MBUF(p); hf != 0; hf = hf->next) {
 
189
        if (hp - hf->mem < (unsigned long)hf->size) {
183
190
            /*
184
 
             * Garbage collect the global heap.
 
191
             * We are not allowed to changed hf->size (because the
 
192
             * size must be correct when deallocating). Therefore,
 
193
             * clear out the uninitialized part of the heap fragment.
185
194
             */
186
 
            Process p;
187
 
 
188
 
            p.htop = global_htop;
189
 
            p.heap = global_heap;
190
 
            p.hend = global_hend;
191
 
            p.heap_sz = global_heap_sz;
192
 
            p.send = NULL;
193
 
            p.stop = NULL;
194
 
            p.fvalue = NIL;
195
 
            p.group_leader = NIL;
196
 
            p.seq_trace_token = NIL;
197
 
            p.dictionary = NULL;
198
 
            p.debug_dictionary = NULL;
199
 
#ifdef HEAP_FRAG_ELIM_TEST
200
 
            p.ssb = NULL;
201
 
#endif
202
 
            p.status = 0;
203
 
            p.flags = 0;
204
 
            p.tracer_proc = NIL;
205
 
            (void) erts_garbage_collect(&p, need, NULL, 0);
206
 
            global_htop = p.htop;
207
 
            global_heap = p.heap;
208
 
            global_hend = p.hend;
209
 
            global_heap_sz = p.heap_sz;
210
 
            hp = global_htop;
211
 
            global_htop += need;
212
 
            return hp;
213
 
        } else {
214
 
            return erts_global_alloc(need);
 
195
            Eterm* to = hf->mem + hf->size;
 
196
            while (hp < to) {
 
197
                *hp++ = NIL;
 
198
            }
 
199
            break;
215
200
        }
216
201
    }
217
202
#endif
218
 
    hp = do_alloc(p, p->htop, need);
219
 
 
220
 
#ifdef HEAP_FRAG_ELIM_TEST
221
 
    if (SAVED_HEAP_TOP(p) == NULL) {
222
 
        SAVED_HEAP_TOP(p) = HEAP_TOP(p);
223
 
        HEAP_TOP(p) = HEAP_LIMIT(p);
224
 
        MSO(p).overhead = HEAP_SIZE(p);
225
 
        HALLOC_MBUF(p) = MBUF(p);
226
 
    }
227
 
    ARITH_AVAIL(p) = 0;
228
 
    ARITH_HEAP(p) = NULL;
229
 
#endif
230
 
    return hp;
231
203
}
232
 
 
233
 
#ifdef SHARED_HEAP
234
 
Eterm*
235
 
erts_global_alloc(Uint need)
 
204
#else
 
205
void erts_arith_shrink(Process* p, Eterm* hp)
236
206
{
237
 
    if (need <= global_hend - global_htop) {
238
 
        Eterm* hp = global_htop;
239
 
        global_htop += need;
240
 
        return hp;
241
 
    } else {
 
207
    ErlHeapFragment* hf;
 
208
 
 
209
#if !defined(HYBRID) && !defined(DEBUG) && !defined(CHECK_FOR_HOLES)
 
210
    if (ARITH_AVAIL(p) == 0) {
242
211
        /*
243
 
         * Either there is no enough room on the global heap, or the heap pointers
244
 
         * are "owned" by the running process.
 
212
         * For a non-hybrid system, there is nothing to gain by
 
213
         * do any work here.
245
214
         */
246
 
        ErlHeapFragment* bp = (ErlHeapFragment*)
247
 
            ERTS_HEAP_ALLOC(ERTS_ALC_T_HEAP_FRAG,
248
 
                            sizeof(ErlHeapFragment) + ((need-1)*sizeof(Eterm)));
249
 
        bp->next = MBUF(dummy);
250
 
        MBUF(dummy) = bp;
251
 
        if (HALLOC_MBUF(dummy) == NULL) {
252
 
            HALLOC_MBUF(dummy) = bp;
253
 
        }
254
 
        bp->size = need;
255
 
        MBUF_SIZE(dummy) += need;
256
 
        bp->off_heap.mso = NULL;
257
 
        bp->off_heap.externals = NULL;
258
 
        bp->off_heap.overhead = 0;
259
 
        MSO(dummy).overhead += (sizeof(ErlHeapFragment)/sizeof(Eterm) - 1); 
260
 
        return bp->mem;
261
 
    }
262
 
}
263
 
#endif
264
 
 
265
 
#if 0 /* XXX Not used! */
266
 
/* Does what arith_alloc does, but only ensures that the space is
267
 
   allocated; doesn't actually start using it. */
268
 
void arith_ensure_alloc(Process* p, Uint need)
269
 
{
270
 
    ErlHeapFragment* bp;
271
 
    Uint n;
272
 
    Eterm* hp;
273
 
#ifdef DEBUG
274
 
    Uint i;
275
 
#endif
276
 
 
277
 
    if (ARITH_AVAIL(p) >= need)
278
215
        return;
279
 
 
280
 
    n = (need < 128) ? 128 : need;
281
 
    bp = new_message_buffer(n+1);
282
 
    bp->next = MBUF(p);
283
 
    MBUF(p) = bp;
284
 
    MBUF_SIZE(p) += n+1;
285
 
    ARITH_AVAIL(p) = n;
286
 
    hp = bp->mem;
287
 
#ifdef DEBUG
288
 
    for (i = 0; i <= n; i++) {
289
 
        hp[i] = ARITH_MARKER;
290
 
    }
291
 
#endif
292
 
    ARITH_HEAP(p) = hp;
293
 
#ifdef DEBUG
294
 
    ARITH_CHECK_ME(p) = ARITH_HEAP(p);
295
 
#endif
 
216
    }
 
217
#endif
 
218
 
 
219
    /*
 
220
     * We must find the heap fragment that hp points into.
 
221
     * If we are unlucky, we might have to search through
 
222
     * a large part of the list. We'll hope that will not
 
223
     * happen to often.
 
224
     */
 
225
    for (hf = MBUF(p); hf != 0; hf = hf->next) {
 
226
        if (hp - hf->mem < (unsigned long)hf->size) {
 
227
            if (ARITH_HEAP(p) - hf->mem < (unsigned long)hf->size) {
 
228
                /*
 
229
                 * Regain lost space from the current arith heap
 
230
                 * and make sure that there are no garbage in a heap
 
231
                 * fragment (important for the hybrid heap).
 
232
                 */
 
233
                Uint diff = ARITH_HEAP(p) - hp;
 
234
                ARITH_HEAP(p) = hp;
 
235
                ARITH_AVAIL(p) += diff;
 
236
#ifdef DEBUG
 
237
                while (diff != 0) {
 
238
                    hp[--diff] = ERTS_HOLE_MARKER;
 
239
                }
 
240
                ARITH_CHECK_ME(p) = hp;
 
241
#endif
 
242
#if defined(HYBRID) || defined(DEBUG) || defined(CHECK_FOR_HOLES)
 
243
            } else {
 
244
                /*
 
245
                 * We are not allowed to changed hf->size (because the
 
246
                 * size must be correct when deallocating). Therefore,
 
247
                 * clear out the uninitialized part of the heap fragment.
 
248
                 */
 
249
                Eterm* to = hf->mem + hf->size;
 
250
                while (hp < to) {
 
251
                    *hp++ = NIL;
 
252
                }
 
253
#endif
 
254
            }
 
255
            return;
 
256
        }
 
257
    }
 
258
}
 
259
#endif
 
260
 
 
261
#ifdef CHECK_FOR_HOLES
 
262
Eterm*
 
263
erts_set_hole_marker(Eterm* ptr, Uint sz)
 
264
{
 
265
    Eterm* p = ptr;
 
266
    int i;
 
267
 
 
268
    for (i = 0; i < sz; i++) {
 
269
        *p++ = ERTS_HOLE_MARKER;
 
270
    }
 
271
    return ptr;
296
272
}
297
273
#endif
298
274
 
343
319
#define IS_PRINT(c)  (!IS_CNTRL(c))
344
320
 
345
321
/*
346
 
 * Generate the integer part from a double.
347
 
 */
348
 
Eterm
349
 
double_to_integer(Process* p, double x)
350
 
{
351
 
    int is_negative;
352
 
    int ds;
353
 
    digit_t* xp;
354
 
    int i;
355
 
    Eterm res;
356
 
    size_t sz;
357
 
    Eterm* hp;
358
 
 
359
 
    if ((x < (double) (MAX_SMALL+1)) && (x > (double) (MIN_SMALL-1))) {
360
 
        Sint xi = x;
361
 
        return make_small(xi);
362
 
    }
363
 
 
364
 
    if (x >= 0) {
365
 
        is_negative = 0;
366
 
    } else {
367
 
        is_negative = 1;
368
 
        x = -x;
369
 
    }
370
 
 
371
 
    /* Unscale & (calculate exponent) */
372
 
    ds = 0;
373
 
    while(x >= 1.0) {
374
 
        x /= D_BASE;         /* "shift" right */
375
 
        ds++;
376
 
    }
377
 
    sz = BIG_NEED_SIZE(ds);          /* number of words */
378
 
 
379
 
    /*
380
 
     * Beam note: This function is called from guard bifs (round/1 and trunc/1),
381
 
     * which are not allowed to build anything at all on the heap.
382
 
     * Therefore it is essential to use the ArithAlloc() macro instead of HAlloc().
383
 
     */
384
 
    hp = ArithAlloc(p, sz+1);
385
 
    res = make_big(hp);
386
 
    xp = (digit_t*) (hp + 1);
387
 
 
388
 
    for (i = ds-1; i >= 0; i--) {
389
 
        digit_t d;
390
 
 
391
 
        x *= D_BASE;      /* "shift" left */
392
 
        d = x;            /* trunc */
393
 
        xp[i] = d;        /* store digit */
394
 
        x -= d;           /* remove integer part */
395
 
    }
396
 
    while ((ds & (BIG_DIGITS_PER_WORD-1)) != 0) {
397
 
        xp[ds++] = 0;
398
 
    }
399
 
 
400
 
    if (is_negative) {
401
 
        *hp = make_neg_bignum_header(sz-1);
402
 
    } else {
403
 
        *hp = make_pos_bignum_header(sz-1);
404
 
    }
405
 
    return res;
406
 
}
407
 
 
408
 
Uint erts_tot_link_lh_size;
409
 
 
410
 
/*
411
 
 * Create a new link with ref.
412
 
 *
413
 
 * item: pid, port, atom, small, or NIL.
414
 
 * data: pid, port, atom, small, or NIL.
415
 
 * ref:  reference, or NIL
416
 
 */
417
 
ErlLink*
418
 
new_ref_link(ErlLink* next, ErlLinkType type, Eterm item, Eterm data, Eterm ref)
419
 
{
420
 
    /* item, data, and ref are allowed to be pids, ports, refs, or any
421
 
       immediate Erlang term */
422
 
 
423
 
#define CP_LINK_VAL(To, Hp, From)                                       \
424
 
do {                                                                    \
425
 
    if (IS_CONST(From))                                                 \
426
 
        (To) = (From);                                                  \
427
 
    else {                                                              \
428
 
        Uint i__;                                                       \
429
 
        Uint len__;                                                     \
430
 
        ASSERT((Hp));                                                   \
431
 
        ASSERT(is_internal_ref((From)) || is_external((From)));         \
432
 
        (To) = make_boxed((Hp));                                        \
433
 
        len__ = thing_arityval(*boxed_val((From))) + 1;                 \
434
 
        for(i__ = 0; i__ < len__; i__++)                                \
435
 
            (*((Hp)++)) = boxed_val((From))[i__];                       \
436
 
        if (is_external((To))) {                                        \
437
 
            external_thing_ptr((To))->next = NULL;                      \
438
 
            external_thing_ptr((To))->node->refc++;                     \
439
 
        }                                                               \
440
 
    }                                                                   \
441
 
} while (0)
442
 
 
443
 
    ErlLink* lnk;
444
 
    Uint *hp;
445
 
    Uint link_size = ERL_LINK_SIZE;
446
 
 
447
 
    if(!IS_CONST(item))
448
 
        link_size += NC_HEAP_SIZE(item);
449
 
    if(!IS_CONST(data))
450
 
        link_size += NC_HEAP_SIZE(data);
451
 
    if(!IS_CONST(ref))
452
 
        link_size += NC_HEAP_SIZE(ref);
453
 
 
454
 
    ASSERT(link_size >= ERL_LINK_SIZE);
455
 
 
456
 
    ERTS_PROC_MORE_MEM(link_size);
457
 
 
458
 
    if (link_size == ERL_LINK_SIZE) {
459
 
        lnk = (ErlLink*) erts_alloc(ERTS_ALC_T_LINK,
460
 
                                    link_size*sizeof(Uint));
461
 
        hp = NULL;
462
 
    }
463
 
    else if (link_size <= ERL_LINK_SH_SIZE) {
464
 
        lnk = (ErlLink*) erts_alloc(ERTS_ALC_T_LINK_SH,
465
 
                                    link_size*sizeof(Uint));
466
 
        hp = lnk->heap;
467
 
    }
468
 
    else {
469
 
        lnk = (ErlLink*) erts_alloc(ERTS_ALC_T_LINK_LH,
470
 
                                    link_size*sizeof(Uint));
471
 
        erts_tot_link_lh_size += link_size*sizeof(Uint);
472
 
        hp = lnk->heap;
473
 
    }
474
 
 
475
 
    lnk->next = next;
476
 
    lnk->type = type;
477
 
 
478
 
    CP_LINK_VAL(lnk->item, hp, item);
479
 
    CP_LINK_VAL(lnk->data, hp, data);
480
 
    CP_LINK_VAL(lnk->ref,  hp, ref);
481
 
 
482
 
    ASSERT(!hp || (Uint) hp <= (Uint) (lnk + link_size));
483
 
    ASSERT(next == lnk->next);
484
 
    ASSERT(type == lnk->type);
485
 
    ASSERT(EQ(item, lnk->item));
486
 
    ASSERT(EQ(data, lnk->data));
487
 
    ASSERT(EQ(ref,  lnk->ref));
488
 
 
489
 
    return lnk;
490
 
 
491
 
#undef CP_LINK_VAL
492
 
 
493
 
}
494
 
 
495
 
/*
496
 
 * Create a new link.
497
 
 */
498
 
ErlLink*
499
 
new_link(ErlLink* next, ErlLinkType type, Eterm item, Eterm data)
500
 
{
501
 
   return new_ref_link(next, type, item, data, NIL);
502
 
}
503
 
 
504
 
/*
505
 
** Delete an old link (and relink)
506
 
*/
507
 
void del_link(lnk)
508
 
ErlLink** lnk;
509
 
{
510
 
    ErlLink* tlink;
511
 
    ErlNode *node;
512
 
    Uint link_size;
513
 
 
514
 
    if (lnk != NULL) {
515
 
        tlink = *lnk;
516
 
        *lnk = tlink->next;
517
 
        link_size = ERL_LINK_SIZE;
518
 
 
519
 
        if (!IS_CONST(tlink->item)) {
520
 
            link_size += NC_HEAP_SIZE(tlink->item);
521
 
            if(is_external(tlink->item)) {
522
 
                node = external_thing_ptr(tlink->item)->node;
523
 
                DEREF_ERL_NODE(node);
524
 
            }
525
 
        }
526
 
        if (!IS_CONST(tlink->data)) {
527
 
            link_size += NC_HEAP_SIZE(tlink->data);
528
 
            if(is_external(tlink->data)) {
529
 
                node = external_thing_ptr(tlink->data)->node;
530
 
                DEREF_ERL_NODE(node);
531
 
            }
532
 
        }
533
 
        if (!IS_CONST(tlink->ref)) {
534
 
            link_size += NC_HEAP_SIZE(tlink->ref);
535
 
            if(is_external(tlink->ref)) {
536
 
                node = external_thing_ptr(tlink->ref)->node;
537
 
                DEREF_ERL_NODE(node);
538
 
            }
539
 
        }
540
 
 
541
 
#ifdef DEBUG
542
 
        ASSERT(link_size >= ERL_LINK_SIZE);
543
 
        sys_memset((void *) tlink, 0x0f, link_size*sizeof(Uint));
544
 
#endif
545
 
 
546
 
        ERTS_PROC_LESS_MEM(link_size);
547
 
 
548
 
        if (link_size == ERL_LINK_SIZE)
549
 
            erts_free(ERTS_ALC_T_LINK, (void *) tlink);
550
 
        else if (link_size <= ERL_LINK_SH_SIZE)
551
 
            erts_free(ERTS_ALC_T_LINK_SH, (void *) tlink);
552
 
        else {
553
 
            erts_tot_link_lh_size -= link_size*sizeof(Uint);
554
 
            erts_free(ERTS_ALC_T_LINK_LH, (void *) tlink);
555
 
        }
556
 
    }
557
 
}
558
 
 
559
 
#ifdef DEBUG
560
 
 
561
 
static ErlLink** 
562
 
not_opt_find_link_by_ref(ErlLink** first, Eterm ref)
563
 
{
564
 
    ErlLink *lnk, *prev;
565
 
 
566
 
    ASSERT(is_ref(ref));
567
 
 
568
 
    for (prev = NULL, lnk = *first; lnk; prev = lnk, lnk = lnk->next)
569
 
        if (eq(lnk->ref, ref))
570
 
            return (prev == NULL) ? first : &prev->next;
571
 
    return NULL;
572
 
}
573
 
 
574
 
#endif
575
 
 
576
 
/*
577
 
** Find a link, given the value of the ref field
578
 
** Result is NULL if not found 
579
 
** otherwise a pointer to a pointer to it is returned (fit with del_link)
580
 
*/
581
 
ErlLink** 
582
 
find_link_by_ref(ErlLink** first, Eterm ref)
583
 
{
584
 
    ErlLink *lnk, *prev;
585
 
    ErlNode *anode;
586
 
    Uint alen, blen;
587
 
    Uint32 *anum, *bnum;
588
 
    ErlLink **res;
589
 
#ifdef DEBUG
590
 
    ErlLink **not_opt_res = not_opt_find_link_by_ref(first, ref);
591
 
#endif
592
 
 
593
 
    if (is_internal_ref(ref)) {
594
 
        anode = internal_ref_node(ref);
595
 
        alen = internal_ref_no_of_numbers(ref);
596
 
        anum = internal_ref_numbers(ref);
597
 
    }
598
 
    else {
599
 
        ASSERT(is_external_ref(ref));
600
 
        anode = external_ref_node(ref);
601
 
        alen = external_ref_no_of_numbers(ref);
602
 
        anum = external_ref_numbers(ref);
603
 
    }
604
 
 
605
 
    ASSERT(alen > 0);
606
 
 
607
 
    for (prev = NULL, lnk = *first; lnk; prev = lnk, lnk = lnk->next) {
608
 
        /* Inlining of
609
 
         * "if (eq(lnk->ref, ref))
610
 
         *      return (prev == NULL) ? first : &prev->next;"
611
 
         */
612
 
 
613
 
        if (is_nil(lnk->ref))
614
 
            continue;
615
 
 
616
 
        if (is_internal_ref(lnk->ref)) {
617
 
            ASSERT(internal_ref_no_of_numbers(lnk->ref) > 0);
618
 
 
619
 
 
620
 
            bnum = internal_ref_numbers(lnk->ref);
621
 
            if (anum[0] != bnum[0])
622
 
                continue;
623
 
            if (anode != internal_ref_node(lnk->ref))
624
 
                continue;
625
 
            blen = internal_ref_no_of_numbers(lnk->ref);
626
 
        }
627
 
        else {
628
 
            ASSERT(is_external_ref(lnk->ref));
629
 
            ASSERT(external_ref_no_of_numbers(lnk->ref) > 0);
630
 
 
631
 
 
632
 
            bnum = external_ref_numbers(lnk->ref);
633
 
            if (anum[0] != bnum[0])
634
 
                continue;
635
 
            if (anode != external_ref_node(lnk->ref))
636
 
                continue;
637
 
            blen = external_ref_no_of_numbers(lnk->ref);
638
 
        }
639
 
 
640
 
 
641
 
        if (alen == 3 && blen == 3) { /* Most refs are of length 3 */
642
 
 
643
 
            if (anum[1] != bnum[1] || anum[2] != bnum[2])
644
 
                continue;
645
 
 
646
 
        found_it:
647
 
            res = (prev == NULL) ? first : &prev->next;
648
 
            ASSERT(not_opt_res == res);
649
 
            return res;
650
 
 
651
 
        }
652
 
        else {
653
 
            Uint common_len;
654
 
            Uint i;
655
 
 
656
 
            common_len = alen;
657
 
            if (blen < alen)
658
 
                common_len = blen;
659
 
 
660
 
            for (i = 1; i < common_len; i++)
661
 
                if (anum[i] != bnum[i])
662
 
                    continue;
663
 
 
664
 
            if(alen != blen) {
665
 
 
666
 
                if (alen > blen) {
667
 
                    for (i = common_len; i < alen; i++)
668
 
                        if (anum[i] != 0)
669
 
                            continue;
670
 
                }
671
 
                else {
672
 
                    for (i = common_len; i < blen; i++)
673
 
                        if (bnum[i] != 0)
674
 
                            continue;
675
 
                }
676
 
                
677
 
            }
678
 
 
679
 
            goto found_it;
680
 
        }
681
 
    }
682
 
 
683
 
    ASSERT(not_opt_res == NULL);
684
 
    return NULL;
685
 
}
686
 
 
687
 
static ERTS_INLINE ErlLink**
688
 
gen_find_link(ErlLink** first, ErlLinkType type, Eterm item, Eterm data)
689
 
{
690
 
    ErlLink *lnk;
691
 
    ErlLink *prev;
692
 
 
693
 
    for (lnk = *first, prev = NULL; lnk; prev = lnk, lnk = lnk->next) {
694
 
        if (lnk->type != type)
695
 
            continue;
696
 
        if (!EQ(lnk->item, item))
697
 
            continue;
698
 
        if (is_nil(data) || EQ(lnk->data, data))
699
 
            return (prev == NULL) ? first : &prev->next;
700
 
    }
701
 
    return NULL;
702
 
}
703
 
 
704
 
/*
705
 
** Find a link.
706
 
** Result is NULL if not found 
707
 
** otherwise a pointer to a pointer to it is returned (fit with del_link)
708
 
*/
709
 
ErlLink**
710
 
find_link(ErlLink** first, ErlLinkType type, Eterm item, Eterm data)
711
 
{
712
 
    ErlLink *lnk = *first;
713
 
    ErlLink *prev = NULL;
714
 
    ErlLink **res;
715
 
 
716
 
    /* First a couple of optimized special cases that are common... */
717
 
    
718
 
    if (is_immed(item)) {
719
 
        if (is_immed(data) || is_external_pid(data)) {
720
 
            /* Local links, node monitors, and remote links in a dist entries
721
 
               will be handled here. */
722
 
            for (; lnk; prev = lnk, lnk = lnk->next) {
723
 
                if (lnk->type != type)
724
 
                    continue;
725
 
                if (lnk->item != item)
726
 
                    continue;
727
 
                if (is_nil(data)) {
728
 
                found_it:
729
 
                    res = (prev == NULL) ? first : &prev->next;
730
 
                    ASSERT(res == gen_find_link(first, type, item, data));
731
 
                    return res;
732
 
                }
733
 
                if (data == lnk->data)
734
 
                    goto found_it;
735
 
                if (is_not_external_pid(lnk->data))
736
 
                    continue;
737
 
                if (external_node(data) != external_node(lnk->data))
738
 
                    continue;
739
 
                if (external_pid_data(data) != external_pid_data(lnk->data))
740
 
                    continue;
741
 
                goto found_it;
742
 
            }
743
 
        not_found:
744
 
            ASSERT(NULL == gen_find_link(first, type, item, data));
745
 
            return NULL;
746
 
        }
747
 
    }
748
 
    else if (is_external_pid(item) && is_nil(data)) {
749
 
        /* Remote links stored in process structs will be handled here. */
750
 
        for (; lnk; prev = lnk, lnk = lnk->next) {
751
 
            if (lnk->type != type)
752
 
                continue;
753
 
            if (is_not_external_pid(lnk->item))
754
 
                continue;
755
 
            if (external_node(item) != external_node(lnk->item))
756
 
                continue;
757
 
            if (external_pid_data(item) != external_pid_data(lnk->item))
758
 
                continue;
759
 
            goto found_it;
760
 
        }
761
 
        goto not_found;
762
 
    }
763
 
 
764
 
    /* ... and then the general case. */
765
 
    return gen_find_link(first, type, item, data);
766
 
}
767
 
 
768
 
Uint
769
 
erts_link_size(ErlLink* elp)
770
 
{
771
 
    Uint size;
772
 
    if (!elp)
773
 
        return 0;
774
 
    size = ERL_LINK_SIZE*sizeof(Uint);
775
 
    if(!IS_CONST(elp->item))
776
 
        size += NC_HEAP_SIZE(elp->item)*sizeof(Uint);
777
 
    if(!IS_CONST(elp->data))
778
 
        size += NC_HEAP_SIZE(elp->data)*sizeof(Uint);
779
 
    if(!IS_CONST(elp->ref))
780
 
        size += NC_HEAP_SIZE(elp->ref)*sizeof(Uint);
781
 
    return size;
782
 
}
783
 
 
784
 
/*
785
322
 * Calculate length of a list.
786
323
 * Returns -1 if not a proper list (i.e. not terminated with NIL)
787
324
 */
812
349
   return i;
813
350
}
814
351
 
 
352
int
 
353
erts_print(int to, void *arg, char *format, ...)
 
354
{
 
355
    int res;
 
356
    va_list arg_list;
 
357
    va_start(arg_list, format);
 
358
 
 
359
    if (to < ERTS_PRINT_MIN)
 
360
        res = -EINVAL;
 
361
    else {
 
362
        switch (to) {
 
363
        case ERTS_PRINT_STDOUT:
 
364
            res = erts_vprintf(format, arg_list);
 
365
            break;
 
366
        case ERTS_PRINT_STDERR:
 
367
            res = erts_vfprintf(stderr, format, arg_list);
 
368
            break;
 
369
        case ERTS_PRINT_FILE:
 
370
            res = erts_vfprintf((FILE *) arg, format, arg_list);
 
371
            break;
 
372
        case ERTS_PRINT_SBUF:
 
373
            res = erts_vsprintf((char *) arg, format, arg_list);
 
374
            break;
 
375
        case ERTS_PRINT_SNBUF:
 
376
            res = erts_vsnprintf(((erts_print_sn_buf *) arg)->buf,
 
377
                                 ((erts_print_sn_buf *) arg)->size,
 
378
                                 format,
 
379
                                 arg_list);
 
380
            break;
 
381
        case ERTS_PRINT_DSBUF:
 
382
            res = erts_vdsprintf((erts_dsprintf_buf_t *) arg, format, arg_list);
 
383
            break;
 
384
        case ERTS_PRINT_INVALID:
 
385
            res = -EINVAL;
 
386
            break;
 
387
        default:
 
388
            res = erts_vfdprintf((int) to, format, arg_list);
 
389
            break;
 
390
        }
 
391
    }
 
392
 
 
393
    va_end(arg_list);
 
394
    return res;
 
395
}
 
396
 
 
397
int
 
398
erts_putc(int to, void *arg, char c)
 
399
{
 
400
    return erts_print(to, arg, "%c", c);
 
401
}
 
402
 
815
403
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
816
404
 * Some Erlang term building utility functions (to be used when performance  *
817
405
 * isn't critical).                                                          *
822
410
\*                                                                           */
823
411
 
824
412
Eterm
 
413
erts_bld_atom(Uint **hpp, Uint *szp, char *str)
 
414
{
 
415
    if (hpp)
 
416
        return am_atom_put(str, sys_strlen(str));
 
417
    else
 
418
        return THE_NON_VALUE;
 
419
}
 
420
 
 
421
Eterm
825
422
erts_bld_uint(Uint **hpp, Uint *szp, Uint ui)
826
423
{
827
424
    Eterm res = THE_NON_VALUE;
1035
632
#define FUNNY_NUMBER10 268440479
1036
633
#define FUNNY_NUMBER11 268440577
1037
634
 
 
635
static Uint32
 
636
hash_binary_bytes(Eterm bin, Uint sz, Uint32 hash)
 
637
{
 
638
    byte* ptr;
 
639
    Uint bitoffs;
 
640
    Uint bitsize;
 
641
 
 
642
    if (sz > 0) {
 
643
        ERTS_GET_BINARY_BYTES(bin, ptr, bitoffs, bitsize);
 
644
        if (bitoffs == 0) {
 
645
            while (sz--) {
 
646
                hash = hash*FUNNY_NUMBER1 + *ptr++;
 
647
            }
 
648
        } else {
 
649
            Uint previous = *ptr++;
 
650
            Uint b;
 
651
            Uint lshift = bitoffs;
 
652
            Uint rshift = 8 - lshift;
 
653
            
 
654
            while (sz--) {
 
655
                b = (previous << lshift) & 0xFF;
 
656
                previous = *ptr++;
 
657
                b |= previous >> rshift;
 
658
                hash = hash*FUNNY_NUMBER1 + b;
 
659
            }
 
660
        }
 
661
    }
 
662
    return hash;
 
663
}
 
664
 
1038
665
Uint32
1039
666
make_hash(Eterm term, Uint32 hash)
1040
667
{
1041
 
    Uint32 x;
1042
 
    Sint32 y;
1043
 
 
1044
668
    /* 
1045
669
    ** Convenience macro for calculating a bytewise hash on an unsigned 32 bit 
1046
670
    ** integer.
1047
671
    ** If the endianess is known, we could be smarter here, 
1048
672
    ** but that gives no significant speedup (on a sparc at least) 
1049
673
    */
1050
 
#define UINT32_HASH_RET(Expr, Prime1, Prime2)                           \
 
674
#define UINT32_HASH_STEP(Expr, Prime1)                                  \
1051
675
        do {                                                            \
1052
 
            x = (Uint32) (Expr);                                        \
1053
 
            return                                                      \
 
676
            Uint32 x = (Uint32) (Expr);                                 \
 
677
            hash =                                                      \
1054
678
                (((((hash)*(Prime1) + (x & 0xFF)) * (Prime1) +          \
1055
679
                ((x >> 8) & 0xFF)) * (Prime1) +                         \
1056
680
                ((x >> 16) & 0xFF)) * (Prime1) +                        \
1057
 
                 (x >> 24)) * (Prime2);                                 \
 
681
                 (x >> 24));                                            \
 
682
        } while(0)
 
683
 
 
684
#define UINT32_HASH_RET(Expr, Prime1, Prime2)                           \
 
685
        do {                                                            \
 
686
            UINT32_HASH_STEP(Expr, Prime1);                             \
 
687
            return hash * (Prime2);                                     \
1058
688
        } while(0)
1059
689
 
1060
690
#define SINT32_HASH_RET(Expr, Prime1, Prime2, Prime3)   \
1061
691
        do {                                            \
1062
 
            y = (Sint32) Expr;                          \
 
692
            Sint32 y = (Sint32) Expr;                   \
1063
693
            if (y < 0) {                                \
1064
694
                UINT32_HASH_RET(-y, Prime1, Prime3);    \
1065
695
            }                                           \
1068
698
                
1069
699
            
1070
700
    /* 
1071
 
    ** Significant additions needed for real 64 bit port with larger fixnums.
1072
 
    */      
1073
 
    ASSERT(SMALL_BITS <= 32);
 
701
     * Significant additions needed for real 64 bit port with larger fixnums.
 
702
     */     
 
703
 
1074
704
    /* 
1075
 
    ** Note, for the simple 64bit port, not utilizing the 
1076
 
    ** larger word size this function will work without modification. 
1077
 
    */
 
705
     * Note, for the simple 64bit port, not utilizing the 
 
706
     * larger word size this function will work without modification. 
 
707
     */
1078
708
 
1079
709
    switch (tag_val_def(term)) {
1080
710
    case NIL_DEF:
1085
715
            (atom_tab(atom_val(term))->slot.bucket.hvalue);
1086
716
 
1087
717
    case SMALL_DEF:
1088
 
        SINT32_HASH_RET(signed_val(term), FUNNY_NUMBER2,
1089
 
                        FUNNY_NUMBER3, FUNNY_NUMBER4);
 
718
        {
 
719
            Sint y1 = signed_val(term);
 
720
            Uint y2 = y1 < 0 ? -(Uint)y1 : y1;
 
721
 
 
722
            UINT32_HASH_STEP(y2, FUNNY_NUMBER2);
 
723
#ifdef ARCH_64
 
724
            if (y2 >> 32)
 
725
                UINT32_HASH_STEP(y2 >> 32, FUNNY_NUMBER2);
 
726
#endif
 
727
            return hash * (y1 < 0 ? FUNNY_NUMBER4 : FUNNY_NUMBER3);
 
728
        }
1090
729
 
1091
730
    case BINARY_DEF:
1092
731
        {
1093
 
            byte* ptr;
1094
 
            unsigned sz = binary_size(term);
1095
 
            int i = sz;
 
732
            Uint sz = binary_size(term);
1096
733
 
1097
 
            GET_BINARY_BYTES(term, ptr);
1098
 
            while (i--) {
1099
 
                hash = hash*FUNNY_NUMBER1 + *ptr++;
1100
 
            }
 
734
            hash = hash_binary_bytes(term, sz, hash);
1101
735
            return hash*FUNNY_NUMBER4 + sz;
1102
736
        }
1103
737
 
 
738
    case EXPORT_DEF:
 
739
        {
 
740
            Export* ep = (Export *) (export_val(term))[1];
 
741
 
 
742
            hash = hash * FUNNY_NUMBER11 + ep->code[2];
 
743
            hash = hash*FUNNY_NUMBER1 + 
 
744
                (atom_tab(atom_val(ep->code[0]))->slot.bucket.hvalue);
 
745
            hash = hash*FUNNY_NUMBER1 + 
 
746
                (atom_tab(atom_val(ep->code[1]))->slot.bucket.hvalue);
 
747
            return hash;
 
748
        }
 
749
 
1104
750
    case FUN_DEF:
1105
751
        {
1106
752
            ErlFunThing* funp = (ErlFunThing *) fun_val(term);
1173
819
            int is_neg = BIG_SIGN(ptr);
1174
820
            Uint i;
1175
821
 
1176
 
            if (n & 1) /* emulate 32 bit behaviour (add a MSB 0 :-( )*/
 
822
            if (D_EXP < 32 && (n & 1)) /* emulate 32 bit behaviour (add a MSB 0 :-( )*/
1177
823
              n++;
1178
824
 
1179
825
            for (i = 0; i < n; i++)  {
1180
826
              digit_t d = BIG_DIGIT(ptr, i);
1181
 
            
1182
 
              hash = (hash*FUNNY_NUMBER2 + (d & 0xff))* FUNNY_NUMBER2 +
1183
 
                (d >> 8);
 
827
              int j;
 
828
              for(j = 0; j < sizeof(digit_t); ++j) {
 
829
                  hash = (hash*FUNNY_NUMBER2) + (d & 0xff);
 
830
                  d >>= 8;
 
831
              }
1184
832
            }
1185
833
            if (is_neg) {
1186
834
                return hash*FUNNY_NUMBER4;
1204
852
        }
1205
853
        break;
1206
854
 
1207
 
    case VECTOR_DEF:
1208
 
        {
1209
 
            Uint siz = (Uint) VECTOR_SIZE(term);
1210
 
            int i = 1;
1211
 
 
1212
 
            for(i=1;i<=siz;++i)
1213
 
                hash = make_hash(erts_unchecked_vector_get(i,term), hash);
1214
 
            return hash*FUNNY_NUMBER11 + siz;
1215
 
        }
1216
 
        break;
1217
 
        
1218
 
 
1219
855
    default:
1220
856
        erl_exit(1, "Invalid tag in make_hash(0x%X)\n", term);
1221
857
        return 0;
1222
858
    }
 
859
#undef UINT32_HASH_STEP
1223
860
#undef UINT32_HASH_RET
1224
861
#undef SINT32_HASH_RET
1225
862
}
1286
923
make_hash2(Eterm term)
1287
924
{
1288
925
    Uint32 hash;
 
926
    Eterm tmp_big[2];
1289
927
 
1290
 
/* (HCONST * {2, ..., 13}) mod 2^32 */
 
928
/* (HCONST * {2, ..., 14}) mod 2^32 */
1291
929
#define HCONST_2 0x3c6ef372UL
1292
930
#define HCONST_3 0xdaa66d2bUL
1293
931
#define HCONST_4 0x78dde6e4UL
1300
938
#define HCONST_11 0xcc623af3UL
1301
939
#define HCONST_12 0x6a99b4acUL
1302
940
#define HCONST_13 0x08d12e65UL
 
941
#define HCONST_14 0xa708a81eUL
1303
942
 
1304
943
#define UINT32_HASH_2(Expr1, Expr2, AConst)       \
1305
944
         do {                                     \
1316
955
            Sint32 y = (Sint32) (Expr);           \
1317
956
            if (y < 0) {                          \
1318
957
                UINT32_HASH(-y, AConst);          \
 
958
                /* Negative numbers are unnecessarily mixed twice. */ \
1319
959
            }                                     \
1320
960
            UINT32_HASH(y, AConst);               \
1321
961
        } while(0)
1322
962
 
1323
 
    ASSERT(SMALL_BITS <= 32);
 
963
#define IS_SSMALL28(x) (((Uint) (((x) >> (28-1)) + 1)) < 2)
1324
964
 
1325
965
    /* Optimization. Simple cases before declaration of estack. */
1326
966
    if (primary_tag(term) == TAG_PRIMARY_IMMED1) {
1332
972
            }
1333
973
            break;
1334
974
        case _TAG_IMMED1_SMALL:
1335
 
            hash = 0;
1336
 
            SINT32_HASH(signed_val(term), HCONST);
1337
 
            return hash;
 
975
          {
 
976
              Sint x = signed_val(term);
 
977
 
 
978
              if (SMALL_BITS > 28 && !IS_SSMALL28(x)) {
 
979
                  term = small_to_big(x, tmp_big);
 
980
                  break;
 
981
              }
 
982
              hash = 0;
 
983
              SINT32_HASH(x, HCONST);
 
984
              return hash;
 
985
          }
1338
986
        }
1339
987
    };
1340
988
    {
1392
1040
                term = elem[1];
1393
1041
            }
1394
1042
            break;
1395
 
            case VECTOR_SUBTAG:
 
1043
            case EXPORT_SUBTAG:
1396
1044
            {
1397
 
                int i;
1398
 
                int siz = VECTOR_SIZE(term);
 
1045
                Export* ep = (Export *) (export_val(term))[1];
1399
1046
 
1400
 
                UINT32_HASH(siz, HCONST_8);
1401
 
                if (siz == 0) 
1402
 
                    goto hash2_common;
1403
 
                for (i=siz; i > 1; i--) {
1404
 
                    tmp = erts_unchecked_vector_get(i, term);
1405
 
                    ESTACK_PUSH(s, tmp);
1406
 
                }
1407
 
                term = erts_unchecked_vector_get(1, term);
 
1047
                UINT32_HASH_2
 
1048
                    (ep->code[2], 
 
1049
                     atom_tab(atom_val(ep->code[0]))->slot.bucket.hvalue,
 
1050
                     HCONST);
 
1051
                UINT32_HASH
 
1052
                    (atom_tab(atom_val(ep->code[1]))->slot.bucket.hvalue,
 
1053
                     HCONST_14);
 
1054
                goto hash2_common;
1408
1055
            }
1409
 
            break;
 
1056
 
1410
1057
            case FUN_SUBTAG:
1411
1058
            {
1412
1059
                ErlFunThing* funp = (ErlFunThing *) fun_val(term);
1437
1084
                byte* bptr;
1438
1085
                unsigned sz = binary_size(term);
1439
1086
                Uint32 con = HCONST_13 + hash;
1440
 
                        
1441
 
                GET_BINARY_BYTES(term, bptr);
1442
 
                hash = (sz == 0) ? con : block_hash(bptr, sz, con);
 
1087
 
 
1088
                if (sz == 0) {
 
1089
                    hash = con;
 
1090
                } else {
 
1091
                    Uint bitoffs;
 
1092
                    Uint bitsize;
 
1093
 
 
1094
                    ERTS_GET_BINARY_BYTES(term, bptr, bitoffs, bitsize);
 
1095
                    if (bitoffs == 0) {
 
1096
                        hash = block_hash(bptr, sz, con);
 
1097
                    } else {
 
1098
                        byte* buf = (byte *) erts_alloc(ERTS_ALC_T_TMP, sz);
 
1099
                        erts_copy_bits(bptr, bitoffs, 1, buf, 0, 1, sz*8);
 
1100
                        hash = block_hash(buf, sz, con);
 
1101
                        erts_free(ERTS_ALC_T_TMP, (void *) buf);
 
1102
                    }
 
1103
                }
1443
1104
                goto hash2_common;
1444
1105
            }
1445
1106
            break;
1452
1113
                Uint32 con = BIG_SIGN(ptr) ? HCONST_10 : HCONST_11;
1453
1114
 
1454
1115
                do {
1455
 
                    digit_t d1 = i < n ? BIG_DIGIT(ptr, i++) : 0;
1456
 
                    digit_t d2 = i < n ? BIG_DIGIT(ptr, i++) : 0;
1457
 
                    digit_t d3 = i < n ? BIG_DIGIT(ptr, i++) : 0;
1458
 
                    digit_t d4 = i < n ? BIG_DIGIT(ptr, i++) : 0;
1459
 
                    UINT32_HASH_2((((Uint32) d2) << 16) + (Uint32) d1,
1460
 
                                  (((Uint32) d4) << 16) + (Uint32) d3, con);
 
1116
                    Uint x, y;
 
1117
                    ASSERT(sizeof(digit_t) <= 4);
 
1118
                    ASSERT(D_EXP < 8*sizeof(Uint));
 
1119
                    x = i < n ? BIG_DIGIT(ptr, i++) : 0;
 
1120
                    if (sizeof(digit_t) == 2)
 
1121
                        x += (Uint)(i < n ? BIG_DIGIT(ptr, i++) : 0) << D_EXP;
 
1122
                    y = i < n ? BIG_DIGIT(ptr, i++) : 0;
 
1123
                    if (sizeof(digit_t) == 2)
 
1124
                        y += (Uint)(i < n ? BIG_DIGIT(ptr, i++) : 0) << D_EXP;
 
1125
                    UINT32_HASH_2((Uint32)x, (Uint32)y, con);
1461
1126
                } while (i < n);
1462
1127
                goto hash2_common;
1463
1128
            }
1521
1186
                    erl_exit(1, "Invalid tag in make_hash2(0x%X)\n", term);
1522
1187
                }
1523
1188
            case _TAG_IMMED1_SMALL:
1524
 
                SINT32_HASH(signed_val(term), HCONST);
1525
 
                goto hash2_common;
 
1189
              {
 
1190
                  Sint x = signed_val(term);
 
1191
 
 
1192
                  if (SMALL_BITS > 28 && !IS_SSMALL28(x)) {
 
1193
                      term = small_to_big(x, tmp_big);
 
1194
                      break;
 
1195
                  }
 
1196
                  SINT32_HASH(x, HCONST);
 
1197
                  goto hash2_common;
 
1198
              }
1526
1199
            }
1527
1200
            break;
1528
1201
        default:
1559
1232
        return hash*FUNNY_NUMBER1 + 
1560
1233
            (atom_tab(atom_val(term))->slot.bucket.hvalue);
1561
1234
    case SMALL_DEF:
 
1235
#ifdef ARCH_64
 
1236
    {
 
1237
        Sint y1 = signed_val(term);
 
1238
        Uint y2 = y1 < 0 ? -(Uint)y1 : y1;
 
1239
        Uint32 y3 = (Uint32) (y2 >> 32);
 
1240
        int arity = 1;
 
1241
 
 
1242
#if defined(WORDS_BIGENDIAN)
 
1243
        if (!IS_SSMALL28(y1))
 
1244
        {   /* like a bignum */
 
1245
            Uint32 y4 = (Uint32) y2;
 
1246
            hash = hash*FUNNY_NUMBER2 + ((y4 << 16) | (y4 >> 16));
 
1247
            if (y3) 
 
1248
            {
 
1249
                hash = hash*FUNNY_NUMBER2 + ((y3 << 16) | (y3 >> 16));
 
1250
                arity++;
 
1251
            }
 
1252
            return hash * (y1 < 0 ? FUNNY_NUMBER3 : FUNNY_NUMBER2) + arity;
 
1253
        }
 
1254
        return hash*FUNNY_NUMBER2 + (((Uint) y1) & 0xfffffff);
 
1255
#else
 
1256
        if  (!IS_SSMALL28(y1))
 
1257
        {   /* like a bignum */
 
1258
            hash = hash*FUNNY_NUMBER2 + ((Uint32) y2);
 
1259
            if (y3)
 
1260
            {
 
1261
                hash = hash*FUNNY_NUMBER2 + y3;
 
1262
                arity++;
 
1263
            }
 
1264
            return hash * (y1 < 0 ? FUNNY_NUMBER3 : FUNNY_NUMBER2) + arity;
 
1265
        }
 
1266
        return hash*FUNNY_NUMBER2 + (((Uint) y1) & 0xfffffff);
 
1267
#endif
 
1268
    }
 
1269
#else
1562
1270
        return hash*FUNNY_NUMBER2 + unsigned_val(term);
 
1271
#endif
1563
1272
    case BINARY_DEF:
1564
1273
        {
1565
 
            byte* ptr;
1566
1274
            size_t sz = binary_size(term);
1567
1275
            size_t i = (sz < 15) ? sz : 15;
1568
1276
 
1569
 
            GET_BINARY_BYTES(term, ptr);
1570
 
            while (i-- != 0) {
1571
 
                hash = hash*FUNNY_NUMBER1 + *ptr++;
1572
 
            }
 
1277
            hash = hash_binary_bytes(term, i, hash);
1573
1278
            return hash*FUNNY_NUMBER4 + sz;
1574
1279
        }
 
1280
 
 
1281
    case EXPORT_DEF:
 
1282
        {
 
1283
            Export* ep = (Export *) (export_val(term))[1];
 
1284
 
 
1285
            hash = hash * FUNNY_NUMBER11 + ep->code[2];
 
1286
            hash = hash*FUNNY_NUMBER1 + 
 
1287
                (atom_tab(atom_val(ep->code[0]))->slot.bucket.hvalue);
 
1288
            hash = hash*FUNNY_NUMBER1 + 
 
1289
                (atom_tab(atom_val(ep->code[1]))->slot.bucket.hvalue);
 
1290
            return hash;
 
1291
        }
 
1292
 
1575
1293
    case FUN_DEF:
1576
1294
        {
1577
1295
            ErlFunThing* funp = (ErlFunThing *) fun_val(term);
1634
1352
#ifdef ARCH_64
1635
1353
            Uint i = 0;
1636
1354
            Uint n = BIG_SIZE(ptr);
1637
 
            ptr++;
1638
 
            arity = (n + 1) >> 1;
 
1355
            arity = n;
1639
1356
 
1640
 
            do {
 
1357
            for (i = 0; i < n; i++)
 
1358
            {
 
1359
                digit_t d = BIG_DIGIT(ptr, i);
1641
1360
#if defined(WORDS_BIGENDIAN)
1642
 
                hash = hash*FUNNY_NUMBER2 + (Uint32) (((Uint) *ptr) >> 32);
1643
 
                i += 2;
1644
 
                if (i < n) {
1645
 
                    hash = hash*FUNNY_NUMBER2 + (Uint32) *ptr;
1646
 
                    i += 2;
1647
 
                }
 
1361
                hash = hash*FUNNY_NUMBER2 + ((d << 16) | (d >> 16));
1648
1362
#else
1649
 
                hash = hash*FUNNY_NUMBER2 + (Uint32) *ptr;
1650
 
                i += 2;
1651
 
                if (i < n) {
1652
 
                    hash = hash*FUNNY_NUMBER2 + (Uint32) (((Uint) *ptr) >> 32);
1653
 
                    i += 2;
1654
 
                }
 
1363
                hash = hash*FUNNY_NUMBER2 + d;
1655
1364
#endif
1656
 
                ptr++; 
1657
 
            } while (i < n);
 
1365
            }
1658
1366
#else
1659
1367
            int i = arity;
1660
1368
 
1684
1392
        }
1685
1393
        break;
1686
1394
 
1687
 
    case VECTOR_DEF:
1688
 
        {
1689
 
            Uint siz = (Uint) VECTOR_SIZE(term);
1690
 
            int i = 1;
1691
 
 
1692
 
            for(i=1;i<=siz;++i)
1693
 
                hash = make_broken_hash(erts_unchecked_vector_get(i,term), 
1694
 
                                        hash);
1695
 
            return hash*FUNNY_NUMBER11 + siz;
1696
 
        }
1697
 
        break;
1698
 
        
1699
1395
    default:
1700
1396
        erl_exit(1, "Invalid tag in make_broken_hash\n");
1701
1397
        return 0;
1702
1398
    }
1703
1399
}
1704
1400
 
1705
 
static int do_send_to_logger(char *tag, Eterm gleader, char *buf, int len)
 
1401
static int do_send_to_logger(Eterm tag, Eterm gleader, char *buf, int len)
1706
1402
{
1707
1403
    /* error_logger ! 
1708
1404
       {notify,{info_msg,gleader,{emulator,"~s~n",[<message as list>]}}} |
1709
1405
       {notify,{error,gleader,{emulator,"~s~n",[<message as list>]}}} |
1710
1406
       {notify,{warning_msg,gleader,{emulator,"~s~n",[<message as list>}]}} */
1711
 
    Process *p;
1712
 
    Eterm atom_tag, atom_notify;
1713
1407
    Eterm* hp;
1714
1408
    Uint sz;
1715
1409
    Uint gl_sz;
1716
1410
    Eterm gl;
1717
1411
    Eterm list,plist,format,tuple1,tuple2,tuple3;
1718
 
    
 
1412
    ErlOffHeap *ohp;
 
1413
#ifdef ERTS_SMP
 
1414
    ErlHeapFragment *bp;
 
1415
#else
 
1416
    Process *p;
 
1417
#endif
 
1418
 
 
1419
    ASSERT(is_atom(tag));
 
1420
 
1719
1421
    if (len <= 0) {
1720
1422
        return -1;
1721
1423
    }
1722
 
    if ((p = whereis_process(am_error_logger)) == NULL ||
1723
 
        p->status == P_EXITING || p->status == P_RUNNING)  {
1724
 
        /* Now, buf might not be null-terminated and it might be tmp_buf... */
1725
 
        if (len >= TMP_BUF_SIZE) {
1726
 
            len = TMP_BUF_SIZE - 1;
1727
 
        }
1728
 
        sys_memmove(tmp_buf,buf,len);
1729
 
        tmp_buf[len] = '\0';
1730
 
        erl_printf(CERR,"(no error logger present) %s: %s\r\n",
1731
 
                   tag,tmp_buf);
 
1424
 
 
1425
#ifndef ERTS_SMP
 
1426
    if (
 
1427
#ifdef USE_THREADS
 
1428
        !erts_get_scheduler_data() || /* Must be scheduler thread */
 
1429
#endif
 
1430
        (p = erts_whereis_process(NULL, 0, am_error_logger, 0, 0)) == NULL
 
1431
        || p->status == P_RUNNING) {
 
1432
        /* buf *always* points to a null terminated string */
 
1433
        erts_fprintf(stderr, "(no error logger present) %T: \"%s\"\n",
 
1434
                     tag, buf);
1732
1435
        return 0;
1733
1436
    }
1734
 
 
1735
1437
    /* So we have an error logger, lets build the message */
1736
 
    atom_tag = am_atom_put(tag,strlen(tag));
1737
 
    atom_notify = am_atom_put("notify",6);
 
1438
#endif
1738
1439
    gl_sz = IS_CONST(gleader) ? 0 : size_object(gleader);
1739
1440
    sz = len * 2 /* message list */+ 2 /* cons surrounding message list */
1740
1441
        + gl_sz + 
1741
1442
        3 /*outher 2-tuple*/ + 4 /* middle 3-tuple */ + 4 /*inner 3-tuple */ +
1742
1443
        8 /* "~s~n" */;
1743
 
    hp = HAlloc(p,sz);
 
1444
#ifdef ERTS_SMP
 
1445
    bp = new_message_buffer(sz);
 
1446
    ohp = &bp->off_heap;
 
1447
    hp = bp->mem;
 
1448
#else
 
1449
    ohp = &MSO(p);
 
1450
    hp = HAlloc(p, sz);
 
1451
#endif
1744
1452
    gl = (is_nil(gleader)
1745
1453
          ? am_noproc
1746
1454
          : (IS_CONST(gleader)
1747
1455
             ? gleader
1748
 
             : copy_struct(gleader,gl_sz,&hp,&MSO(p))));
 
1456
             : copy_struct(gleader,gl_sz,&hp,ohp)));
1749
1457
    list = buf_to_intlist(&hp, buf, len, NIL);
1750
1458
    plist = CONS(hp,list,NIL);
1751
1459
    hp += 2;
1752
1460
    format = buf_to_intlist(&hp, "~s~n", 4, NIL);
1753
1461
    tuple1 = TUPLE3(hp, am_emulator, format, plist);
1754
1462
    hp += 4;
1755
 
    tuple2 = TUPLE3(hp, atom_tag, gl, tuple1);
 
1463
    tuple2 = TUPLE3(hp, tag, gl, tuple1);
1756
1464
    hp += 4;
1757
 
    tuple3 = TUPLE2(hp, atom_notify, tuple2);
 
1465
    tuple3 = TUPLE2(hp, am_notify, tuple2);
1758
1466
#ifdef HARDDEBUG
1759
 
    display(tuple3,CERR);
1760
 
#endif
1761
 
    queue_message_tt(p, NULL, tuple3, NIL);
 
1467
    erts_fprintf(stderr, "%T\n", tuple3);
 
1468
#endif
 
1469
#ifdef ERTS_SMP
 
1470
    {
 
1471
        Eterm from = erts_get_current_pid();
 
1472
        if (is_not_internal_pid(from))
 
1473
            from = NIL;
 
1474
        erts_queue_error_logger_message(from, tuple3, bp);
 
1475
    }
 
1476
#else
 
1477
    erts_queue_message(p, 0/* only used for smp build */, NULL, tuple3, NIL);
 
1478
#endif
1762
1479
    return 0;
1763
1480
}
1764
1481
 
1765
 
int erts_send_info_to_logger(Eterm gleader, char *buf, int len) 
 
1482
static ERTS_INLINE int
 
1483
send_info_to_logger(Eterm gleader, char *buf, int len) 
1766
1484
{
1767
 
    return do_send_to_logger("info_msg",gleader,buf,len);
 
1485
    return do_send_to_logger(am_info_msg, gleader, buf, len);
1768
1486
}
1769
1487
 
1770
 
int erts_send_warning_to_logger(Eterm gleader, char *buf, int len) 
 
1488
static ERTS_INLINE int
 
1489
send_warning_to_logger(Eterm gleader, char *buf, int len) 
1771
1490
{
1772
 
    char *tag;
 
1491
    Eterm tag;
1773
1492
    switch (erts_error_logger_warnings) {
1774
 
    case am_info:
1775
 
        tag = "info_msg";
1776
 
        break;
1777
 
    case am_warning:
1778
 
        tag = "warning_msg";
1779
 
        break;
1780
 
    default:
1781
 
        tag = "error";
1782
 
        break;
 
1493
    case am_info:       tag = am_info_msg;      break;
 
1494
    case am_warning:    tag = am_warning_msg;   break;
 
1495
    default:            tag = am_error;         break;
1783
1496
    }
1784
 
    return do_send_to_logger(tag,gleader,buf,len);
1785
 
}
1786
 
 
1787
 
int erts_send_error_to_logger(Eterm gleader, char *buf, int len) 
1788
 
{
1789
 
    return do_send_to_logger("error",gleader,buf,len);
1790
 
}
1791
 
 
1792
 
/* To be removed, old obsolete interface */
1793
 
int send_error_to_logger(Eterm gleader)
1794
 
{
1795
 
    return erts_send_error_to_logger(gleader,tmp_buf,cerr_pos) == 0;
1796
 
}
 
1497
    return do_send_to_logger(tag, gleader, buf, len);
 
1498
}
 
1499
 
 
1500
static ERTS_INLINE int
 
1501
send_error_to_logger(Eterm gleader, char *buf, int len) 
 
1502
{
 
1503
    return do_send_to_logger(am_error, gleader, buf, len);
 
1504
}
 
1505
 
 
1506
#define LOGGER_DSBUF_INC_SZ 256
 
1507
 
 
1508
static erts_dsprintf_buf_t *
 
1509
grow_logger_dsbuf(erts_dsprintf_buf_t *dsbufp, size_t need)
 
1510
{
 
1511
    size_t size;
 
1512
    size_t free_size = dsbufp->size - dsbufp->str_len;
 
1513
 
 
1514
    ASSERT(dsbufp && dsbufp->str);
 
1515
 
 
1516
    if (need <= free_size)
 
1517
        return dsbufp;
 
1518
 
 
1519
    size = need - free_size + LOGGER_DSBUF_INC_SZ;
 
1520
    size = (((size + LOGGER_DSBUF_INC_SZ - 1) / LOGGER_DSBUF_INC_SZ)
 
1521
            * LOGGER_DSBUF_INC_SZ);
 
1522
    size += dsbufp->size;
 
1523
    ASSERT(dsbufp->str_len + need <= size);
 
1524
    dsbufp->str = (char *) erts_realloc(ERTS_ALC_T_LOGGER_DSBUF,
 
1525
                                        (void *) dsbufp->str,
 
1526
                                        size);
 
1527
    dsbufp->size = size;
 
1528
    return dsbufp;
 
1529
}
 
1530
 
 
1531
erts_dsprintf_buf_t *
 
1532
erts_create_logger_dsbuf(void)
 
1533
{
 
1534
    erts_dsprintf_buf_t init = ERTS_DSPRINTF_BUF_INITER(grow_logger_dsbuf);
 
1535
    erts_dsprintf_buf_t *dsbufp = erts_alloc(ERTS_ALC_T_LOGGER_DSBUF,
 
1536
                                             sizeof(erts_dsprintf_buf_t));
 
1537
    sys_memcpy((void *) dsbufp, (void *) &init, sizeof(erts_dsprintf_buf_t));
 
1538
    dsbufp->str = (char *) erts_alloc(ERTS_ALC_T_LOGGER_DSBUF,
 
1539
                                      LOGGER_DSBUF_INC_SZ);
 
1540
    dsbufp->str[0] = '\0';
 
1541
    dsbufp->size = LOGGER_DSBUF_INC_SZ;
 
1542
    return dsbufp;
 
1543
}
 
1544
 
 
1545
static ERTS_INLINE void
 
1546
destroy_logger_dsbuf(erts_dsprintf_buf_t *dsbufp)
 
1547
{
 
1548
    ASSERT(dsbufp && dsbufp->str);
 
1549
    erts_free(ERTS_ALC_T_LOGGER_DSBUF, (void *) dsbufp->str);
 
1550
    erts_free(ERTS_ALC_T_LOGGER_DSBUF, (void *) dsbufp);
 
1551
}
 
1552
 
 
1553
int
 
1554
erts_send_info_to_logger(Eterm gleader, erts_dsprintf_buf_t *dsbufp)
 
1555
{
 
1556
    int res;
 
1557
    res = send_info_to_logger(gleader, dsbufp->str, dsbufp->str_len);
 
1558
    destroy_logger_dsbuf(dsbufp);
 
1559
    return res;
 
1560
}
 
1561
 
 
1562
int
 
1563
erts_send_warning_to_logger(Eterm gleader, erts_dsprintf_buf_t *dsbufp)
 
1564
{
 
1565
    int res;
 
1566
    res = send_warning_to_logger(gleader, dsbufp->str, dsbufp->str_len);
 
1567
    destroy_logger_dsbuf(dsbufp);
 
1568
    return res;
 
1569
}
 
1570
 
 
1571
int
 
1572
erts_send_error_to_logger(Eterm gleader, erts_dsprintf_buf_t *dsbufp)
 
1573
{
 
1574
    int res;
 
1575
    res = send_error_to_logger(gleader, dsbufp->str, dsbufp->str_len);
 
1576
    destroy_logger_dsbuf(dsbufp);
 
1577
    return res;
 
1578
}
 
1579
 
 
1580
int
 
1581
erts_send_info_to_logger_str(Eterm gleader, char *str)
 
1582
{
 
1583
    return send_info_to_logger(gleader, str, sys_strlen(str));
 
1584
}
 
1585
 
 
1586
int
 
1587
erts_send_warning_to_logger_str(Eterm gleader, char *str)
 
1588
{
 
1589
    return send_warning_to_logger(gleader, str, sys_strlen(str));
 
1590
}
 
1591
 
 
1592
int
 
1593
erts_send_error_to_logger_str(Eterm gleader, char *str)
 
1594
{
 
1595
    return send_error_to_logger(gleader, str, sys_strlen(str));
 
1596
}
 
1597
 
 
1598
int
 
1599
erts_send_info_to_logger_nogl(erts_dsprintf_buf_t *dsbuf)
 
1600
{
 
1601
    return erts_send_info_to_logger(NIL, dsbuf);
 
1602
}
 
1603
 
 
1604
int
 
1605
erts_send_warning_to_logger_nogl(erts_dsprintf_buf_t *dsbuf)
 
1606
{
 
1607
    return erts_send_warning_to_logger(NIL, dsbuf);
 
1608
}
 
1609
 
 
1610
int
 
1611
erts_send_error_to_logger_nogl(erts_dsprintf_buf_t *dsbuf)
 
1612
{
 
1613
    return erts_send_error_to_logger(NIL, dsbuf);
 
1614
}
 
1615
 
 
1616
int
 
1617
erts_send_info_to_logger_str_nogl(char *str)
 
1618
{
 
1619
    return erts_send_info_to_logger_str(NIL, str);
 
1620
}
 
1621
 
 
1622
int
 
1623
erts_send_warning_to_logger_str_nogl(char *str)
 
1624
{
 
1625
    return erts_send_warning_to_logger_str(NIL, str);
 
1626
}
 
1627
 
 
1628
int
 
1629
erts_send_error_to_logger_str_nogl(char *str)
 
1630
{
 
1631
    return erts_send_error_to_logger_str(NIL, str);
 
1632
}
 
1633
 
 
1634
 
 
1635
#define TMP_DSBUF_INC_SZ 256
 
1636
 
 
1637
static erts_dsprintf_buf_t *
 
1638
grow_tmp_dsbuf(erts_dsprintf_buf_t *dsbufp, size_t need)
 
1639
{
 
1640
    size_t size;
 
1641
    size_t free_size = dsbufp->size - dsbufp->str_len;
 
1642
 
 
1643
    ASSERT(dsbufp);
 
1644
 
 
1645
    if (need <= free_size)
 
1646
        return dsbufp;
 
1647
    size = need - free_size + TMP_DSBUF_INC_SZ;
 
1648
    size = ((size + TMP_DSBUF_INC_SZ - 1)/TMP_DSBUF_INC_SZ)*TMP_DSBUF_INC_SZ;
 
1649
    size += dsbufp->size;
 
1650
    ASSERT(dsbufp->str_len + need <= size);
 
1651
    dsbufp->str = (char *) erts_realloc(ERTS_ALC_T_TMP_DSBUF,
 
1652
                                        (void *) dsbufp->str,
 
1653
                                        size);
 
1654
    dsbufp->size = size;
 
1655
    return dsbufp;
 
1656
}
 
1657
 
 
1658
erts_dsprintf_buf_t *
 
1659
erts_create_tmp_dsbuf(Uint size)
 
1660
{
 
1661
    Uint init_size = size ? size : TMP_DSBUF_INC_SZ;
 
1662
    erts_dsprintf_buf_t init = ERTS_DSPRINTF_BUF_INITER(grow_tmp_dsbuf);
 
1663
    erts_dsprintf_buf_t *dsbufp = erts_alloc(ERTS_ALC_T_TMP_DSBUF,
 
1664
                                             sizeof(erts_dsprintf_buf_t));
 
1665
    sys_memcpy((void *) dsbufp, (void *) &init, sizeof(erts_dsprintf_buf_t));
 
1666
    dsbufp->str = (char *) erts_alloc(ERTS_ALC_T_TMP_DSBUF, init_size);
 
1667
    dsbufp->str[0] = '\0';
 
1668
    dsbufp->size = init_size;
 
1669
    return dsbufp;
 
1670
}
 
1671
 
 
1672
void
 
1673
erts_destroy_tmp_dsbuf(erts_dsprintf_buf_t *dsbufp)
 
1674
{
 
1675
    if (dsbufp->str)
 
1676
        erts_free(ERTS_ALC_T_TMP_DSBUF, (void *) dsbufp->str);
 
1677
    erts_free(ERTS_ALC_T_TMP_DSBUF, (void *) dsbufp);
 
1678
}
 
1679
 
 
1680
 
1797
1681
/* eq and cmp are written as separate functions a eq is a little faster */
1798
1682
 
1799
1683
/*
1836
1720
            case HEAP_BINARY_SUBTAG:
1837
1721
            case SUB_BINARY_SUBTAG:
1838
1722
                {
1839
 
                    Uint size;
1840
1723
                    byte* a_ptr;
1841
1724
                    byte* b_ptr;
1842
 
 
 
1725
                    size_t a_size;
 
1726
                    size_t b_size;
 
1727
                    Uint a_bitsize;
 
1728
                    Uint b_bitsize;
 
1729
                    Uint a_bitoffs;
 
1730
                    Uint b_bitoffs;
 
1731
                    
1843
1732
                    if (is_not_binary(b)) {
1844
1733
                        return 0;
1845
1734
                    }
1846
 
                    size = binary_size(a);
1847
 
                    if (size != binary_size(b)) {
1848
 
                        return 0;
1849
 
                    }
1850
 
                    GET_BINARY_BYTES(a, a_ptr);
1851
 
                    GET_BINARY_BYTES(b, b_ptr);
1852
 
                    return sys_memcmp(a_ptr, b_ptr, size) == 0;
 
1735
                    a_size = binary_size(a);
 
1736
                    b_size = binary_size(b); 
 
1737
                    if (a_size != b_size) {
 
1738
                        return 0;
 
1739
                    }
 
1740
                    ERTS_GET_BINARY_BYTES(a, a_ptr, a_bitoffs, a_bitsize);
 
1741
                    ERTS_GET_BINARY_BYTES(b, b_ptr, b_bitoffs, b_bitsize);
 
1742
                    if ((a_bitsize | b_bitsize | a_bitoffs | b_bitoffs) == 0) {
 
1743
                        return sys_memcmp(a_ptr, b_ptr, a_size) == 0;
 
1744
                    } else if (a_bitsize == b_bitsize) {
 
1745
                        return erts_cmp_bits(a_ptr, a_bitoffs, b_ptr, b_bitoffs,
 
1746
                                             (a_size << 3) + a_bitsize) == 0;
 
1747
                    } else {
 
1748
                        return 0;
 
1749
                    }
 
1750
                }
 
1751
        case EXPORT_SUBTAG:
 
1752
                {
 
1753
                    Export* a_exp;
 
1754
                    Export* b_exp;
 
1755
 
 
1756
                    if (is_not_export(b)) {
 
1757
                        return 0;
 
1758
                    }
 
1759
                    a_exp = (Export *) (export_val(a))[1];
 
1760
                    b_exp = (Export *) (export_val(b))[1];
 
1761
                    return a_exp == b_exp;
1853
1762
                }
1854
1763
            case FUN_SUBTAG:
1855
1764
                {
2003
1912
                    GET_DOUBLE(b, bf);
2004
1913
                    return (af.fd == bf.fd) ? 1 : 0;
2005
1914
                }
2006
 
            case VECTOR_SUBTAG:
2007
 
                {
2008
 
                    int i;
2009
 
                    int n;
2010
 
                    if (is_not_vector(b)) {
2011
 
                        return 0;
2012
 
                    }
2013
 
                    n = VECTOR_SIZE(a);
2014
 
                    if (n != VECTOR_SIZE(b)) {
2015
 
                        return 0;
2016
 
                    }
2017
 
                    for (i = 1; i <= n; i++) {
2018
 
                        Eterm atmp = erts_unchecked_vector_get(i, a);
2019
 
                        Eterm btmp = erts_unchecked_vector_get(i, b);
2020
 
                        if (!EQ(atmp, btmp)) {
2021
 
                            return 0;
2022
 
                        }
2023
 
                    }
2024
 
                    return 1;
2025
 
                }
2026
1915
            }
2027
1916
            break;
2028
1917
        }
2093
1982
                    bb->name+3, bb->len-3);
2094
1983
}
2095
1984
 
2096
 
int
 
1985
Sint
2097
1986
cmp(Eterm a, Eterm b)
2098
1987
{
2099
1988
    Eterm* aa;
2100
1989
    Eterm* bb;
2101
1990
    int i;
2102
 
    int j;
2103
 
    int n;
 
1991
    Sint j;
2104
1992
    Eterm big_buf[2];
2105
1993
    int a_tag;
2106
1994
    int b_tag;
 
1995
    ErlNode *anode;
 
1996
    ErlNode *bnode;
 
1997
    Uint adata;
 
1998
    Uint bdata;
 
1999
    Uint alen;
 
2000
    Uint blen;
 
2001
    Uint32 *anum;
 
2002
    Uint32 *bnum;
2107
2003
 
2108
2004
#undef  CMP_NODES
2109
2005
#define CMP_NODES(AN, BN)                                               \
2134
2030
     * Take care of cases where the types are the same.
2135
2031
     */
2136
2032
 
2137
 
    a_tag = tag_val_def(a);
2138
 
    switch (a_tag) {
2139
 
    case TUPLE_DEF:
2140
 
        if (is_not_tuple(b))
2141
 
            break;
2142
 
        aa = tuple_val(a);
2143
 
        bb = tuple_val(b);
2144
 
        /* compare the arities */
2145
 
        i = arityval(*aa);      /* get the arity*/
2146
 
        if (i < arityval(*bb)) return(-1);
2147
 
        if (i > arityval(*bb)) return(1);
2148
 
        while (i--) {
2149
 
            if ((j = cmp(*++aa, *++bb)) != 0) 
2150
 
                return j;
2151
 
        }
2152
 
        return 0;
2153
 
    case LIST_DEF:
2154
 
        if (is_not_list(b))
2155
 
            break;
 
2033
    a_tag = 42;                 /* Suppress warning */
 
2034
    switch (primary_tag(a)) {
 
2035
    case TAG_PRIMARY_IMMED1:
 
2036
        switch ((a & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
 
2037
        case (_TAG_IMMED1_PORT >> _TAG_PRIMARY_SIZE):
 
2038
            if (is_internal_port(b)) {
 
2039
                bnode = erts_this_node;
 
2040
                bdata = internal_port_data(b);
 
2041
            } else if (is_external_port(b)) {
 
2042
                bnode = external_port_node(b);
 
2043
                bdata = external_port_data(b);
 
2044
            } else {
 
2045
                a_tag = PORT_DEF;
 
2046
                goto mixed_types;
 
2047
            }
 
2048
            anode = erts_this_node;
 
2049
            adata = internal_port_data(a);
 
2050
                
 
2051
        port_common:
 
2052
            CMP_NODES(anode, bnode);
 
2053
            if (adata != bdata) {
 
2054
                return adata < bdata ? -1 : 1;
 
2055
            }
 
2056
            return 0;
 
2057
        case (_TAG_IMMED1_PID >> _TAG_PRIMARY_SIZE):
 
2058
            if (is_internal_pid(b)) {
 
2059
                bnode = erts_this_node;
 
2060
                bdata = internal_pid_data(b);
 
2061
            } else if (is_external_pid(b)) {
 
2062
                bnode = external_pid_node(b);
 
2063
                bdata = external_pid_data(b);
 
2064
            } else {
 
2065
                a_tag = PID_DEF;
 
2066
                goto mixed_types;
 
2067
            }
 
2068
            anode = erts_this_node;
 
2069
            adata = internal_pid_data(a);
 
2070
            
 
2071
        pid_common:
 
2072
            if (adata != bdata) {
 
2073
                return adata < bdata ? -1 : 1;
 
2074
            }
 
2075
            CMP_NODES(anode, bnode);
 
2076
            return 0;
 
2077
        case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE):
 
2078
            a_tag = SMALL_DEF;
 
2079
            goto mixed_types;
 
2080
        case (_TAG_IMMED1_IMMED2 >> _TAG_PRIMARY_SIZE): {
 
2081
            switch ((a & _TAG_IMMED2_MASK) >> _TAG_IMMED1_SIZE) {
 
2082
            case (_TAG_IMMED2_ATOM >> _TAG_IMMED1_SIZE):
 
2083
                a_tag = ATOM_DEF;
 
2084
                goto mixed_types;
 
2085
            case (_TAG_IMMED2_NIL >> _TAG_IMMED1_SIZE):
 
2086
                a_tag = NIL_DEF;
 
2087
                goto mixed_types;
 
2088
            }
 
2089
        }
 
2090
        }
 
2091
    case TAG_PRIMARY_LIST:
 
2092
        if (is_not_list(b)) {
 
2093
            a_tag = LIST_DEF;
 
2094
            goto mixed_types;
 
2095
        }
2156
2096
        aa = list_val(a);
2157
2097
        bb = list_val(b);
2158
2098
        while (1) {
2168
2108
            aa = list_val(*aa);
2169
2109
            bb = list_val(*bb);
2170
2110
        }
2171
 
    case FLOAT_DEF:
2172
 
        if (is_not_float(b))
2173
 
            break;
2174
 
        {
2175
 
            FloatDef af;
2176
 
            FloatDef bf; 
2177
 
 
2178
 
            GET_DOUBLE(a, af);
2179
 
            GET_DOUBLE(b, bf);
2180
 
            return float_comp(af.fd, bf.fd);
2181
 
        }
2182
 
    case REF_DEF: {
2183
 
        /*
2184
 
         * Observe!
2185
 
         *  When comparing refs we need to compare ref numbers (32-bit words)
2186
 
         *  *not* ref data words.
2187
 
         */
2188
 
        Uint alen;
2189
 
        Uint blen;
2190
 
        Sint i;
2191
 
        Uint32 *anum;
2192
 
        Uint32 *bnum;
2193
 
        ErlNode *anode;
2194
 
        ErlNode *bnode;
2195
 
 
2196
 
        if (is_internal_ref(b)) {
2197
 
            bnode = erts_this_node;
2198
 
            bnum = internal_ref_numbers(b);
2199
 
            blen = internal_ref_no_of_numbers(b);
2200
 
        }
2201
 
        else if(is_external_ref(b)) {
2202
 
            bnode = external_ref_node(b);
2203
 
            bnum = external_ref_numbers(b);
2204
 
            blen = external_ref_no_of_numbers(b);
2205
 
        }
2206
 
        else
2207
 
            break;
2208
 
 
2209
 
        anode = erts_this_node;
2210
 
        anum = internal_ref_numbers(a);
2211
 
        alen = internal_ref_no_of_numbers(a);
2212
 
 
2213
 
    ref_common:
2214
 
 
2215
 
        CMP_NODES(anode, bnode);
2216
 
 
2217
 
        ASSERT(alen > 0 && blen > 0);
2218
 
 
2219
 
        if(alen != blen) {
2220
 
            
2221
 
            if (alen > blen) {
2222
 
                do {
2223
 
                    if (anum[alen - 1] != 0)
2224
 
                        return 1;
2225
 
                    alen--;
2226
 
                } while (alen > blen);
2227
 
            }
2228
 
            else {
2229
 
                do {
2230
 
                    if (bnum[blen - 1] != 0)
2231
 
                        return -1;
2232
 
                    blen--;
2233
 
                } while (alen < blen);
2234
 
            }
2235
 
            
2236
 
        }
2237
 
 
2238
 
        ASSERT(alen == blen);
2239
 
 
2240
 
        for (i = (Sint) alen - 1; i >= 0; i--)
2241
 
            if (anum[i] != bnum[i])
2242
 
                return anum[i] < bnum[i] ? -1 : 1;
2243
 
 
2244
 
        return 0;
2245
 
 
2246
 
    case EXTERNAL_REF_DEF:
2247
 
 
2248
 
        if (is_internal_ref(b)) {
2249
 
            bnode = erts_this_node;
2250
 
            bnum = internal_ref_numbers(b);
2251
 
            blen = internal_ref_no_of_numbers(b);
2252
 
        }
2253
 
        else if(is_external_ref(b)) {
2254
 
            bnode = external_ref_node(b);
2255
 
            bnum = external_ref_numbers(b);
2256
 
            blen = external_ref_no_of_numbers(b);
2257
 
        }
2258
 
        else
2259
 
            break;
2260
 
 
2261
 
        anode = external_ref_node(a);
2262
 
        anum = external_ref_numbers(a);
2263
 
        alen = external_ref_no_of_numbers(a);
2264
 
 
2265
 
        goto ref_common;
2266
 
    }
2267
 
    case BIG_DEF:
2268
 
        if (is_not_big(b))
2269
 
            break;
2270
 
        return big_comp(a, b);
2271
 
    case BINARY_DEF:
2272
 
        if (is_not_binary(b))
2273
 
            break;
2274
 
        {
2275
 
            Uint a_size = binary_size(a);
2276
 
            Uint b_size = binary_size(b);
2277
 
            Uint min_size;
2278
 
            int cmp;
2279
 
            byte* a_ptr;
2280
 
            byte* b_ptr;
2281
 
 
2282
 
            min_size = (a_size < b_size) ? a_size : b_size;
2283
 
            GET_BINARY_BYTES(a, a_ptr);
2284
 
            GET_BINARY_BYTES(b, b_ptr);
2285
 
            if ((cmp = sys_memcmp(a_ptr, b_ptr, min_size)) != 0) {
2286
 
                return cmp;
2287
 
            } else {
2288
 
                return a_size - b_size;
2289
 
            }
2290
 
        }
2291
 
    case FUN_DEF:
2292
 
        if (is_not_fun(b))
2293
 
            break;
2294
 
        {
2295
 
            ErlFunThing* f1 = (ErlFunThing *) fun_val(a);
2296
 
            ErlFunThing* f2 = (ErlFunThing *) fun_val(b);
2297
 
            int num_free;
2298
 
            int diff;
2299
 
 
2300
 
            diff = cmpbytes(atom_tab(atom_val(f1->fe->module))->name,
2301
 
                            atom_tab(atom_val(f1->fe->module))->len,
2302
 
                            atom_tab(atom_val(f2->fe->module))->name,
2303
 
                            atom_tab(atom_val(f2->fe->module))->len);
2304
 
            if (diff != 0) {
2305
 
                return diff;
2306
 
            }
2307
 
            diff = f1->fe->old_index - f2->fe->old_index;
2308
 
            if (diff != 0) {
2309
 
                return diff;
2310
 
            }
2311
 
            diff = f1->fe->old_uniq - f2->fe->old_uniq;
2312
 
            if (diff != 0) {
2313
 
                return diff;
2314
 
            }
2315
 
            diff = f1->num_free - f2->num_free;
2316
 
            if (diff != 0) {
2317
 
                return diff;
2318
 
            }
2319
 
            num_free = f1->num_free;
2320
 
            for (i = 0; i < num_free; i++) {
2321
 
                if ((diff = cmp(f1->env[i], f2->env[i])) != 0) {
2322
 
                    return diff;
2323
 
                }
2324
 
            }
2325
 
            return 0;
2326
 
        }
2327
 
 
2328
 
    case PID_DEF: {
2329
 
        Uint adata;
2330
 
        Uint bdata;
2331
 
        ErlNode *anode;
2332
 
        ErlNode *bnode;
2333
 
 
2334
 
        if(is_internal_pid(b)) {
2335
 
            bnode = erts_this_node;
2336
 
            bdata = internal_pid_data(b);
2337
 
        }
2338
 
        else if (is_external_pid(b)) {
2339
 
            bnode = external_pid_node(b);
2340
 
            bdata = external_pid_data(b);
2341
 
        }
2342
 
        else
2343
 
            break;
2344
 
        
2345
 
        anode = erts_this_node;
2346
 
        adata = internal_pid_data(a);
2347
 
 
2348
 
    pid_common:
2349
 
 
2350
 
        if (adata != bdata)
2351
 
            return adata < bdata ? -1 : 1;
2352
 
 
2353
 
        CMP_NODES(anode, bnode);
2354
 
 
2355
 
        return 0;
2356
 
 
2357
 
    case EXTERNAL_PID_DEF:
2358
 
 
2359
 
        if(is_internal_pid(b)) {
2360
 
            bnode = erts_this_node;
2361
 
            bdata = internal_pid_data(b);
2362
 
        }
2363
 
        else if (is_external_pid(b)) {
2364
 
            bnode = external_pid_node(b);
2365
 
            bdata = external_pid_data(b);
2366
 
        }
2367
 
        else
2368
 
            break;
2369
 
 
2370
 
        anode = external_pid_node(a);
2371
 
        adata = external_pid_data(a);
2372
 
 
2373
 
        goto pid_common;
2374
 
 
2375
 
    case PORT_DEF:
2376
 
 
2377
 
        if(is_internal_port(b)) {
2378
 
            bnode = erts_this_node;
2379
 
            bdata = internal_port_data(b);
2380
 
        }
2381
 
        else if (is_external_port(b)) {
2382
 
            bnode = external_port_node(b);
2383
 
            bdata = external_port_data(b);
2384
 
        }
2385
 
        else
2386
 
            break;
2387
 
        
2388
 
        anode = erts_this_node;
2389
 
        adata = internal_port_data(a);
2390
 
 
2391
 
 
2392
 
    port_common:
2393
 
 
2394
 
        CMP_NODES(anode, bnode);
2395
 
 
2396
 
        if (adata != bdata)
2397
 
            return adata < bdata ? -1 : 1;
2398
 
 
2399
 
        return 0;
2400
 
 
2401
 
    case EXTERNAL_PORT_DEF:
2402
 
 
2403
 
        if(is_internal_port(b)) {
2404
 
            bnode = erts_this_node;
2405
 
            bdata = internal_port_data(b);
2406
 
        }
2407
 
        else if (is_external_port(b)) {
2408
 
            bnode = external_port_node(b);
2409
 
            bdata = external_port_data(b);
2410
 
        }
2411
 
        else
2412
 
            break;
2413
 
 
2414
 
        anode = external_port_node(a);
2415
 
        adata = external_port_data(a);
2416
 
 
2417
 
        goto port_common;
2418
 
 
2419
 
    }
2420
 
    case VECTOR_DEF:
2421
 
        if (is_not_vector(b))
2422
 
            break;
2423
 
        n = VECTOR_SIZE(a);
2424
 
        if (n < VECTOR_SIZE(b)) return(-1);
2425
 
        if (n > VECTOR_SIZE(b)) return(1);
2426
 
        for (i = 1; i <= n; i++) {
2427
 
            Eterm atmp = erts_unchecked_vector_get(i, a);
2428
 
            Eterm btmp = erts_unchecked_vector_get(i, b);
2429
 
            if ((j = cmp(atmp, btmp)) != 0) {
2430
 
                return j;
2431
 
            }
2432
 
        }
2433
 
        return 0;
2434
 
    }
2435
 
 
 
2111
    case TAG_PRIMARY_BOXED:
 
2112
        {
 
2113
            Eterm ahdr = *boxed_val(a);
 
2114
            switch ((ahdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
 
2115
            case (_TAG_HEADER_ARITYVAL >> _TAG_PRIMARY_SIZE):
 
2116
                if (is_not_tuple(b)) {
 
2117
                    a_tag = TUPLE_DEF;
 
2118
                    goto mixed_types;
 
2119
                }
 
2120
                aa = tuple_val(a);
 
2121
                bb = tuple_val(b);
 
2122
                /* compare the arities */
 
2123
                i = arityval(ahdr);     /* get the arity*/
 
2124
                if (i < arityval(*bb)) return(-1);
 
2125
                if (i > arityval(*bb)) return(1);
 
2126
                if (i == 0) {
 
2127
                    return 0;
 
2128
                }
 
2129
                while (--i) {
 
2130
                    a = *++aa;
 
2131
                    b = *++bb;
 
2132
                    if (a != b) {
 
2133
                        if (is_atom(a) && is_atom(b)) {
 
2134
                            if ((j = cmp_atoms(a, b)) != 0) {
 
2135
                                return j;
 
2136
                            }
 
2137
                        } else if (is_both_small(a, b)) {
 
2138
                            if ((j = signed_val(a)-signed_val(b)) != 0) {
 
2139
                                return j;
 
2140
                            }
 
2141
                        } else if ((j = cmp(a, b)) != 0) {
 
2142
                            return j;
 
2143
                        }
 
2144
                    }
 
2145
                }
 
2146
                a = *++aa;
 
2147
                b = *++bb;
 
2148
                goto tailrecur;
 
2149
            case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE):
 
2150
                if (is_not_float(b)) {
 
2151
                    a_tag = FLOAT_DEF;
 
2152
                    goto mixed_types;
 
2153
                } else {
 
2154
                    FloatDef af;
 
2155
                    FloatDef bf; 
 
2156
 
 
2157
                    GET_DOUBLE(a, af);
 
2158
                    GET_DOUBLE(b, bf);
 
2159
                    return float_comp(af.fd, bf.fd);
 
2160
                }
 
2161
            case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE):
 
2162
            case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE):
 
2163
                if (is_not_big(b)) {
 
2164
                    a_tag = BIG_DEF;
 
2165
                    goto mixed_types;
 
2166
                }
 
2167
                return big_comp(a, b);
 
2168
            case (_TAG_HEADER_EXPORT >> _TAG_PRIMARY_SIZE):
 
2169
                if (is_not_export(b)) {
 
2170
                    a_tag = EXPORT_DEF;
 
2171
                    goto mixed_types;
 
2172
                } else {
 
2173
                    Export* a_exp = (Export *) (export_val(a))[1];
 
2174
                    Export* b_exp = (Export *) (export_val(b))[1];
 
2175
 
 
2176
                    if ((j = cmp_atoms(a_exp->code[0], b_exp->code[0])) != 0) {
 
2177
                        return j;
 
2178
                    }
 
2179
                    if ((j = cmp_atoms(a_exp->code[1], b_exp->code[1])) != 0) {
 
2180
                        return j;
 
2181
                    }
 
2182
                    return (Sint) a_exp->code[2] - (Sint) b_exp->code[2];
 
2183
                }
 
2184
                break;
 
2185
            case (_TAG_HEADER_FUN >> _TAG_PRIMARY_SIZE):
 
2186
                if (is_not_fun(b)) {
 
2187
                    a_tag = FUN_DEF;
 
2188
                    goto mixed_types;
 
2189
                } else {
 
2190
                    ErlFunThing* f1 = (ErlFunThing *) fun_val(a);
 
2191
                    ErlFunThing* f2 = (ErlFunThing *) fun_val(b);
 
2192
                    int num_free;
 
2193
                    Sint diff;
 
2194
 
 
2195
                    diff = cmpbytes(atom_tab(atom_val(f1->fe->module))->name,
 
2196
                                    atom_tab(atom_val(f1->fe->module))->len,
 
2197
                                    atom_tab(atom_val(f2->fe->module))->name,
 
2198
                                    atom_tab(atom_val(f2->fe->module))->len);
 
2199
                    if (diff != 0) {
 
2200
                        return diff;
 
2201
                    }
 
2202
                    diff = f1->fe->old_index - f2->fe->old_index;
 
2203
                    if (diff != 0) {
 
2204
                        return diff;
 
2205
                    }
 
2206
                    diff = f1->fe->old_uniq - f2->fe->old_uniq;
 
2207
                    if (diff != 0) {
 
2208
                        return diff;
 
2209
                    }
 
2210
                    diff = f1->num_free - f2->num_free;
 
2211
                    if (diff != 0) {
 
2212
                        return diff;
 
2213
                    }
 
2214
                    num_free = f1->num_free;
 
2215
                    for (i = 0; i < num_free; i++) {
 
2216
                        if ((diff = cmp(f1->env[i], f2->env[i])) != 0) {
 
2217
                            return diff;
 
2218
                        }
 
2219
                    }
 
2220
                    return 0;
 
2221
                }
 
2222
            case (_TAG_HEADER_EXTERNAL_PID >> _TAG_PRIMARY_SIZE):
 
2223
                if (is_internal_pid(b)) {
 
2224
                    bnode = erts_this_node;
 
2225
                    bdata = internal_pid_data(b);
 
2226
                } else if (is_external_pid(b)) {
 
2227
                    bnode = external_pid_node(b);
 
2228
                    bdata = external_pid_data(b);
 
2229
                } else {
 
2230
                    a_tag = EXTERNAL_PID_DEF;
 
2231
                    goto mixed_types;
 
2232
                }
 
2233
                anode = external_pid_node(a);
 
2234
                adata = external_pid_data(a);
 
2235
                goto pid_common;
 
2236
            case (_TAG_HEADER_EXTERNAL_PORT >> _TAG_PRIMARY_SIZE):
 
2237
                if (is_internal_port(b)) {
 
2238
                    bnode = erts_this_node;
 
2239
                    bdata = internal_port_data(b);
 
2240
                } else if (is_external_port(b)) {
 
2241
                    bnode = external_port_node(b);
 
2242
                    bdata = external_port_data(b);
 
2243
                } else {
 
2244
                    a_tag = EXTERNAL_PORT_DEF;
 
2245
                    goto mixed_types;
 
2246
                }
 
2247
                anode = external_port_node(a);
 
2248
                adata = external_port_data(a);
 
2249
                goto port_common;
 
2250
            case (_TAG_HEADER_REF >> _TAG_PRIMARY_SIZE):
 
2251
                /*
 
2252
                 * Note! When comparing refs we need to compare ref numbers
 
2253
                 * (32-bit words), *not* ref data words.
 
2254
                 */
 
2255
                
 
2256
                if (is_internal_ref(b)) {
 
2257
                    bnode = erts_this_node;
 
2258
                    bnum = internal_ref_numbers(b);
 
2259
                    blen = internal_ref_no_of_numbers(b);
 
2260
                } else if(is_external_ref(b)) {
 
2261
                    bnode = external_ref_node(b);
 
2262
                    bnum = external_ref_numbers(b);
 
2263
                    blen = external_ref_no_of_numbers(b);
 
2264
                } else {
 
2265
                    a_tag = REF_DEF;
 
2266
                    goto mixed_types;
 
2267
                }
 
2268
                anode = erts_this_node;
 
2269
                anum = internal_ref_numbers(a);
 
2270
                alen = internal_ref_no_of_numbers(a);
 
2271
                
 
2272
            ref_common:
 
2273
                CMP_NODES(anode, bnode);
 
2274
                
 
2275
                ASSERT(alen > 0 && blen > 0);
 
2276
                if (alen != blen) {
 
2277
                    if (alen > blen) {
 
2278
                        do {
 
2279
                            if (anum[alen - 1] != 0)
 
2280
                                return 1;
 
2281
                            alen--;
 
2282
                        } while (alen > blen);
 
2283
                    }
 
2284
                    else {
 
2285
                        do {
 
2286
                            if (bnum[blen - 1] != 0)
 
2287
                                return -1;
 
2288
                            blen--;
 
2289
                        } while (alen < blen);
 
2290
                    }
 
2291
                }
 
2292
                
 
2293
                ASSERT(alen == blen);
 
2294
                for (i = (Sint) alen - 1; i >= 0; i--)
 
2295
                    if (anum[i] != bnum[i])
 
2296
                        return anum[i] < bnum[i] ? -1 : 1;
 
2297
                return 0;
 
2298
            case (_TAG_HEADER_EXTERNAL_REF >> _TAG_PRIMARY_SIZE):
 
2299
                if (is_internal_ref(b)) {
 
2300
                    bnode = erts_this_node;
 
2301
                    bnum = internal_ref_numbers(b);
 
2302
                    blen = internal_ref_no_of_numbers(b);
 
2303
                } else if (is_external_ref(b)) {
 
2304
                    bnode = external_ref_node(b);
 
2305
                    bnum = external_ref_numbers(b);
 
2306
                    blen = external_ref_no_of_numbers(b);
 
2307
                } else {
 
2308
                    a_tag = EXTERNAL_REF_DEF;
 
2309
                    goto mixed_types;
 
2310
                }
 
2311
                anode = external_ref_node(a);
 
2312
                anum = external_ref_numbers(a);
 
2313
                alen = external_ref_no_of_numbers(a);
 
2314
                goto ref_common;
 
2315
            default:
 
2316
                /* Must be a binary */
 
2317
                ASSERT(is_binary(a));
 
2318
                if (is_not_binary(b)) {
 
2319
                    a_tag = BINARY_DEF;
 
2320
                    goto mixed_types;
 
2321
                } else {
 
2322
                    Uint a_size = binary_size(a);
 
2323
                    Uint b_size = binary_size(b);
 
2324
                    Uint a_bitsize;
 
2325
                    Uint b_bitsize;
 
2326
                    Uint a_bitoffs;
 
2327
                    Uint b_bitoffs;
 
2328
                    Uint min_size;
 
2329
                    int cmp;
 
2330
                    byte* a_ptr;
 
2331
                    byte* b_ptr;
 
2332
                    ERTS_GET_BINARY_BYTES(a, a_ptr, a_bitoffs, a_bitsize);
 
2333
                    ERTS_GET_BINARY_BYTES(b, b_ptr, b_bitoffs, b_bitsize);
 
2334
                    if ((a_bitsize | b_bitsize | a_bitoffs | b_bitoffs) == 0) {
 
2335
                        min_size = (a_size < b_size) ? a_size : b_size;
 
2336
                        if ((cmp = sys_memcmp(a_ptr, b_ptr, min_size)) != 0) {
 
2337
                            return cmp;
 
2338
                        } else {
 
2339
                            return a_size - b_size;
 
2340
                        }
 
2341
                    }
 
2342
                    else {
 
2343
                        a_size = (a_size << 3) + a_bitsize;
 
2344
                        b_size = (b_size << 3) + b_bitsize;
 
2345
                        min_size = (a_size < b_size) ? a_size : b_size;
 
2346
                        if ((cmp = erts_cmp_bits(a_ptr,a_bitoffs,
 
2347
                                                 b_ptr,b_bitoffs,min_size)) != 0) {
 
2348
                            return cmp;
 
2349
                        }
 
2350
                        else {
 
2351
                            return a_size - b_size;
 
2352
                        }
 
2353
                    }
 
2354
                }
 
2355
            }
 
2356
        }
 
2357
    }
 
2358
 
 
2359
    /*
 
2360
     * Take care of the case that the tags are different.
 
2361
     */
 
2362
 
 
2363
 mixed_types:
2436
2364
    b_tag = tag_val_def(b);
2437
2365
 
2438
 
    /*
2439
 
     * Take care of the case that the tags are different.
2440
 
     */
2441
 
 
2442
2366
    {
2443
2367
        FloatDef f1, f2;
2444
2368
        Eterm big;
2479
2403
 
2480
2404
}
2481
2405
 
2482
 
Process*
2483
 
pid2proc(Eterm pid)
2484
 
{
2485
 
    Uint pix;
2486
 
    Process *rp;
2487
 
    if (is_not_internal_pid(pid))
2488
 
        return NULL;
2489
 
    pix = internal_pid_index(pid);
2490
 
    if(pix >= erts_max_processes)
2491
 
        return NULL;
2492
 
    rp = process_tab[pix];
2493
 
    if (INVALID_PID(rp, pid))
2494
 
        return NULL;
2495
 
    return rp;
2496
 
}
2497
 
 
2498
2406
void
2499
2407
erts_cleanup_externals(ExternalThing *etp)
2500
2408
{
2503
2411
    tetp = etp;
2504
2412
 
2505
2413
    while(tetp) {
2506
 
        DEREF_ERL_NODE(tetp->node);
 
2414
        erts_deref_node_entry(tetp->node);
2507
2415
        tetp = tetp->next;
2508
2416
    }
2509
2417
}
2526
2434
        for(i = 0; i < size; i++)
2527
2435
            to_hp[i] = from_hp[i];
2528
2436
 
2529
 
        ((ExternalThing *) to_hp)->node->refc++;
 
2437
        erts_refc_inc(&((ExternalThing *) to_hp)->node->refc, 2);
2530
2438
 
2531
2439
        ((ExternalThing *) to_hp)->next = *etpp;
2532
2440
        *etpp = (ExternalThing *) to_hp;
2561
2469
    return store_external_or_ref_(&hp, &MSO(proc).externals, ns);
2562
2470
}
2563
2471
 
2564
 
static int dcount;
2565
 
 
2566
 
/* 
2567
 
 * Display a term.
2568
 
 */
2569
 
 
2570
 
static int 
2571
 
display1(Eterm obj, CIO fd)
2572
 
{
2573
 
    int i, k;
2574
 
    Uint32 *ref_num;
2575
 
    Eterm* nobj;
2576
 
 
2577
 
    if (dcount-- <= 0) return(1);
2578
 
 
2579
 
    if (is_CP(obj)) {
2580
 
        erl_printf(fd, "<cp/header:%08lX>", (unsigned long) obj);
2581
 
        return 0;
2582
 
    }
2583
 
 
2584
 
    switch (tag_val_def(obj)) {
2585
 
    case NIL_DEF:
2586
 
        erl_printf(fd, "[]");
2587
 
        break;
2588
 
    case ATOM_DEF:
2589
 
        print_atom((int)atom_val(obj),fd);
2590
 
        break;
2591
 
    case SMALL_DEF:
2592
 
        erl_printf(fd, "%d", signed_val(obj));
2593
 
        break;
2594
 
    case BIG_DEF:
2595
 
        nobj = big_val(obj);
2596
 
        i = BIG_SIZE(nobj);
2597
 
        if (BIG_SIGN(nobj)) {
2598
 
            erl_printf(fd, "-16#", i);
2599
 
        } else {
2600
 
            erl_printf(fd, "16#", i);
2601
 
        }
2602
 
        for (k = i-1; k >= 0; k--) {
2603
 
            erl_printf(fd, "%0X", BIG_DIGIT(nobj, k));
2604
 
        }
2605
 
        break;
2606
 
    case REF_DEF:
2607
 
        erl_printf(fd, "#Ref<%lu", internal_ref_channel_no(obj));
2608
 
        ref_num = internal_ref_numbers(obj);
2609
 
        for (i = internal_ref_no_of_numbers(obj)-1; i >= 0; i--)
2610
 
            erl_printf(fd, ".%lu", (unsigned long) ref_num[i]);
2611
 
        erl_printf(fd, ">");
2612
 
        break;
2613
 
    case EXTERNAL_REF_DEF:
2614
 
        erl_printf(fd, "#Ref<%lu", external_ref_channel_no(obj));
2615
 
        ref_num = external_ref_numbers(obj);
2616
 
        for (i = external_ref_no_of_numbers(obj)-1; i >= 0; i--)
2617
 
            erl_printf(fd, ".%lu", (unsigned long) ref_num[i]);
2618
 
        erl_printf(fd, ">");
2619
 
        break;
2620
 
    case PID_DEF:
2621
 
    case EXTERNAL_PID_DEF:
2622
 
        erl_printf(fd, "<%lu.%lu.%lu>",
2623
 
                   (unsigned long) pid_channel_no(obj),
2624
 
                   (unsigned long) pid_number(obj),
2625
 
                   (unsigned long) pid_serial(obj));
2626
 
        break;
2627
 
    case PORT_DEF:
2628
 
    case EXTERNAL_PORT_DEF:
2629
 
        erl_printf(fd, "#Port<%lu.%lu>",
2630
 
                   (unsigned long) port_channel_no(obj),
2631
 
                   (unsigned long) port_number(obj));
2632
 
        break;
2633
 
    case LIST_DEF:
2634
 
        if (is_printable_string(obj)) {
2635
 
           int c;
2636
 
           erl_putc('"', fd);
2637
 
           nobj = list_val(obj);
2638
 
           while (1) {
2639
 
              if (dcount-- <= 0) return(1);
2640
 
              c = signed_val(*nobj++);
2641
 
              if (c == '\n') {
2642
 
                 erl_putc('\\', fd);
2643
 
                 erl_putc('n', fd);
2644
 
              } else {
2645
 
                 if (c == '"')
2646
 
                    erl_putc('\\', fd);
2647
 
                 erl_putc(c, fd);
2648
 
              }
2649
 
              if (is_not_list(*nobj)) break;
2650
 
              nobj = list_val(*nobj);
2651
 
           }
2652
 
           erl_putc('"', fd);
2653
 
        } else {
2654
 
           erl_putc('[', fd);
2655
 
           nobj = list_val(obj);
2656
 
           while (1) {
2657
 
              if (display1(*nobj++, fd) != 0) return(1);
2658
 
              if (is_not_list(*nobj)) break;
2659
 
              erl_putc(',',fd);
2660
 
              nobj = list_val(*nobj);
2661
 
           }
2662
 
           if (is_not_nil(*nobj)) {
2663
 
              erl_putc('|', fd);
2664
 
              if (display1(*nobj, fd) != 0) return(1);
2665
 
           }
2666
 
           erl_putc(']', fd);
2667
 
        }
2668
 
        break;
2669
 
    case TUPLE_DEF:
2670
 
        nobj = tuple_val(obj);  /* pointer to arity */
2671
 
        i = arityval(*nobj);    /* arity */
2672
 
        erl_putc('{', fd);
2673
 
        while (i--) {
2674
 
            if (display1(*++nobj,fd) != 0) return(1);
2675
 
            if (i >= 1) erl_putc(',',fd);
2676
 
        }
2677
 
        erl_putc('}',fd);
2678
 
        break;
2679
 
    case FLOAT_DEF: {
2680
 
            FloatDef ff;
2681
 
            GET_DOUBLE(obj, ff);
2682
 
#ifdef _OSE_
2683
 
            erl_printf(fd, "%e", ff.fd);
2684
 
#else
2685
 
            erl_printf(fd, "%e", ff.fd);
2686
 
#endif
2687
 
        }
2688
 
        break;
2689
 
    case BINARY_DEF:
2690
 
        {
2691
 
            ProcBin* pb = (ProcBin *) binary_val(obj);
2692
 
            erl_printf(fd, pb->size == 1 ? "<<%lu byte>>" : "<<%lu bytes>>",
2693
 
                       (unsigned long) pb->size);
2694
 
        }
2695
 
        break;
2696
 
    case FUN_DEF:
2697
 
        {
2698
 
            ErlFunThing* funp = (ErlFunThing *) fun_val(obj);
2699
 
            Atom* ap;
2700
 
 
2701
 
            erl_printf(fd, "#Fun<");
2702
 
            ap = atom_tab(atom_val(funp->fe->module));
2703
 
            for (i = 0; i < ap->len; i++) {
2704
 
                erl_putc(ap->name[i], fd);
2705
 
            }
2706
 
            erl_printf(fd, ".%d.%d>", funp->fe->old_index,
2707
 
                       funp->fe->old_uniq);
2708
 
        }
2709
 
        break;
2710
 
    case VECTOR_DEF:
2711
 
        erl_printf(fd, "#Vector<%ld>", (long) signed_val(vector_val(obj)[1]));
2712
 
        break;
2713
 
    default:
2714
 
        erl_printf(fd, "<unknown:%lx>", (unsigned long) obj);
2715
 
    }
2716
 
    return(0);
2717
 
}
2718
 
 
2719
 
 
2720
 
/*
2721
 
 * Display a term on file fd.
2722
 
 * Only used by debugging rountines as Erlang formatting is 
2723
 
 * done in the io module.
2724
 
 */
2725
 
 
2726
 
void
2727
 
display(Eterm obj, CIO fd)
2728
 
{
2729
 
    dcount = 100000;
2730
 
    display1(obj, fd);
2731
 
}
2732
 
 
2733
 
 
2734
 
/* as above, but limit the number of items printed */
2735
 
void ldisplay(Eterm obj, CIO fd, int count)
2736
 
{
2737
 
    dcount = count;
2738
 
    display1(obj, fd);
2739
 
    if (dcount <= 0) erl_printf(fd, "... "); /* Show that more items exist */
2740
 
}
2741
 
 
2742
 
 
2743
 
/* print a name doing what quoting is necessary */
2744
 
static void print_name(byte *s, int n, CIO fd)
2745
 
{
2746
 
    
2747
 
    int need_quote;
2748
 
    int pos;
2749
 
    byte *cpos;
2750
 
    int c;
2751
 
 
2752
 
    if (n == 0) {
2753
 
        erl_printf(fd, "''");
2754
 
        return;
2755
 
    }
2756
 
 
2757
 
    need_quote = 0;
2758
 
    cpos = s;
2759
 
    pos = n - 1;
2760
 
 
2761
 
    c = *cpos++;
2762
 
    if (!IS_LOWER(c))
2763
 
        need_quote++;
2764
 
    else {
2765
 
        while (pos--) {
2766
 
            c = *cpos++;
2767
 
            if (!IS_ALNUM(c) && (c != '_')) {
2768
 
                need_quote++;
2769
 
                break;
2770
 
            }
2771
 
        }
2772
 
    }
2773
 
    cpos = s;
2774
 
    pos = n;
2775
 
    if (need_quote)
2776
 
        erl_putc('\'',fd);
2777
 
    while(pos--) {
2778
 
        c = *cpos++;
2779
 
        switch(c) {
2780
 
        case '\'': erl_printf(fd, "\\'"); break;
2781
 
        case '\\': erl_printf(fd, "\\\\"); break;
2782
 
        case '\n': erl_printf(fd, "\\n"); break;
2783
 
        case '\f': erl_printf(fd, "\\f"); break;
2784
 
        case '\t': erl_printf(fd, "\\t"); break;
2785
 
        case '\r': erl_printf(fd, "\\r"); break;
2786
 
        case '\b': erl_printf(fd, "\\b"); break;
2787
 
        case '\v': erl_printf(fd, "\\v"); break;
2788
 
        default:
2789
 
            if (IS_CNTRL(c))
2790
 
                erl_printf(fd, "\\%03o", c);
2791
 
            else
2792
 
                erl_putc(c, fd);
2793
 
            break;
2794
 
        }
2795
 
    }
2796
 
    if (need_quote) 
2797
 
        erl_putc('\'',fd);
2798
 
}
2799
 
 
2800
 
/* print the text of an atom with number i on open file descriptor fd */
2801
 
void
2802
 
print_atom(int i, CIO fd)
2803
 
{
2804
 
    if ((i < 0) || (i >= atom_table_size) ||  (atom_tab(i) == NULL)) {
2805
 
        erl_printf(fd, "<bad atom index: %d>", i);
2806
 
    }
2807
 
    print_name(atom_tab(i)->name, atom_tab(i)->len, fd);
2808
 
    dcount -= atom_tab(i)->len;
2809
 
}
2810
 
 
2811
2472
/* 
2812
2473
 *  member(X,Y)
2813
2474
 *  returns 0 if X is a member of list Y
2830
2491
    }
2831
2492
}
2832
2493
 
2833
 
void bin_write(fp,buf,sz)
2834
 
CIO fp; byte* buf;
2835
 
int sz;
 
2494
void bin_write(int to, void *to_arg, byte* buf, int sz)
2836
2495
{
2837
2496
    int i;
2838
2497
 
2839
2498
    for (i=0;i<sz;i++) {
2840
2499
        if (IS_DIGIT(buf[i]))
2841
 
            erl_printf(fp, "%d,", buf[i]);
 
2500
            erts_print(to, to_arg, "%d,", buf[i]);
2842
2501
        else if (IS_PRINT(buf[i])) {
2843
 
            erl_putc(buf[i],fp);
2844
 
            erl_putc(',',fp);
 
2502
            erts_print(to, to_arg, "%c,", buf[i]);
2845
2503
        }
2846
2504
        else
2847
 
            erl_printf(fp,"%d,", buf[i]);
 
2505
            erts_print(to, to_arg, "%d,", buf[i]);
2848
2506
    }
2849
 
    erl_putc('\n',fp);
 
2507
    erts_putc(to, to_arg, '\n');
2850
2508
}
2851
2509
 
2852
2510
/* Fill buf with the contents of bytelist list 
2853
2511
   return number of chars in list or -1 for error */
2854
2512
 
2855
2513
int
2856
 
intlist_to_buf(Eterm list, byte *buf, int len)
 
2514
intlist_to_buf(Eterm list, char *buf, int len)
2857
2515
{
2858
2516
    Eterm* listptr;
2859
2517
    int sz = 0;
2878
2536
}
2879
2537
 
2880
2538
/*
2881
 
** Convert an integer to a byte list buf must have at least 12 bytes avaiable
 
2539
** Convert an integer to a byte list
2882
2540
** return pointer to converted stuff (need not to be at start of buf!)
2883
2541
*/
2884
 
char* int_to_buf(n, buf)
2885
 
int n; char* buf;
 
2542
char* Sint_to_buf(Sint n, struct Sint_buf *buf)
2886
2543
{
2887
 
    char* p = buf+11;
 
2544
    char* p = &buf->s[sizeof(buf->s)-1];
2888
2545
    int sign = 0;
2889
2546
 
2890
2547
    *p-- = '\0'; /* null terminate */
2911
2568
*/
2912
2569
 
2913
2570
Eterm
2914
 
buf_to_intlist(Eterm** hpp, byte *buf, int len, Eterm tail)
 
2571
buf_to_intlist(Eterm** hpp, char *buf, int len, Eterm tail)
2915
2572
{
2916
2573
    Eterm* hp = *hpp;
2917
2574
 
2927
2584
}
2928
2585
 
2929
2586
/*
2930
 
** write io list in to a buffer.
 
2587
** Write io list in to a buffer.
2931
2588
**
2932
 
** A iolist is defined as:
 
2589
** An iolist is defined as:
2933
2590
**
2934
2591
** iohead ::= Binary
2935
2592
**        |   Byte (i.e integer in range [0..255]
2946
2603
**        |   [ iohead | iotail]
2947
2604
**        ;
2948
2605
** 
2949
 
** Return remaing bytes in buffer on succsess
 
2606
** Return remaning bytes in buffer on success
2950
2607
**        -1 on overflow
2951
 
**        -2 on type error
 
2608
**        -2 on type error (including that result would not be a whole number of bytes)
2952
2609
*/
2953
2610
 
2954
2611
int io_list_to_buf(Eterm obj, char* buf, int len)
2955
2612
{
2956
2613
    Eterm* objp;
2957
 
    DECLARE_ESTACK(s);
2958
 
    goto L_again;
2959
 
 
2960
 
    while (!ESTACK_ISEMPTY(s)) {
2961
 
        obj = ESTACK_POP(s);
2962
 
    L_again:
2963
 
        if (is_list(obj)) {
2964
 
        L_iter_list:
2965
 
            objp = list_val(obj);
2966
 
            obj = CAR(objp);
2967
 
            if (is_byte(obj)) {
2968
 
                if (len == 0)
2969
 
                    goto L_overflow;
2970
 
                *buf++ = unsigned_val(obj);
2971
 
                len--;
2972
 
            } else if (is_binary(obj)) {
2973
 
                byte* bytes;
2974
 
                size_t size = binary_size(obj);
2975
 
                if (len < size) {
2976
 
                    goto L_overflow;
2977
 
                }
2978
 
                GET_BINARY_BYTES(obj, bytes);
2979
 
                sys_memcpy(buf, bytes, size);
2980
 
                buf += size;
2981
 
                len -= size;
2982
 
            }
2983
 
            else if (is_nil(obj)) {
2984
 
                ;
2985
 
            }
2986
 
            else if (is_list(obj)) {
2987
 
                ESTACK_PUSH(s, CDR(objp));
2988
 
                goto L_iter_list; /* on head */
2989
 
            }
2990
 
            else
2991
 
                goto L_type_error;
2992
 
 
2993
 
            obj = CDR(objp);
2994
 
            if (is_list(obj))
2995
 
                goto L_iter_list; /* on tail */
2996
 
            else if (is_binary(obj)) {
2997
 
                byte* bytes;
2998
 
                size_t size = binary_size(obj);
2999
 
                if (len < size) {
3000
 
                    goto L_overflow;
3001
 
                }
3002
 
                GET_BINARY_BYTES(obj, bytes);
3003
 
                sys_memcpy(buf, bytes, size);
3004
 
                buf += size;
3005
 
                len -= size;
 
2614
    int offset = 0;
 
2615
    DECLARE_ESTACK(s);
 
2616
    goto L_again;
 
2617
    
 
2618
    while (!ESTACK_ISEMPTY(s)) {
 
2619
        obj = ESTACK_POP(s);
 
2620
    L_again:
 
2621
        if (is_list(obj)) {
 
2622
        L_iter_list:
 
2623
            objp = list_val(obj);
 
2624
            obj = CAR(objp);
 
2625
            if (is_byte(obj)) {
 
2626
                if (len == 0)
 
2627
                    goto L_overflow;
 
2628
                if (offset == 0) {
 
2629
                    *buf++ = unsigned_val(obj);
 
2630
                } else {
 
2631
                    *buf =  (char)((unsigned_val(obj) >> offset) & *buf);
 
2632
                    buf++;
 
2633
                    *buf = (unsigned_val(obj) << (8-offset));
 
2634
                }   
 
2635
                len--;
 
2636
            } else if (is_binary(obj)) {
 
2637
                byte* bptr;
 
2638
                size_t size = binary_size(obj);
 
2639
                Uint bitsize;
 
2640
                Uint bitoffs;
 
2641
                Uint num_bits;
 
2642
                
 
2643
                if (len < size) {
 
2644
                    goto L_overflow;
 
2645
                }
 
2646
                ERTS_GET_BINARY_BYTES(obj, bptr, bitoffs, bitsize);
 
2647
                num_bits = 8*size+bitsize;
 
2648
                copy_binary_to_buffer(buf, offset, bptr, bitoffs, num_bits);
 
2649
                offset += bitsize;
 
2650
                buf += size+(offset>7);
 
2651
                len -= size+(offset>7);
 
2652
                offset = offset & 7;
 
2653
            }
 
2654
            else if (is_nil(obj)) {
 
2655
                ;
 
2656
            }
 
2657
            else if (is_list(obj)) {
 
2658
                ESTACK_PUSH(s, CDR(objp));
 
2659
                goto L_iter_list; /* on head */
 
2660
            }
 
2661
            else
 
2662
                goto L_type_error;
 
2663
 
 
2664
            obj = CDR(objp);
 
2665
            if (is_list(obj))
 
2666
                goto L_iter_list; /* on tail */
 
2667
            else if (is_binary(obj)) {
 
2668
                byte* bptr;
 
2669
                size_t size = binary_size(obj);
 
2670
                Uint bitsize;
 
2671
                Uint bitoffs;
 
2672
                Uint num_bits;
 
2673
                if (len < size) {
 
2674
                    goto L_overflow;
 
2675
                }
 
2676
                ERTS_GET_BINARY_BYTES(obj, bptr, bitoffs, bitsize);
 
2677
                num_bits = 8*size+bitsize;
 
2678
                copy_binary_to_buffer(buf, offset, bptr, bitoffs, num_bits);
 
2679
                offset += bitsize;
 
2680
                buf += size+(offset>7);
 
2681
                len -= size+(offset>7);
 
2682
                offset = offset & 7;
 
2683
            } else if (is_nil(obj)) {
 
2684
                ;
 
2685
            } else {
 
2686
                goto L_type_error;
 
2687
            }
 
2688
        } else if (is_binary(obj)) {
 
2689
            byte* bptr;
 
2690
            size_t size = binary_size(obj);
 
2691
            Uint bitsize;
 
2692
            Uint bitoffs;
 
2693
            Uint num_bits;
 
2694
            if (len < size) {
 
2695
                goto L_overflow;
 
2696
            }
 
2697
            ERTS_GET_BINARY_BYTES(obj, bptr, bitoffs, bitsize);
 
2698
            num_bits = 8*size+bitsize;
 
2699
            copy_binary_to_buffer(buf, offset, bptr, bitoffs, num_bits);
 
2700
            offset += bitsize;
 
2701
            buf += size+(offset>7);
 
2702
            len -= size+(offset>7);
 
2703
            offset = offset & 7;
 
2704
        } else if (is_not_nil(obj)) {
 
2705
            goto L_type_error;
 
2706
        }
 
2707
    }
 
2708
      
 
2709
    DESTROY_ESTACK(s);
 
2710
    if (offset) {
 
2711
        return -2;
 
2712
    }
 
2713
    return len;
 
2714
 
 
2715
 L_type_error:
 
2716
    DESTROY_ESTACK(s);
 
2717
    return -2;
 
2718
 
 
2719
 L_overflow:
 
2720
    DESTROY_ESTACK(s);
 
2721
    return -1;
 
2722
}
 
2723
 
 
2724
int io_list_to_buf2(Eterm obj, char* buf, int len)
 
2725
{
 
2726
    Eterm* objp;
 
2727
    int offset=0;
 
2728
    DECLARE_ESTACK(s);
 
2729
    goto L_again;
 
2730
    
 
2731
    while (!ESTACK_ISEMPTY(s)) {
 
2732
        obj = ESTACK_POP(s);
 
2733
    L_again:
 
2734
        if (is_list(obj)) {
 
2735
        L_iter_list:
 
2736
            objp = list_val(obj);
 
2737
            obj = CAR(objp);
 
2738
            if (is_byte(obj)) {
 
2739
                if (len == 0)
 
2740
                    goto L_overflow;
 
2741
                if (offset==0) {
 
2742
                    *buf++ = unsigned_val(obj);
 
2743
                } else {
 
2744
                    *buf =  (char)((unsigned_val(obj) >> offset) | 
 
2745
                                   ((*buf >> (8-offset)) << (8-offset)));
 
2746
                    buf++;
 
2747
                    *buf = (unsigned_val(obj) << (8-offset));
 
2748
                }   
 
2749
                len--;
 
2750
            } else if (is_binary(obj)) {
 
2751
                byte* bptr;
 
2752
                size_t size = binary_size(obj);
 
2753
                Uint bitsize;
 
2754
                Uint bitoffs;
 
2755
                Uint num_bits;
 
2756
                
 
2757
                if (len < size) {
 
2758
                    goto L_overflow;
 
2759
                }
 
2760
                ERTS_GET_BINARY_BYTES(obj, bptr, bitoffs, bitsize);
 
2761
                num_bits = 8*size+bitsize;
 
2762
                copy_binary_to_buffer(buf, offset, bptr, bitoffs, num_bits);
 
2763
                offset += bitsize;
 
2764
                buf += size+(offset>7);
 
2765
                len -= size+(offset>7);
 
2766
                offset = offset & 7;
 
2767
            }
 
2768
            else if (is_nil(obj)) {
 
2769
                ;
 
2770
            }
 
2771
            else if (is_list(obj)) {
 
2772
                ESTACK_PUSH(s, CDR(objp));
 
2773
                goto L_iter_list; /* on head */
 
2774
            }
 
2775
            else
 
2776
                goto L_type_error;
 
2777
 
 
2778
            obj = CDR(objp);
 
2779
            if (is_list(obj))
 
2780
                goto L_iter_list; /* on tail */
 
2781
            else if (is_binary(obj)) {
 
2782
                byte* bptr;
 
2783
                size_t size = binary_size(obj);
 
2784
                Uint bitsize;
 
2785
                Uint bitoffs;
 
2786
                Uint num_bits;
 
2787
                if (len < size) {
 
2788
                    goto L_overflow;
 
2789
                }
 
2790
                ERTS_GET_BINARY_BYTES(obj, bptr, bitoffs, bitsize);
 
2791
                num_bits = 8*size+bitsize;
 
2792
                copy_binary_to_buffer(buf, offset, bptr, bitoffs, num_bits);
 
2793
                offset += bitsize;
 
2794
                buf += size+(offset>7);
 
2795
                len -= size+(offset>7);
 
2796
                offset = offset & 7;
 
2797
                
3006
2798
            }
3007
2799
            else if (is_nil(obj))
3008
2800
                ;
3009
2801
            else
3010
2802
                goto L_type_error;
3011
2803
        } else if (is_binary(obj)) {
3012
 
            byte* bytes;
 
2804
            byte* bptr;
3013
2805
            size_t size = binary_size(obj);
 
2806
            Uint bitsize;
 
2807
            Uint bitoffs;
 
2808
            Uint num_bits;
3014
2809
            if (len < size) {
3015
2810
                goto L_overflow;
3016
2811
            }
3017
 
            GET_BINARY_BYTES(obj, bytes);
3018
 
            sys_memcpy(buf, bytes, size);
3019
 
            buf += size;
3020
 
            len -= size;
 
2812
            ERTS_GET_BINARY_BYTES(obj, bptr, bitoffs, bitsize);
 
2813
            num_bits = 8*size+bitsize;
 
2814
            copy_binary_to_buffer(buf, offset, bptr, bitoffs, num_bits);
 
2815
            offset += bitsize;
 
2816
            buf += size+(offset>7);
 
2817
            len -= size+(offset>7);
 
2818
            offset = offset & 7;
3021
2819
        } else if (is_not_nil(obj)) {
3022
2820
            goto L_type_error;
3023
2821
        }
3024
2822
    }
3025
 
 
 
2823
    
3026
2824
    DESTROY_ESTACK(s);
3027
 
    return len;
 
2825
    return offset;
3028
2826
 
3029
2827
 L_type_error:
3030
2828
    DESTROY_ESTACK(s);
3039
2837
{
3040
2838
    Eterm* objp;
3041
2839
    int len = 0;
 
2840
    int offs = 0;
3042
2841
    DECLARE_ESTACK(s);
3043
2842
    goto L_again;
3044
2843
 
3054
2853
                len++;
3055
2854
            } else if (is_binary(obj)) {
3056
2855
                len += binary_size(obj);
 
2856
                offs += binary_bitsize(obj);
 
2857
                if (offs > 8) { len+=1; offs-=8;}
3057
2858
            } else if (is_nil(obj)) {
3058
2859
                ;
3059
2860
            } else if (is_list(obj)) {
3075
2876
            }
3076
2877
        } else if (is_binary(obj)) { /* Tail was binary */
3077
2878
            len += binary_size(obj);
 
2879
            offs = binary_bitsize(obj);
 
2880
            if (offs > 8) { len+=1; offs-=8;}
3078
2881
        } else if (is_not_nil(obj)) {
3079
2882
            goto L_type_error;
3080
2883
        }
3081
2884
    }
3082
2885
 
3083
2886
    DESTROY_ESTACK(s);
3084
 
    return len;
 
2887
    return len+(offs>0);
3085
2888
 
3086
2889
 L_type_error:
3087
2890
    DESTROY_ESTACK(s);
3141
2944
    return 0;
3142
2945
}
3143
2946
 
3144
 
/* return 0 if item is not a non-empty flat list of printable characters */
3145
 
 
3146
 
static int
3147
 
is_printable_string(Eterm list)
3148
 
{
3149
 
    int len = 0;
3150
 
    int c;
3151
 
 
3152
 
    while(is_list(list)) {
3153
 
        Eterm* consp = list_val(list);
3154
 
        Eterm hd = CAR(consp);
3155
 
 
3156
 
        if (!is_byte(hd))
3157
 
            return 0;
3158
 
        c = signed_val(hd);
3159
 
        /* IS_PRINT || IS_SPACE would be another way to put it */
3160
 
        if (IS_CNTRL(c) && !IS_SPACE(c))
3161
 
           return 0;
3162
 
        len++;
3163
 
        list = CDR(consp);
3164
 
    }
3165
 
    if (is_nil(list))
3166
 
        return len;
3167
 
    return 0;
3168
 
}
3169
 
 
3170
 
Uint erts_sys_misc_mem_sz;
 
2947
#ifdef ERTS_SMP
 
2948
 
 
2949
/*
 
2950
 * Process and Port timers in smp case
 
2951
 */
 
2952
 
 
2953
ERTS_SMP_PALLOC_IMPL(ptimer_pre, ErtsSmpPTimer, 1000)
 
2954
 
 
2955
#define ERTS_PTMR_FLGS_ALLCD_SIZE \
 
2956
  2
 
2957
#define ERTS_PTMR_FLGS_ALLCD_MASK \
 
2958
  ((((Uint32) 1) << ERTS_PTMR_FLGS_ALLCD_SIZE) - 1)
 
2959
 
 
2960
#define ERTS_PTMR_FLGS_PREALLCD ((Uint32) 1)
 
2961
#define ERTS_PTMR_FLGS_SLALLCD  ((Uint32) 2)
 
2962
#define ERTS_PTMR_FLGS_LLALLCD  ((Uint32) 3)
 
2963
#define ERTS_PTMR_FLG_CANCELLED (((Uint32) 1) << (ERTS_PTMR_FLGS_ALLCD_SIZE+0))
 
2964
 
 
2965
static void
 
2966
init_ptimers(void)
 
2967
{
 
2968
    init_ptimer_pre_alloc();
 
2969
}
 
2970
 
 
2971
static ERTS_INLINE void
 
2972
free_ptimer(ErtsSmpPTimer *ptimer)
 
2973
{
 
2974
    switch (ptimer->timer.flags & ERTS_PTMR_FLGS_ALLCD_MASK) {
 
2975
    case ERTS_PTMR_FLGS_PREALLCD:
 
2976
        (void) ptimer_pre_free(ptimer);
 
2977
        break;
 
2978
    case ERTS_PTMR_FLGS_SLALLCD:
 
2979
        erts_free(ERTS_ALC_T_SL_PTIMER, (void *) ptimer);
 
2980
        break;
 
2981
    case ERTS_PTMR_FLGS_LLALLCD:
 
2982
        erts_free(ERTS_ALC_T_LL_PTIMER, (void *) ptimer);
 
2983
        break;
 
2984
    default:
 
2985
        erl_exit(ERTS_ABORT_EXIT,
 
2986
                 "Internal error: Bad ptimer alloc type\n");
 
2987
        break;
 
2988
    }
 
2989
}
 
2990
 
 
2991
/* Callback for process timeout cancelled */
 
2992
static void
 
2993
ptimer_cancelled(ErtsSmpPTimer *ptimer)
 
2994
{
 
2995
    free_ptimer(ptimer);
 
2996
}
 
2997
 
 
2998
/* Callback for process timeout */
 
2999
static void
 
3000
ptimer_timeout(ErtsSmpPTimer *ptimer)
 
3001
{
 
3002
    if (!(ptimer->timer.flags & ERTS_PTMR_FLG_CANCELLED)) {
 
3003
        if (is_internal_pid(ptimer->timer.id)) {
 
3004
            Process *p;
 
3005
            p = erts_pid2proc(NULL,
 
3006
                              0,
 
3007
                              ptimer->timer.id,
 
3008
                              ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS);
 
3009
            if (p) {
 
3010
                if (!(ptimer->timer.flags & ERTS_PTMR_FLG_CANCELLED)) {
 
3011
                    ASSERT(*ptimer->timer.timer_ref == ptimer);
 
3012
                    *ptimer->timer.timer_ref = NULL;
 
3013
                    (*ptimer->timer.timeout_func)(p);
 
3014
                }
 
3015
                erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS);
 
3016
            }
 
3017
        }
 
3018
        else {
 
3019
            Port *p;
 
3020
            ASSERT(is_internal_port(ptimer->timer.id));
 
3021
            p = erts_id2port(ptimer->timer.id, NULL, 0);
 
3022
            if (p) {
 
3023
                if (!(ptimer->timer.flags & ERTS_PTMR_FLG_CANCELLED)) {
 
3024
                    ASSERT(*ptimer->timer.timer_ref == ptimer);
 
3025
                    *ptimer->timer.timer_ref = NULL;
 
3026
                    (*ptimer->timer.timeout_func)(p);
 
3027
                }
 
3028
                erts_smp_io_unlock();
 
3029
            }
 
3030
        }
 
3031
    }
 
3032
    free_ptimer(ptimer);
 
3033
}
 
3034
 
 
3035
void
 
3036
erts_create_smp_ptimer(ErtsSmpPTimer **timer_ref,
 
3037
                       Eterm id,
 
3038
                       ErlTimeoutProc timeout_func,
 
3039
                       Uint timeout)
 
3040
{
 
3041
    ErtsSmpPTimer *res = ptimer_pre_alloc();
 
3042
    if (res)
 
3043
        res->timer.flags = ERTS_PTMR_FLGS_PREALLCD;
 
3044
    else {
 
3045
        if (timeout < ERTS_ALC_MIN_LONG_LIVED_TIME) {
 
3046
            res = erts_alloc(ERTS_ALC_T_SL_PTIMER, sizeof(ErtsSmpPTimer));
 
3047
            res->timer.flags = ERTS_PTMR_FLGS_SLALLCD;
 
3048
        }
 
3049
        else {
 
3050
            res = erts_alloc(ERTS_ALC_T_LL_PTIMER, sizeof(ErtsSmpPTimer));
 
3051
            res->timer.flags = ERTS_PTMR_FLGS_LLALLCD;
 
3052
        }
 
3053
    }
 
3054
    res->timer.timeout_func = timeout_func;
 
3055
    res->timer.timer_ref = timer_ref;
 
3056
    res->timer.id = id;
 
3057
    res->timer.tm.active = 0; /* MUST be initalized */
 
3058
 
 
3059
    ASSERT(!*timer_ref);
 
3060
 
 
3061
    *timer_ref = res;
 
3062
 
 
3063
    erl_set_timer(&res->timer.tm,
 
3064
                  (ErlTimeoutProc) ptimer_timeout,
 
3065
                  (ErlCancelProc) ptimer_cancelled,
 
3066
                  (void*) res,
 
3067
                  timeout);
 
3068
}
 
3069
 
 
3070
void
 
3071
erts_cancel_smp_ptimer(ErtsSmpPTimer *ptimer)
 
3072
{
 
3073
    if (ptimer) {
 
3074
        ASSERT(*ptimer->timer.timer_ref == ptimer);
 
3075
        *ptimer->timer.timer_ref = NULL;
 
3076
        ptimer->timer.flags |= ERTS_PTMR_FLG_CANCELLED;
 
3077
        erl_cancel_timer(&ptimer->timer.tm);
 
3078
    }
 
3079
}
 
3080
 
 
3081
#endif
3171
3082
 
3172
3083
static Sint trim_threshold;
3173
3084
static Sint top_pad;
3178
3089
 
3179
3090
void erts_init_utils(void)
3180
3091
{
3181
 
 
 
3092
#ifdef ERTS_SMP
 
3093
    init_ptimers();
 
3094
#endif
3182
3095
}
3183
3096
 
3184
3097
void erts_init_utils_mem(void) 
3185
3098
{
3186
 
    erts_sys_misc_mem_sz = 0;
3187
3099
    trim_threshold = -1;
3188
3100
    top_pad = -1;
3189
3101
    mmap_threshold = -1;
3254
3166
 
3255
3167
}
3256
3168
 
 
3169
#ifdef ERTS_SMP
 
3170
 
 
3171
/* Local system block state */
 
3172
struct {
 
3173
    int emergency;
 
3174
    int threads_to_block;
 
3175
    int have_blocker;
 
3176
    erts_smp_tid_t blocker_tid;
 
3177
    int recursive_block;
 
3178
    Uint32 allowed_activities;
 
3179
    erts_smp_tsd_key_t blockable_key;
 
3180
    erts_smp_mtx_t mtx;
 
3181
    erts_smp_cnd_t cnd;
 
3182
#ifdef ERTS_ENABLE_LOCK_CHECK
 
3183
    int activity_changing;
 
3184
    int checking;
 
3185
#endif
 
3186
} system_block_state;
 
3187
 
 
3188
/* Global system block state */
 
3189
erts_system_block_state_t erts_system_block_state;
 
3190
 
 
3191
 
 
3192
static ERTS_INLINE int
 
3193
is_blockable_thread(void)
 
3194
{
 
3195
    return erts_smp_tsd_get(system_block_state.blockable_key) != NULL;
 
3196
}
 
3197
 
 
3198
static ERTS_INLINE int
 
3199
is_blocker(void)
 
3200
{
 
3201
    return (system_block_state.have_blocker
 
3202
            && erts_smp_equal_tids(system_block_state.blocker_tid,
 
3203
                                   erts_smp_thr_self()));
 
3204
}
 
3205
 
 
3206
static ERTS_INLINE void
 
3207
block_me(void (*prepare)(void *),
 
3208
         void (*resume)(void *),
 
3209
         void *arg,
 
3210
         int mtx_locked,
 
3211
         int want_to_block,
 
3212
         int update_act_changing)
 
3213
{
 
3214
 
 
3215
    if (prepare)
 
3216
        (*prepare)(arg);
 
3217
 
 
3218
    /* Locks might be held... */
 
3219
 
 
3220
    if (!mtx_locked)
 
3221
        erts_smp_mtx_lock(&system_block_state.mtx);
 
3222
 
 
3223
    if (erts_smp_pending_system_block() && !is_blocker()) {
 
3224
        int is_blockable = is_blockable_thread();
 
3225
        ASSERT(is_blockable);
 
3226
 
 
3227
        if (is_blockable)
 
3228
            system_block_state.threads_to_block--;
 
3229
#ifdef ERTS_ENABLE_LOCK_CHECK
 
3230
        if (update_act_changing)
 
3231
            system_block_state.activity_changing--;
 
3232
#endif
 
3233
        erts_smp_cnd_broadcast(&system_block_state.cnd);
 
3234
 
 
3235
        do {
 
3236
            erts_smp_cnd_wait(&system_block_state.cnd, &system_block_state.mtx);
 
3237
        } while (erts_smp_pending_system_block()
 
3238
                 && !(want_to_block && !system_block_state.have_blocker));
 
3239
#ifdef ERTS_ENABLE_LOCK_CHECK
 
3240
        if (update_act_changing)
 
3241
            system_block_state.activity_changing++;
 
3242
#endif
 
3243
        if (is_blockable)
 
3244
            system_block_state.threads_to_block++;
 
3245
    }
 
3246
 
 
3247
    if (!mtx_locked)
 
3248
        erts_smp_mtx_unlock(&system_block_state.mtx);
 
3249
 
 
3250
    if (resume)
 
3251
        (*resume)(arg);
 
3252
}
 
3253
 
 
3254
void
 
3255
erts_block_me(void (*prepare)(void *),
 
3256
              void (*resume)(void *),
 
3257
              void *arg)
 
3258
{
 
3259
    if (prepare)
 
3260
        (*prepare)(arg);
 
3261
 
 
3262
#ifdef ERTS_ENABLE_LOCK_CHECK
 
3263
    erts_lc_check_exact(NULL, 0); /* No locks should be locked */
 
3264
#endif
 
3265
 
 
3266
    block_me(NULL, NULL, NULL, 0, 0, 0);
 
3267
 
 
3268
    if (resume)
 
3269
        (*resume)(arg);
 
3270
}
 
3271
 
 
3272
void
 
3273
erts_register_blockable_thread(void)
 
3274
{
 
3275
    if (!is_blockable_thread()) {
 
3276
        erts_smp_mtx_lock(&system_block_state.mtx);
 
3277
        system_block_state.threads_to_block++;
 
3278
        erts_smp_tsd_set(system_block_state.blockable_key,
 
3279
                         (void *) &erts_system_block_state);
 
3280
 
 
3281
        /* Someone might be waiting for us to block... */
 
3282
        if (erts_smp_pending_system_block())
 
3283
            block_me(NULL, NULL, NULL, 1, 0, 0);
 
3284
        erts_smp_mtx_unlock(&system_block_state.mtx);
 
3285
    }
 
3286
}
 
3287
 
 
3288
void
 
3289
erts_unregister_blockable_thread(void)
 
3290
{
 
3291
    if (is_blockable_thread()) {
 
3292
        erts_smp_mtx_lock(&system_block_state.mtx);
 
3293
        system_block_state.threads_to_block--;
 
3294
        ASSERT(system_block_state.threads_to_block >= 0);
 
3295
        erts_smp_tsd_set(system_block_state.blockable_key, NULL);
 
3296
 
 
3297
        /* Someone might be waiting for us to block... */
 
3298
        if (erts_smp_pending_system_block())
 
3299
            erts_smp_cnd_broadcast(&system_block_state.cnd);
 
3300
        erts_smp_mtx_unlock(&system_block_state.mtx);
 
3301
    }
 
3302
}
 
3303
 
 
3304
void
 
3305
erts_note_activity_begin(erts_activity_t activity)
 
3306
{
 
3307
    erts_smp_mtx_lock(&system_block_state.mtx);
 
3308
    if (erts_smp_pending_system_block()) {
 
3309
        Uint32 broadcast = 0;
 
3310
        switch (activity) {
 
3311
        case ERTS_ACTIVITY_GC:
 
3312
            broadcast = (system_block_state.allowed_activities
 
3313
                         & ERTS_BS_FLG_ALLOW_GC);
 
3314
            break;
 
3315
        case ERTS_ACTIVITY_IO:
 
3316
            broadcast = (system_block_state.allowed_activities
 
3317
                         & ERTS_BS_FLG_ALLOW_IO);
 
3318
            break;
 
3319
        case ERTS_ACTIVITY_WAIT:
 
3320
            broadcast = 1;
 
3321
            break;
 
3322
        default:
 
3323
            abort();
 
3324
            break;
 
3325
        }
 
3326
        if (broadcast)
 
3327
            erts_smp_cnd_broadcast(&system_block_state.cnd);
 
3328
    }
 
3329
    erts_smp_mtx_unlock(&system_block_state.mtx);
 
3330
}
 
3331
 
 
3332
void
 
3333
erts_check_block(erts_activity_t old_activity,
 
3334
                 erts_activity_t new_activity,
 
3335
                 int locked,
 
3336
                 void (*prepare)(void *),
 
3337
                 void (*resume)(void *),
 
3338
                 void *arg)
 
3339
{
 
3340
    int do_block;
 
3341
 
 
3342
    if (!locked && prepare)
 
3343
        (*prepare)(arg);
 
3344
 
 
3345
    erts_smp_mtx_lock(&system_block_state.mtx);
 
3346
 
 
3347
    /* First check if it is ok to block... */
 
3348
    if (!locked)
 
3349
        do_block = 1;
 
3350
    else {
 
3351
        switch (old_activity) {
 
3352
        case ERTS_ACTIVITY_UNDEFINED:
 
3353
            do_block = 0;
 
3354
            break;
 
3355
        case ERTS_ACTIVITY_GC:
 
3356
            do_block = (system_block_state.allowed_activities
 
3357
                        & ERTS_BS_FLG_ALLOW_GC);
 
3358
            break;
 
3359
        case ERTS_ACTIVITY_IO:
 
3360
            do_block = (system_block_state.allowed_activities
 
3361
                        & ERTS_BS_FLG_ALLOW_IO);
 
3362
            break;
 
3363
        case ERTS_ACTIVITY_WAIT:
 
3364
            /* You are not allowed to leave activity waiting
 
3365
             * without supplying the possibility to block
 
3366
             * unlocked.
 
3367
             */
 
3368
            erts_set_activity_error(ERTS_ACT_ERR_LEAVE_WAIT_UNLOCKED,
 
3369
                                    __FILE__, __LINE__);
 
3370
            do_block = 0;
 
3371
            break;
 
3372
        default:
 
3373
            erts_set_activity_error(ERTS_ACT_ERR_LEAVE_UNKNOWN_ACTIVITY,
 
3374
                                    __FILE__, __LINE__);
 
3375
            do_block = 0;
 
3376
            break;
 
3377
        }
 
3378
    }
 
3379
 
 
3380
    if (do_block) {
 
3381
        /* ... then check if it is necessary to block... */
 
3382
 
 
3383
        switch (new_activity) {
 
3384
        case ERTS_ACTIVITY_UNDEFINED:
 
3385
            do_block = 1;
 
3386
            break;
 
3387
        case ERTS_ACTIVITY_GC:
 
3388
            do_block = !(system_block_state.allowed_activities
 
3389
                         & ERTS_BS_FLG_ALLOW_GC);
 
3390
        break;
 
3391
        case ERTS_ACTIVITY_IO:
 
3392
            do_block = !(system_block_state.allowed_activities
 
3393
                         & ERTS_BS_FLG_ALLOW_IO);
 
3394
            break;
 
3395
        case ERTS_ACTIVITY_WAIT:
 
3396
            /* No need to block if we are going to wait */
 
3397
            do_block = 0;
 
3398
            break;
 
3399
        default:
 
3400
            erts_set_activity_error(ERTS_ACT_ERR_ENTER_UNKNOWN_ACTIVITY,
 
3401
                                    __FILE__, __LINE__);
 
3402
            break;
 
3403
        }
 
3404
    }
 
3405
 
 
3406
    if (do_block) {
 
3407
 
 
3408
#ifdef ERTS_ENABLE_LOCK_CHECK
 
3409
        if (!locked) {
 
3410
            /* Only system_block_state.mtx should be held */
 
3411
            erts_lc_check_exact(&system_block_state.mtx.lc, 1);
 
3412
        }
 
3413
#endif
 
3414
 
 
3415
        block_me(NULL, NULL, NULL, 1, 0, 1);
 
3416
 
 
3417
    }
 
3418
 
 
3419
    erts_smp_mtx_unlock(&system_block_state.mtx);
 
3420
 
 
3421
    if (!locked && resume)
 
3422
        (*resume)(arg);
 
3423
}
 
3424
 
 
3425
 
 
3426
 
 
3427
void
 
3428
erts_set_activity_error(erts_activity_error_t error, char *file, int line)
 
3429
{
 
3430
    switch (error) {
 
3431
    case ERTS_ACT_ERR_LEAVE_WAIT_UNLOCKED:
 
3432
        erl_exit(1, "%s:%d: Fatal error: Leaving activity waiting without "
 
3433
                 "supplying the possibility to block unlocked.",
 
3434
                 file, line);
 
3435
        break;
 
3436
    case ERTS_ACT_ERR_LEAVE_UNKNOWN_ACTIVITY:
 
3437
        erl_exit(1, "%s:%d: Fatal error: Leaving unknown activity.",
 
3438
                 file, line);
 
3439
        break;
 
3440
    case ERTS_ACT_ERR_ENTER_UNKNOWN_ACTIVITY:
 
3441
        erl_exit(1, "%s:%d: Fatal error: Leaving unknown activity.",
 
3442
                 file, line);
 
3443
        break;
 
3444
    default:
 
3445
        erl_exit(1, "%s:%d: Internal error in erts_smp_set_activity()",
 
3446
                 file, line);
 
3447
        break;
 
3448
    }
 
3449
 
 
3450
}
 
3451
 
 
3452
 
 
3453
static ERTS_INLINE int
 
3454
threads_not_under_control(void)
 
3455
{
 
3456
    int res = system_block_state.threads_to_block;
 
3457
 
 
3458
    /* Waiting is allways an allowed activity... */
 
3459
    res -= erts_smp_atomic_read(&erts_system_block_state.in_activity.wait);
 
3460
 
 
3461
    if (system_block_state.allowed_activities & ERTS_BS_FLG_ALLOW_GC)
 
3462
        res -= erts_smp_atomic_read(&erts_system_block_state.in_activity.gc);
 
3463
 
 
3464
    if (system_block_state.allowed_activities & ERTS_BS_FLG_ALLOW_IO)
 
3465
        res -= erts_smp_atomic_read(&erts_system_block_state.in_activity.io);
 
3466
 
 
3467
    if (res < 0) {
 
3468
        ASSERT(0);
 
3469
        return 0;
 
3470
    }
 
3471
    return res;
 
3472
}
 
3473
 
 
3474
/*
 
3475
 * erts_block_system() blocks all threads registered as blockable.
 
3476
 * It doesn't return until either all threads have blocked (0 is returned)
 
3477
 * or it has timed out (ETIMEDOUT) is returned.
 
3478
 *
 
3479
 * If allowed activities == 0, blocked threads will release all locks
 
3480
 * before blocking.
 
3481
 *
 
3482
 * If allowed_activities is != 0, erts_block_system() will allow blockable
 
3483
 * threads to continue executing as long as they are doing an allowed
 
3484
 * activity. When they are done with the allowed activity they will block,
 
3485
 * *but* they will block holding locks. Therefore, the thread calling
 
3486
 * erts_block_system() must *not* try to aquire any locks that might be
 
3487
 * held by blocked threads holding locks from allowed activities.
 
3488
 *
 
3489
 * Currently allowed_activities are:
 
3490
 *      * ERTS_BS_FLG_ALLOW_GC          Thread continues with garbage
 
3491
 *                                      collection and blocks with
 
3492
 *                                      main process lock on current
 
3493
 *                                      process locked.
 
3494
 *      * ERTS_BS_FLG_ALLOW_IO          Thread continues with I/O
 
3495
 */
 
3496
 
 
3497
void
 
3498
erts_block_system(Uint32 allowed_activities)
 
3499
{
 
3500
    int do_block;
 
3501
#ifdef ERTS_ENABLE_LOCK_CHECK
 
3502
    erts_lc_check_exact(NULL, 0); /* No locks should be locked */
 
3503
#endif
 
3504
 
 
3505
    erts_smp_mtx_lock(&system_block_state.mtx);
 
3506
 
 
3507
    do_block = erts_smp_pending_system_block();
 
3508
    if (do_block
 
3509
        && system_block_state.have_blocker
 
3510
        && erts_smp_equal_tids(system_block_state.blocker_tid,
 
3511
                               erts_smp_thr_self())) {
 
3512
        ASSERT(system_block_state.recursive_block >= 0);
 
3513
        system_block_state.recursive_block++;
 
3514
 
 
3515
        /* You are not allowed to restrict allowed activites
 
3516
           in a recursive block! */
 
3517
        ERTS_SMP_LC_ASSERT((system_block_state.allowed_activities
 
3518
                            & ~allowed_activities) == 0);
 
3519
    }
 
3520
    else {
 
3521
 
 
3522
        erts_smp_atomic_inc(&erts_system_block_state.do_block);
 
3523
 
 
3524
        /* Someone else might be waiting for us to block... */
 
3525
        if (do_block) {
 
3526
        do_block_me:
 
3527
            block_me(NULL, NULL, NULL, 1, 1, 0);
 
3528
        }
 
3529
 
 
3530
        ASSERT(!system_block_state.have_blocker);
 
3531
        system_block_state.have_blocker = 1;
 
3532
        system_block_state.blocker_tid = erts_smp_thr_self();
 
3533
        system_block_state.allowed_activities = allowed_activities;
 
3534
 
 
3535
        if (is_blockable_thread())
 
3536
            system_block_state.threads_to_block--;
 
3537
 
 
3538
        while (threads_not_under_control() && !system_block_state.emergency)
 
3539
            erts_smp_cnd_wait(&system_block_state.cnd, &system_block_state.mtx);
 
3540
 
 
3541
        if (system_block_state.emergency) {
 
3542
            system_block_state.have_blocker = 0;
 
3543
            goto do_block_me;
 
3544
        }
 
3545
    }
 
3546
 
 
3547
    erts_smp_mtx_unlock(&system_block_state.mtx);
 
3548
}
 
3549
 
 
3550
/*
 
3551
 * erts_emergency_block_system() should only be called when we are
 
3552
 * about to write a crash dump...
 
3553
 */
 
3554
 
 
3555
int
 
3556
erts_emergency_block_system(long timeout, Uint32 allowed_activities)
 
3557
{
 
3558
    int res = 0;
 
3559
    long another_blocker;
 
3560
 
 
3561
    erts_smp_mtx_lock(&system_block_state.mtx);
 
3562
 
 
3563
    if (system_block_state.emergency) {
 
3564
         /* Argh... */
 
3565
        res = EINVAL;
 
3566
        goto done;
 
3567
    }
 
3568
 
 
3569
    another_blocker = erts_smp_pending_system_block();
 
3570
    system_block_state.emergency = 1;
 
3571
    erts_smp_atomic_inc(&erts_system_block_state.do_block);
 
3572
 
 
3573
    if (another_blocker) {
 
3574
        if (is_blocker()) {
 
3575
            erts_smp_atomic_dec(&erts_system_block_state.do_block);
 
3576
            res = 0;
 
3577
            goto done;
 
3578
        }
 
3579
        /* kick the other blocker */
 
3580
        erts_smp_cnd_broadcast(&system_block_state.cnd);
 
3581
        while (system_block_state.have_blocker)
 
3582
            erts_smp_cnd_wait(&system_block_state.cnd, &system_block_state.mtx);
 
3583
    }
 
3584
 
 
3585
    ASSERT(!system_block_state.have_blocker);
 
3586
    system_block_state.have_blocker = 1;
 
3587
    system_block_state.blocker_tid = erts_smp_thr_self();
 
3588
    system_block_state.allowed_activities = allowed_activities;
 
3589
 
 
3590
    if (is_blockable_thread())
 
3591
        system_block_state.threads_to_block--;
 
3592
 
 
3593
    if (timeout < 0) {
 
3594
        while (threads_not_under_control())
 
3595
            erts_smp_cnd_wait(&system_block_state.cnd, &system_block_state.mtx);
 
3596
    }
 
3597
    else {
 
3598
        erts_thr_timeval_t to;
 
3599
        erts_thr_time_now(&to);
 
3600
 
 
3601
        to.tv_sec += timeout / 1000;
 
3602
        to.tv_nsec += timeout % 1000;
 
3603
        if (to.tv_nsec >= 1000000000) {
 
3604
            to.tv_sec++;
 
3605
            to.tv_nsec -= 1000000000;
 
3606
        }
 
3607
 
 
3608
        while (res != ETIMEDOUT && threads_not_under_control()) {
 
3609
            res = erts_smp_cnd_timedwait(&system_block_state.cnd,
 
3610
                                         &system_block_state.mtx,
 
3611
                                         &to);
 
3612
        }
 
3613
    }
 
3614
 done:
 
3615
    erts_smp_mtx_unlock(&system_block_state.mtx);
 
3616
    return res;
 
3617
}
 
3618
 
 
3619
void
 
3620
erts_release_system(void)
 
3621
{
 
3622
    long do_block;
 
3623
 
 
3624
#ifdef ERTS_ENABLE_LOCK_CHECK
 
3625
    erts_lc_check_exact(NULL, 0); /* No locks should be locked */
 
3626
#endif
 
3627
 
 
3628
    erts_smp_mtx_lock(&system_block_state.mtx);
 
3629
    ASSERT(is_blocker());
 
3630
 
 
3631
    ASSERT(system_block_state.recursive_block >= 0);
 
3632
 
 
3633
    if (system_block_state.recursive_block)
 
3634
        system_block_state.recursive_block--;
 
3635
    else {
 
3636
        do_block = erts_smp_atomic_dectest(&erts_system_block_state.do_block);
 
3637
        system_block_state.have_blocker = 0;
 
3638
        if (is_blockable_thread())
 
3639
            system_block_state.threads_to_block++;
 
3640
        else
 
3641
            do_block = 0;
 
3642
 
 
3643
        /* Someone else might be waiting for us to block... */
 
3644
        if (do_block)
 
3645
            block_me(NULL, NULL, NULL, 1, 0, 0);
 
3646
        else
 
3647
            erts_smp_cnd_broadcast(&system_block_state.cnd);
 
3648
    }
 
3649
 
 
3650
    erts_smp_mtx_unlock(&system_block_state.mtx);
 
3651
    
 
3652
}
 
3653
 
 
3654
#ifdef ERTS_ENABLE_LOCK_CHECK
 
3655
 
 
3656
void
 
3657
erts_lc_activity_change_begin(void)
 
3658
{
 
3659
    erts_smp_mtx_lock(&system_block_state.mtx);
 
3660
    system_block_state.activity_changing++;
 
3661
    erts_smp_mtx_unlock(&system_block_state.mtx);
 
3662
}
 
3663
 
 
3664
void
 
3665
erts_lc_activity_change_end(void)
 
3666
{
 
3667
    erts_smp_mtx_lock(&system_block_state.mtx);
 
3668
    system_block_state.activity_changing--;
 
3669
    if (system_block_state.checking && !system_block_state.activity_changing)
 
3670
        erts_smp_cnd_broadcast(&system_block_state.cnd);
 
3671
    erts_smp_mtx_unlock(&system_block_state.mtx);
 
3672
}
 
3673
 
 
3674
#endif
 
3675
 
 
3676
int
 
3677
erts_is_system_blocked(erts_activity_t allowed_activities)
 
3678
{
 
3679
    int blkd;
 
3680
 
 
3681
    erts_smp_mtx_lock(&system_block_state.mtx);
 
3682
    blkd = (erts_smp_pending_system_block()
 
3683
            && system_block_state.have_blocker
 
3684
            && erts_smp_equal_tids(system_block_state.blocker_tid,
 
3685
                                   erts_smp_thr_self())
 
3686
            && !(system_block_state.allowed_activities & ~allowed_activities));
 
3687
#ifdef ERTS_ENABLE_LOCK_CHECK
 
3688
    if (blkd) {
 
3689
        system_block_state.checking = 1;
 
3690
        while (system_block_state.activity_changing)
 
3691
            erts_smp_cnd_wait(&system_block_state.cnd, &system_block_state.mtx);
 
3692
        system_block_state.checking = 0;
 
3693
        blkd = !threads_not_under_control();
 
3694
    }
 
3695
#endif
 
3696
    erts_smp_mtx_unlock(&system_block_state.mtx);
 
3697
    return blkd;
 
3698
}
 
3699
 
 
3700
void
 
3701
erts_system_block_init(void)
 
3702
{
 
3703
    /* Local state... */
 
3704
    system_block_state.emergency = 0;
 
3705
    system_block_state.threads_to_block = 0;
 
3706
    system_block_state.have_blocker = 0;
 
3707
    /* system_block_state.block_tid */
 
3708
    system_block_state.recursive_block = 0;
 
3709
    system_block_state.allowed_activities = 0;
 
3710
    erts_smp_tsd_key_create(&system_block_state.blockable_key);
 
3711
    erts_smp_mtx_init(&system_block_state.mtx, "system_block");
 
3712
    erts_smp_cnd_init(&system_block_state.cnd);
 
3713
#ifdef ERTS_ENABLE_LOCK_CHECK
 
3714
    system_block_state.activity_changing = 0;
 
3715
    system_block_state.checking = 0;
 
3716
#endif
 
3717
 
 
3718
    /* Global state... */
 
3719
 
 
3720
    erts_smp_atomic_init(&erts_system_block_state.do_block, 0L);
 
3721
    erts_smp_atomic_init(&erts_system_block_state.in_activity.wait, 0L);
 
3722
    erts_smp_atomic_init(&erts_system_block_state.in_activity.gc, 0L);
 
3723
    erts_smp_atomic_init(&erts_system_block_state.in_activity.io, 0L);
 
3724
 
 
3725
    /* Make sure blockable threads unregister when exiting... */
 
3726
    erts_smp_install_exit_handler(erts_unregister_blockable_thread);
 
3727
}
 
3728
 
 
3729
 
 
3730
#endif /* #ifdef ERTS_SMP */
 
3731
 
3257
3732
#ifdef DEBUG
3258
3733
/*
3259
3734
 * Handy functions when using a debugger - don't use in the code!
3263
3738
byte* buf;
3264
3739
int sz;
3265
3740
{
3266
 
    bin_write(CERR,buf,sz);
 
3741
    bin_write(ERTS_PRINT_STDERR,NULL,buf,sz);
3267
3742
}
3268
3743
 
3269
3744
void pat(Eterm atom)
3275
3750
 
3276
3751
void pinfo()
3277
3752
{
3278
 
    process_info(COUT);
 
3753
    process_info(ERTS_PRINT_STDOUT, NULL);
3279
3754
}
3280
3755
 
3281
3756
 
3283
3758
Process *p;
3284
3759
{
3285
3760
    if(p)
3286
 
        print_process_info(p,CERR);
 
3761
        print_process_info(ERTS_PRINT_STDERR, NULL, p);
3287
3762
}
3288
3763
    
3289
3764
void ppi(Eterm pid)
3290
3765
{
3291
 
    pp(pid2proc(pid));
 
3766
    pp(erts_pid2proc_unlocked(pid));
3292
3767
}
3293
3768
 
3294
3769
void td(Eterm x)
3295
3770
{
3296
 
    display(x, CERR);
3297
 
    erl_putc('\n', CERR);
 
3771
    erts_fprintf(stderr, "%T\n", x);
3298
3772
}
3299
3773
 
3300
3774
void
3307
3781
    }
3308
3782
 
3309
3783
    while(sp >= stop) {
3310
 
        erl_printf(COUT,"%08lx: ", (unsigned long) (Eterm) sp);
3311
 
        ldisplay(*sp, COUT, 75);
3312
 
        erl_putc('\r', COUT);
3313
 
        erl_putc('\n', COUT);
 
3784
        erts_printf("%p: %.75T\n", sp, *sp);
3314
3785
        sp--;
3315
3786
    }
3316
3787
}
3317
3788
#endif
 
3789
 
 
3790