summaryrefslogtreecommitdiff
path: root/Tools/c-analyzer/c_globals/README
blob: 772b8be27008bd1370315d250b3e8f98f852fff1 (plain)
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
#######################################
# C Globals and CPython Runtime State.

CPython's C code makes extensive use of global variables (whether static
globals or static locals).  Each such variable falls into one of several
categories:

* strictly const data
* used exclusively in main or in the REPL
* process-global state (e.g. managing process-level resources
  like signals and file descriptors)
* Python "global" runtime state
* per-interpreter runtime state

The last one can be a problem as soon as anyone creates a second
interpreter (AKA "subinterpreter") in a process.  It is definitely a
problem under subinterpreters if they are no longer sharing the GIL,
since the GIL protects us from a lot of race conditions.  Keep in mind
that ultimately *all* objects (PyObject) should be treated as
per-interpreter state.  This includes "static types", freelists,
_PyIdentifier, and singletons.  Take that in for a second.  It has
significant implications on where we use static variables!

Be aware that module-global state (stored in C statics) is a kind of
per-interpreter state.  There have been efforts across many years, and
still going, to provide extension module authors mechanisms to store
that state safely (see PEPs 3121, 489, etc.).

(Note that there has been discussion around support for running multiple
Python runtimes in the same process.  That would ends up with the same
problems, relative to static variables, that subinterpreters have.)

Historically we have been bad at keeping per-interpreter state out of
static variables, mostly because until recently subinterpreters were
not widely used nor even factored in to solutions.  However, the
feature is growing in popularity and use in the community.

Mandate: "Eliminate use of static variables for per-interpreter state."

The "c-statics.py" script in this directory, along with its accompanying
data files, are part of the effort to resolve existing problems with
our use of static variables and to prevent future problems.

#-------------------------
## statics for actually-global state (and runtime state consolidation)

In general, holding any kind of state in static variables
increases maintenance burden and increases the complexity of code (e.g.
we use TSS to identify the active thread state).  So it is a good idea
to avoid using statics for state even if for the "global" runtime or
for process-global state.

Relative to maintenance burden, one problem is where the runtime
state is spread throughout the codebase in dozens of individual
globals.  Unlike the other globals, the runtime state represents a set
of values that are constantly shifting in a complex way.  When they are
spread out it's harder to get a clear picture of what the runtime
involves.  Furthermore, when they are spread out it complicates efforts
that change the runtime.

Consequently, the globals for Python's runtime state have been
consolidated under a single top-level _PyRuntime global. No new globals
should be added for runtime state.  Instead, they should be added to
_PyRuntimeState or one of its sub-structs.  The tools in this directory
are run as part of the test suite to ensure that no new globals have
been added.  The script can be run manually as well:

  ./python Lib/test/test_c_statics/c-statics.py check

If it reports any globals then they should be resolved.  If the globals
are runtime state then they should be folded into _PyRuntimeState.
Otherwise they should be marked as ignored.