Skip to content

Commit e850622

Browse files
copy echion to dd-trace-py
1 parent 06ea45c commit e850622

File tree

26 files changed

+5376
-7
lines changed

26 files changed

+5376
-7
lines changed
Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
// This file is part of "echion" which is released under MIT.
2+
//
3+
// Copyright (c) 2023 Gabriele N. Tornetta <phoenix1987@gmail.com>.
4+
5+
#pragma once
6+
7+
#define PY_SSIZE_T_CLEAN
8+
#include <Python.h>
9+
10+
#if PY_VERSION_HEX >= 0x030b0000
11+
#include <cpython/genobject.h>
12+
13+
#define Py_BUILD_CORE
14+
#if PY_VERSION_HEX >= 0x030d0000
15+
#include <opcode.h>
16+
#else
17+
#include <internal/pycore_frame.h>
18+
#include <internal/pycore_opcode.h>
19+
#endif // PY_VERSION_HEX >= 0x030d0000
20+
#else
21+
#include <genobject.h>
22+
#include <opcode.h>
23+
#endif
24+
25+
#include <memory>
26+
27+
#include <echion/vm.h>
28+
29+
extern "C" {
30+
31+
typedef enum
32+
{
33+
STATE_PENDING,
34+
STATE_CANCELLED,
35+
STATE_FINISHED
36+
} fut_state;
37+
38+
#if PY_VERSION_HEX >= 0x030d0000
39+
#define FutureObj_HEAD(prefix) \
40+
PyObject_HEAD PyObject* prefix##_loop; \
41+
PyObject* prefix##_callback0; \
42+
PyObject* prefix##_context0; \
43+
PyObject* prefix##_callbacks; \
44+
PyObject* prefix##_exception; \
45+
PyObject* prefix##_exception_tb; \
46+
PyObject* prefix##_result; \
47+
PyObject* prefix##_source_tb; \
48+
PyObject* prefix##_cancel_msg; \
49+
PyObject* prefix##_cancelled_exc; \
50+
fut_state prefix##_state; \
51+
/* These bitfields need to be at the end of the struct \
52+
so that these and bitfields from TaskObj are contiguous. \
53+
*/ \
54+
unsigned prefix##_log_tb : 1; \
55+
unsigned prefix##_blocking : 1;
56+
57+
#elif PY_VERSION_HEX >= 0x030b0000
58+
#define FutureObj_HEAD(prefix) \
59+
PyObject_HEAD PyObject* prefix##_loop; \
60+
PyObject* prefix##_callback0; \
61+
PyObject* prefix##_context0; \
62+
PyObject* prefix##_callbacks; \
63+
PyObject* prefix##_exception; \
64+
PyObject* prefix##_exception_tb; \
65+
PyObject* prefix##_result; \
66+
PyObject* prefix##_source_tb; \
67+
PyObject* prefix##_cancel_msg; \
68+
fut_state prefix##_state; \
69+
int prefix##_log_tb; \
70+
int prefix##_blocking; \
71+
PyObject* dict; \
72+
PyObject* prefix##_weakreflist; \
73+
PyObject* prefix##_cancelled_exc;
74+
75+
#elif PY_VERSION_HEX >= 0x030a0000
76+
#define FutureObj_HEAD(prefix) \
77+
PyObject_HEAD PyObject* prefix##_loop; \
78+
PyObject* prefix##_callback0; \
79+
PyObject* prefix##_context0; \
80+
PyObject* prefix##_callbacks; \
81+
PyObject* prefix##_exception; \
82+
PyObject* prefix##_exception_tb; \
83+
PyObject* prefix##_result; \
84+
PyObject* prefix##_source_tb; \
85+
PyObject* prefix##_cancel_msg; \
86+
fut_state prefix##_state; \
87+
int prefix##_log_tb; \
88+
int prefix##_blocking; \
89+
PyObject* dict; \
90+
PyObject* prefix##_weakreflist; \
91+
_PyErr_StackItem prefix##_cancelled_exc_state;
92+
93+
#elif PY_VERSION_HEX >= 0x03090000
94+
#define FutureObj_HEAD(prefix) \
95+
PyObject_HEAD PyObject* prefix##_loop; \
96+
PyObject* prefix##_callback0; \
97+
PyObject* prefix##_context0; \
98+
PyObject* prefix##_callbacks; \
99+
PyObject* prefix##_exception; \
100+
PyObject* prefix##_result; \
101+
PyObject* prefix##_source_tb; \
102+
PyObject* prefix##_cancel_msg; \
103+
fut_state prefix##_state; \
104+
int prefix##_log_tb; \
105+
int prefix##_blocking; \
106+
PyObject* dict; \
107+
PyObject* prefix##_weakreflist; \
108+
_PyErr_StackItem prefix##_cancelled_exc_state;
109+
110+
#else
111+
#define FutureObj_HEAD(prefix) \
112+
PyObject_HEAD PyObject* prefix##_loop; \
113+
PyObject* prefix##_callback0; \
114+
PyObject* prefix##_context0; \
115+
PyObject* prefix##_callbacks; \
116+
PyObject* prefix##_exception; \
117+
PyObject* prefix##_result; \
118+
PyObject* prefix##_source_tb; \
119+
fut_state prefix##_state; \
120+
int prefix##_log_tb; \
121+
int prefix##_blocking; \
122+
PyObject* dict; \
123+
PyObject* prefix##_weakreflist;
124+
#endif
125+
126+
typedef struct
127+
{
128+
FutureObj_HEAD(future)
129+
} FutureObj;
130+
131+
#if PY_VERSION_HEX >= 0x030d0000
132+
typedef struct
133+
{
134+
FutureObj_HEAD(task)
135+
unsigned task_must_cancel : 1;
136+
unsigned task_log_destroy_pending : 1;
137+
int task_num_cancels_requested;
138+
PyObject* task_fut_waiter;
139+
PyObject* task_coro;
140+
PyObject* task_name;
141+
PyObject* task_context;
142+
} TaskObj;
143+
144+
#elif PY_VERSION_HEX >= 0x030a0000
145+
typedef struct
146+
{
147+
FutureObj_HEAD(task) PyObject* task_fut_waiter;
148+
PyObject* task_coro;
149+
PyObject* task_name;
150+
PyObject* task_context;
151+
int task_must_cancel;
152+
int task_log_destroy_pending;
153+
int task_num_cancels_requested;
154+
} TaskObj;
155+
156+
#else
157+
typedef struct
158+
{
159+
FutureObj_HEAD(task) PyObject* task_fut_waiter;
160+
PyObject* task_coro;
161+
PyObject* task_name;
162+
PyObject* task_context;
163+
int task_must_cancel;
164+
int task_log_destroy_pending;
165+
} TaskObj;
166+
#endif
167+
168+
// ---- cr_await ----
169+
170+
#if PY_VERSION_HEX >= 0x030c0000
171+
#define RESUME_QUICK INSTRUMENTED_RESUME
172+
#endif
173+
174+
#if PY_VERSION_HEX >= 0x030b0000
175+
inline PyObject* PyGen_yf(PyGenObject* gen, PyObject* frame_addr)
176+
{
177+
PyObject* yf = NULL;
178+
179+
if (gen->gi_frame_state < FRAME_CLEARED)
180+
{
181+
if (gen->gi_frame_state == FRAME_CREATED)
182+
return NULL;
183+
184+
_PyInterpreterFrame frame;
185+
if (copy_type(frame_addr, frame))
186+
return NULL;
187+
188+
_Py_CODEUNIT next;
189+
#if PY_VERSION_HEX >= 0x030d0000
190+
if (copy_type(frame.instr_ptr, next))
191+
#else
192+
if (copy_type(frame.prev_instr + 1, next))
193+
#endif
194+
return NULL;
195+
if (!(_Py_OPCODE(next) == RESUME || _Py_OPCODE(next) == RESUME_QUICK) ||
196+
_Py_OPARG(next) < 2)
197+
return NULL;
198+
199+
if (frame.stacktop < 1 || frame.stacktop > (1 << 20))
200+
return NULL;
201+
202+
auto localsplus = std::make_unique<PyObject*[]>(frame.stacktop);
203+
if (copy_generic(frame.localsplus, localsplus.get(), frame.stacktop * sizeof(PyObject*)))
204+
return NULL;
205+
206+
yf = localsplus[frame.stacktop - 1];
207+
}
208+
209+
return yf;
210+
}
211+
212+
#elif PY_VERSION_HEX >= 0x030a0000
213+
inline PyObject* PyGen_yf(PyGenObject* Py_UNUSED(gen), PyObject* frame_addr)
214+
{
215+
PyObject* yf = NULL;
216+
PyFrameObject* f = (PyFrameObject*)frame_addr;
217+
218+
if (f)
219+
{
220+
PyFrameObject frame;
221+
if (copy_type(f, frame))
222+
return NULL;
223+
224+
if (frame.f_lasti < 0)
225+
return NULL;
226+
227+
PyCodeObject code;
228+
if (copy_type(frame.f_code, code))
229+
return NULL;
230+
231+
Py_ssize_t s = 0;
232+
auto c = pybytes_to_bytes_and_size(code.co_code, &s);
233+
if (c == nullptr)
234+
return NULL;
235+
236+
if (c[(frame.f_lasti + 1) * sizeof(_Py_CODEUNIT)] != YIELD_FROM)
237+
return NULL;
238+
239+
ssize_t nvalues = frame.f_stackdepth;
240+
if (nvalues < 1 || nvalues > (1 << 20))
241+
return NULL;
242+
243+
auto stack = std::make_unique<PyObject*[]>(nvalues);
244+
245+
if (copy_generic(frame.f_valuestack, stack.get(), nvalues * sizeof(PyObject*)))
246+
return NULL;
247+
248+
yf = stack[nvalues - 1];
249+
}
250+
251+
return yf;
252+
}
253+
254+
#else
255+
inline PyObject* PyGen_yf(PyGenObject* Py_UNUSED(gen), PyObject* frame_addr)
256+
{
257+
PyObject* yf = NULL;
258+
PyFrameObject* f = (PyFrameObject*)frame_addr;
259+
260+
if (frame_addr == NULL)
261+
return NULL;
262+
263+
PyFrameObject frame;
264+
if (copy_type(f, frame))
265+
return NULL;
266+
267+
if (frame.f_stacktop)
268+
{
269+
if (frame.f_lasti < 0)
270+
return NULL;
271+
272+
PyCodeObject code;
273+
if (copy_type(frame.f_code, code))
274+
return NULL;
275+
276+
Py_ssize_t s = 0;
277+
auto c = pybytes_to_bytes_and_size(code.co_code, &s);
278+
if (c == nullptr)
279+
return NULL;
280+
281+
if (c[f->f_lasti + sizeof(_Py_CODEUNIT)] != YIELD_FROM)
282+
return NULL;
283+
284+
auto stacktop = std::make_unique<PyObject*>();
285+
if (copy_generic(frame.f_stacktop - 1, stacktop.get(), sizeof(PyObject*)))
286+
return NULL;
287+
288+
yf = *stacktop;
289+
}
290+
291+
return yf;
292+
}
293+
#endif
294+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// This file is part of "echion" which is released under MIT.
2+
//
3+
// Copyright (c) 2023 Gabriele N. Tornetta <phoenix1987@gmail.com>.
4+
5+
#pragma once
6+
7+
#include <functional>
8+
#include <list>
9+
#include <memory>
10+
#include <unordered_map>
11+
12+
#include <echion/errors.h>
13+
14+
#define CACHE_MAX_ENTRIES 2048
15+
16+
template <typename K, typename V>
17+
class LRUCache
18+
{
19+
public:
20+
LRUCache(size_t capacity) : capacity(capacity) {}
21+
22+
Result<std::reference_wrapper<V>> lookup(const K& k);
23+
24+
void store(const K& k, std::unique_ptr<V> v);
25+
26+
private:
27+
size_t capacity;
28+
std::list<std::pair<K, std::unique_ptr<V>>> items;
29+
std::unordered_map<K, typename std::list<std::pair<K, std::unique_ptr<V>>>::iterator> index;
30+
};
31+
32+
template <typename K, typename V>
33+
void LRUCache<K, V>::store(const K& k, std::unique_ptr<V> v)
34+
{
35+
// Check if cache is full
36+
if (items.size() >= capacity)
37+
{
38+
index.erase(items.back().first);
39+
items.pop_back();
40+
}
41+
42+
// Insert the new item at front of the list
43+
items.emplace_front(k, std::move(v));
44+
45+
// Insert in the map
46+
index[k] = items.begin();
47+
}
48+
49+
template <typename K, typename V>
50+
Result<std::reference_wrapper<V>> LRUCache<K, V>::lookup(const K& k)
51+
{
52+
auto itr = index.find(k);
53+
if (itr == index.end())
54+
return ErrorKind::LookupError;
55+
56+
// Move to the front of the list
57+
items.splice(items.begin(), items, itr->second);
58+
59+
return std::reference_wrapper<V>(*(itr->second->second.get()));
60+
}

0 commit comments

Comments
 (0)