aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/erl_bif_unique.h
blob: c6481864d070539621f4074fdf359fc42327c3d7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
 * %CopyrightBegin%
 *
 * Copyright Ericsson AB 2014-2016. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * %CopyrightEnd%
 */

#ifndef ERTS_BIF_UNIQUE_H__
#define ERTS_BIF_UNIQUE_H__

#include "erl_process.h"
#include "big.h"

void erts_bif_unique_init(void);
void erts_sched_bif_unique_init(ErtsSchedulerData *esdp);

/* reference */
Eterm erts_make_ref(Process *);
Eterm erts_make_ref_in_buffer(Eterm buffer[REF_THING_SIZE]);
void erts_make_ref_in_array(Uint32 ref[ERTS_MAX_REF_NUMBERS]);

/* strict monotonic counter */

#define ERTS_MAX_UNIQUE_MONOTONIC_INTEGER_HEAP_SIZE ERTS_MAX_UINT64_HEAP_SIZE

/*
 * Note that a raw value is an intermediate value that 
 * not necessarily correspond to the end result.
 */
Sint64 erts_raw_get_unique_monotonic_integer(void);
Uint erts_raw_unique_monotonic_integer_heap_size(Sint64 raw, int positive);
Eterm erts_raw_make_unique_monotonic_integer_value(Eterm **hpp, Sint64 raw,
                                                   int positive);

Sint64 erts_get_min_unique_monotonic_integer(void);

int erts_debug_set_unique_monotonic_integer_state(Eterm et_value);
Eterm erts_debug_get_unique_monotonic_integer_state(Process *c_p);

/* unique integer */
#define ERTS_UNIQUE_INT_RAW_VALUES 2
#define ERTS_MAX_UNIQUE_INT_HEAP_SIZE ERTS_UINT64_ARRAY_TO_BIG_MAX_HEAP_SZ(2)

Uint erts_raw_unique_integer_heap_size(Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES],
                                       int positive);
Eterm erts_raw_make_unique_integer(Eterm **hpp,
                                   Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES],
                                   int postive);
void erts_raw_get_unique_integer(Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES]);
Sint64 erts_get_min_unique_integer(void);

Eterm erts_debug_make_unique_integer(Process *c_p,
				     Eterm etval0,
				     Eterm etval1);


ERTS_GLB_INLINE void erts_set_ref_numbers(Uint32 ref[ERTS_MAX_REF_NUMBERS],
					  Uint32 thr_id, Uint64 value);
ERTS_GLB_INLINE Uint32 erts_get_ref_numbers_thr_id(Uint32 ref[ERTS_MAX_REF_NUMBERS]);
ERTS_GLB_INLINE Uint64 erts_get_ref_numbers_value(Uint32 ref[ERTS_MAX_REF_NUMBERS]);
ERTS_GLB_INLINE void erts_sched_make_ref_in_array(ErtsSchedulerData *esdp,
						  Uint32 ref[ERTS_MAX_REF_NUMBERS]);
ERTS_GLB_INLINE Eterm erts_sched_make_ref_in_buffer(ErtsSchedulerData *esdp,
						    Eterm buffer[REF_THING_SIZE]);

#if ERTS_GLB_INLINE_INCL_FUNC_DEF

ERTS_GLB_INLINE void
erts_set_ref_numbers(Uint32 ref[ERTS_MAX_REF_NUMBERS], Uint32 thr_id, Uint64 value)
{
    /*
     * We cannot use thread id in the first 18-bit word since
     * the hash/phash/phash2 BIFs only hash on this word. If
     * we did, we would get really poor hash values. Instead
     * we have to shuffle the bits a bit.
     */
    ASSERT(thr_id == (thr_id & ((Uint32) 0x3ffff)));
    ref[0] = (Uint32) (value & ((Uint64) 0x3ffff));
    ref[1] = (((Uint32) (value & ((Uint64) 0xfffc0000)))
	      | (thr_id & ((Uint32) 0x3ffff)));
    ref[2] = (Uint32) ((value >> 32) & ((Uint64) 0xffffffff));
}

ERTS_GLB_INLINE Uint32
erts_get_ref_numbers_thr_id(Uint32 ref[ERTS_MAX_REF_NUMBERS])
{
    return ref[1] & ((Uint32) 0x3ffff);
}

ERTS_GLB_INLINE Uint64
erts_get_ref_numbers_value(Uint32 ref[ERTS_MAX_REF_NUMBERS])
{
    return (((((Uint64) ref[2]) & ((Uint64) 0xffffffff)) << 32)
	    | (((Uint64) ref[1]) & ((Uint64) 0xfffc0000))
	    | (((Uint64) ref[0]) & ((Uint64) 0x3ffff)));
}

ERTS_GLB_INLINE void
erts_sched_make_ref_in_array(ErtsSchedulerData *esdp,
			     Uint32 ref[ERTS_MAX_REF_NUMBERS])
{
    Uint64 value;

    ASSERT(esdp);
    value = esdp->ref++;
    erts_set_ref_numbers(ref, (Uint32) esdp->thr_id, value);
}

ERTS_GLB_INLINE Eterm
erts_sched_make_ref_in_buffer(ErtsSchedulerData *esdp,
			      Eterm buffer[REF_THING_SIZE])
{
    Eterm* hp = buffer;
    Uint32 ref[ERTS_MAX_REF_NUMBERS];

    erts_sched_make_ref_in_array(esdp, ref);
    write_ref_thing(hp, ref[0], ref[1], ref[2]);
    return make_internal_ref(hp);
}

#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */

#endif /*  ERTS_BIF_UNIQUE_H__ */