Qucs-S S-parameter Viewer & RF Synthesis Tools
Loading...
Searching...
No Matches
greenlet_slp_switch.hpp
1#ifndef GREENLET_SLP_SWITCH_HPP
2#define GREENLET_SLP_SWITCH_HPP
3
4#include "greenlet_compiler_compat.hpp"
5#include "greenlet_refs.hpp"
6
7/*
8 * the following macros are spliced into the OS/compiler
9 * specific code, in order to simplify maintenance.
10 */
11// We can save about 10% of the time it takes to switch greenlets if
12// we thread the thread state through the slp_save_state() and the
13// following slp_restore_state() calls from
14// slp_switch()->g_switchstack() (which already needs to access it).
15//
16// However:
17//
18// that requires changing the prototypes and implementations of the
19// switching functions. If we just change the prototype of
20// slp_switch() to accept the argument and update the macros, without
21// changing the implementation of slp_switch(), we get crashes on
22// 64-bit Linux and 32-bit x86 (for reasons that aren't 100% clear);
23// on the other hand, 64-bit macOS seems to be fine. Also, 64-bit
24// windows is an issue because slp_switch is written fully in assembly
25// and currently ignores its argument so some code would have to be
26// adjusted there to pass the argument on to the
27// ``slp_save_state_asm()`` function (but interestingly, because of
28// the calling convention, the extra argument is just ignored and
29// things function fine, albeit slower, if we just modify
30// ``slp_save_state_asm`()` to fetch the pointer to pass to the
31// macro.)
32//
33// Our compromise is to use a *glabal*, untracked, weak, pointer
34// to the necessary thread state during the process of switching only.
35// This is safe because we're protected by the GIL, and if we're
36// running this code, the thread isn't exiting. This also nets us a
37// 10-12% speed improvement.
38
39#if Py_GIL_DISABLED
40thread_local greenlet::Greenlet* switching_thread_state = nullptr;
41#else
42static greenlet::Greenlet* volatile switching_thread_state = nullptr;
43#endif
44
45
46extern "C" {
47static int GREENLET_NOINLINE(slp_save_state_trampoline)(char* stackref);
48static void GREENLET_NOINLINE(slp_restore_state_trampoline)();
49}
50
51
52#define SLP_SAVE_STATE(stackref, stsizediff) \
53do { \
54 assert(switching_thread_state); \
55 stackref += STACK_MAGIC; \
56 if (slp_save_state_trampoline((char*)stackref)) \
57 return -1; \
58 if (!switching_thread_state->active()) \
59 return 1; \
60 stsizediff = switching_thread_state->stack_start() - (char*)stackref; \
61} while (0)
62
63#define SLP_RESTORE_STATE() slp_restore_state_trampoline()
64
65#define SLP_EVAL
66extern "C" {
67#define slp_switch GREENLET_NOINLINE(slp_switch)
68#include "slp_platformselect.h"
69}
70#undef slp_switch
71
72#ifndef STACK_MAGIC
73# error \
74 "greenlet needs to be ported to this platform, or taught how to detect your compiler properly."
75#endif /* !STACK_MAGIC */
76
77
78
79#ifdef EXTERNAL_ASM
80/* CCP addition: Make these functions, to be called from assembler.
81 * The token include file for the given platform should enable the
82 * EXTERNAL_ASM define so that this is included.
83 */
84extern "C" {
85intptr_t
86slp_save_state_asm(intptr_t* ref)
87{
88 intptr_t diff;
89 SLP_SAVE_STATE(ref, diff);
90 return diff;
91}
92
93void
94slp_restore_state_asm(void)
95{
96 SLP_RESTORE_STATE();
97}
98
99extern int slp_switch(void);
100};
101#endif
102
103#endif
Definition TGreenlet.hpp:343