1/*
2 This file is part of Mtproto-proxy Library.
3
4 Mtproto-proxy Library is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 Mtproto-proxy Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with Mtproto-proxy Library. If not, see <http://www.gnu.org/licenses/>.
16
17 Copyright 2014-2018 Telegram Messenger Inc
18 2014-2015 Andrey Lopatin
19 2014-2018 Nikolai Durov
20*/
21
22#pragma once
23
24#define MPQ_USE_POSIX_SEMAPHORES 0
25
26#if MPQ_USE_POSIX_SEMAPHORES
27#include <semaphore.h>
28#endif
29
30typedef struct mp_semaphore {
31 volatile int value;
32 volatile int waiting;
33} mp_sem_t;
34
35#define THREAD_HPTRS 16
36
37#define MPQ_SMALL_BLOCK_SIZE 64
38#define MPQ_BLOCK_SIZE 4096 // must be a power of 2
39#define MPQ_BLOCK_ALIGNMENT 64
40
41#ifdef _LP64
42typedef int int128_t __attribute__((__mode__(TI)));
43# define DLONG int128_t
44// # define DLONG __int128
45# define MQN_SAFE (-1LL << 63)
46#else
47# define DLONG long long
48# define MQN_SAFE (-1L << 31)
49#endif
50
51
52#define MQN_IDX_MASK (~MQN_SAFE)
53
54typedef void *mqn_value_t;
55
56typedef struct mp_queue_node {
57 union {
58 struct {
59 long idx;
60 union {
61 long mqn_value;
62 void *mqn_ptr;
63 mqn_value_t val;
64 };
65 };
66 DLONG pair;
67 };
68} mpq_node_t;
69
70#define MQ_BLOCK_USED_MAGIC 0x1ebacaef
71#define MQ_BLOCK_FREE_MAGIC 0x2e4afeda
72#define MQ_BLOCK_GARBAGE_MAGIC 0x3a04dc7d
73#define MQ_BLOCK_PREPARED_MAGIC 0x4b9b13cd
74
75#define MQ_MAGIC 0x1aed9b43
76#define MQ_MAGIC_SEM 0x1aedcd21
77
78struct mp_queue_block {
79 long mqb_head __attribute__ ((aligned(64)));
80 int mqb_magic;
81 int mqb_align_bytes;
82 int mqb_size; // power of 2; one of MPQ_BLOCK_SIZE or MPQ_SMALL_BLOCK_SIZE
83 long mqb_tail __attribute__ ((aligned(64)));
84 struct mp_queue_block *mqb_next;
85 int mqb_next_allocators;
86 mpq_node_t mqb_nodes[MPQ_BLOCK_SIZE] __attribute__ ((aligned(64)));
87};
88
89struct mp_queue {
90 struct mp_queue_block *mq_head __attribute__ ((aligned(64)));
91 int mq_magic;
92 struct mp_queue_block *mq_tail __attribute__ ((aligned(64)));
93#if MPQ_USE_POSIX_SEMAPHORES
94 sem_t mq_sem __attribute__ ((aligned(64)));
95#else
96 mp_sem_t mq_sem __attribute__ ((aligned(64)));
97#endif
98 };
99
100extern volatile int mpq_blocks_allocated, mpq_blocks_allocated_max, mpq_blocks_allocations, mpq_blocks_true_allocations, mpq_blocks_wasted, mpq_blocks_prepared;
101extern volatile int mpq_small_blocks_allocated, mpq_small_blocks_allocated_max;
102
103#define MAX_MPQ_THREADS 256
104extern __thread int mpq_this_thread_id;
105extern __thread void **thread_hazard_pointers;
106extern volatile int mpq_threads;
107
108/* initialize this thread id and return it */
109int get_this_thread_id (void);
110
111/* functions for one mp_queue_block */
112struct mp_queue_block *alloc_mpq_block (mqn_value_t first_val, int allow_recursion, int is_small);
113void free_mpq_block (struct mp_queue_block *QB);
114
115mqn_value_t mpq_block_pop (struct mp_queue_block *QB);
116long mpq_block_push (struct mp_queue_block *QB, mqn_value_t val);
117
118/* functions for mp_queue = list of mp_queue_block's */
119void init_mp_queue (struct mp_queue *MQ);
120struct mp_queue *alloc_mp_queue (void);
121struct mp_queue *alloc_mp_queue_w (void);
122void init_mp_queue_w (struct mp_queue *MQ);
123void clear_mp_queue (struct mp_queue *MQ); // frees all mpq block chain; invoke only if nobody else is using mp-queue
124void free_mp_queue (struct mp_queue *MQ); // same + invoke free()
125
126// flags for mpq_push / mpq_pop functions
127#define MPQF_RECURSIVE 8192
128#define MPQF_STORE_PTR 4096
129#define MPQF_MAX_ITERATIONS (MPQF_STORE_PTR - 1)
130
131long mpq_push (struct mp_queue *MQ, mqn_value_t val, int flags);
132mqn_value_t mpq_pop (struct mp_queue *MQ, int flags);
133int mpq_is_empty (struct mp_queue *MQ);
134
135long mpq_push_w (struct mp_queue *MQ, mqn_value_t val, int flags);
136mqn_value_t mpq_pop_w (struct mp_queue *MQ, int flags);
137mqn_value_t mpq_pop_nw (struct mp_queue *MQ, int flags);
138
139int mp_sem_post (mp_sem_t *sem);
140int mp_sem_wait (mp_sem_t *sem);
141int mp_sem_trywait (mp_sem_t *sem);
142
143#define COMMON_HAZARD_PTR_NUM 3
144int is_hazard_ptr (void *ptr, int a, int b);
145extern void *mqb_hazard_ptr[MAX_MPQ_THREADS][THREAD_HPTRS];
146void *get_ptr_multithread_copy (void **ptr, void (*incref)(void *ptr));
147