49
49
import com .oracle .graal .python .PythonLanguage ;
50
50
import com .oracle .graal .python .builtins .Builtin ;
51
51
import com .oracle .graal .python .builtins .CoreFunctions ;
52
+ import com .oracle .graal .python .builtins .Python3Core ;
52
53
import com .oracle .graal .python .builtins .PythonBuiltinClassType ;
53
54
import com .oracle .graal .python .builtins .PythonBuiltins ;
54
55
import com .oracle .graal .python .builtins .objects .PNone ;
55
56
import com .oracle .graal .python .builtins .objects .exception .PBaseException ;
56
57
import com .oracle .graal .python .builtins .objects .function .PKeyword ;
58
+ import com .oracle .graal .python .builtins .objects .module .PythonModule ;
57
59
import com .oracle .graal .python .builtins .objects .thread .PLock ;
58
60
import com .oracle .graal .python .builtins .objects .thread .PRLock ;
59
61
import com .oracle .graal .python .builtins .objects .thread .PThread ;
67
69
import com .oracle .graal .python .nodes .function .builtins .PythonUnaryBuiltinNode ;
68
70
import com .oracle .graal .python .runtime .GilNode ;
69
71
import com .oracle .graal .python .runtime .PythonContext ;
70
- import com .oracle .graal .python .builtins .Python3Core ;
71
72
import com .oracle .graal .python .runtime .exception .PException ;
72
73
import com .oracle .graal .python .runtime .exception .PythonThreadKillException ;
73
74
import com .oracle .truffle .api .CompilerDirectives .TruffleBoundary ;
75
+ import com .oracle .truffle .api .CompilerDirectives ;
74
76
import com .oracle .truffle .api .TruffleLanguage ;
75
77
import com .oracle .truffle .api .dsl .Cached ;
76
78
import com .oracle .truffle .api .dsl .CachedContext ;
77
79
import com .oracle .truffle .api .dsl .GenerateNodeFactory ;
78
80
import com .oracle .truffle .api .dsl .NodeFactory ;
79
81
import com .oracle .truffle .api .dsl .Specialization ;
80
82
import com .oracle .truffle .api .frame .VirtualFrame ;
83
+ import com .oracle .truffle .api .nodes .UnexpectedResultException ;
84
+ import com .oracle .truffle .api .object .DynamicObjectLibrary ;
85
+ import com .oracle .truffle .api .object .HiddenKey ;
81
86
import com .oracle .truffle .api .profiles .ConditionProfile ;
82
87
83
88
@ CoreFunctions (defineModule = "_thread" )
84
89
public class ThreadModuleBuiltins extends PythonBuiltins {
90
+ private static final HiddenKey THREAD_COUNT = new HiddenKey ("thread_count" );
91
+
85
92
@ Override
86
93
protected List <? extends NodeFactory <? extends PythonBuiltinBaseNode >> getNodeFactories () {
87
94
return ThreadModuleBuiltinsFactory .getFactories ();
@@ -91,6 +98,7 @@ protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFa
91
98
public void initialize (Python3Core core ) {
92
99
builtinConstants .put ("error" , core .lookupType (PythonBuiltinClassType .RuntimeError ));
93
100
builtinConstants .put ("TIMEOUT_MAX" , TIMEOUT_MAX );
101
+ builtinConstants .put (THREAD_COUNT , 0 );
94
102
super .initialize (core );
95
103
}
96
104
@@ -140,13 +148,17 @@ public static long getId() {
140
148
}
141
149
}
142
150
143
- @ Builtin (name = "_count" , minNumOfPositionalArgs = 0 )
151
+ @ Builtin (name = "_count" , minNumOfPositionalArgs = 1 , declaresExplicitSelf = true )
144
152
@ GenerateNodeFactory
145
- abstract static class GetThreadCountNode extends PythonBuiltinNode {
153
+ abstract static class GetThreadCountNode extends PythonUnaryBuiltinNode {
146
154
@ Specialization
147
155
@ TruffleBoundary
148
- long getCount () {
149
- return getContext ().getThreadGroup ().activeCount ();
156
+ long getCount (PythonModule self ) {
157
+ try {
158
+ return DynamicObjectLibrary .getUncached ().getIntOrDefault (self , THREAD_COUNT , 0 );
159
+ } catch (UnexpectedResultException e ) {
160
+ throw CompilerDirectives .shouldNotReachHere ();
161
+ }
150
162
}
151
163
}
152
164
@@ -189,6 +201,7 @@ long start(VirtualFrame frame, Object cls, Object callable, Object args, Object
189
201
@ Cached ExpandKeywordStarargsNode getKwArgsNode ) {
190
202
PythonContext context = getContext ();
191
203
TruffleLanguage .Env env = context .getEnv ();
204
+ PythonModule threadModule = context .getCore ().lookupBuiltinModule ("_thread" );
192
205
193
206
// TODO: python thread stack size != java thread stack size
194
207
// ignore setting the stack size for the moment
@@ -197,11 +210,31 @@ long start(VirtualFrame frame, Object cls, Object callable, Object args, Object
197
210
PKeyword [] keywords = getKwArgsNode .execute (kwargs );
198
211
199
212
try (GilNode .UncachedAcquire gil = GilNode .uncachedAcquire ()) {
200
- // n.b.: It is important to pass 'null' frame here because each thread has it's
201
- // own stack and if we would pass the current frame, this would be connected as
202
- // a caller which is incorrect. However, the thread-local 'topframeref' is
203
- // initialized with EMPTY which will be picked up.
204
- callNode .execute (null , callable , arguments , keywords );
213
+ // the increment is protected by the gil
214
+ DynamicObjectLibrary lib = DynamicObjectLibrary .getUncached ();
215
+ int curCount = 0 ;
216
+ try {
217
+ curCount = lib .getIntOrDefault (threadModule , THREAD_COUNT , 0 );
218
+ } catch (UnexpectedResultException ure ) {
219
+ throw CompilerDirectives .shouldNotReachHere ();
220
+ }
221
+ lib .putInt (threadModule , THREAD_COUNT , curCount + 1 );
222
+ try {
223
+ // n.b.: It is important to pass 'null' frame here because each thread has
224
+ // it's own stack and if we would pass the current frame, this would be
225
+ // connected as a caller which is incorrect. However, the thread-local
226
+ // 'topframeref' is initialized with EMPTY which will be picked up.
227
+ callNode .execute (null , callable , arguments , keywords );
228
+ } finally {
229
+ // the catch blocks run ofter the gil is released, so we decrement the
230
+ // threadcount here while still protected by the gil
231
+ try {
232
+ curCount = lib .getIntOrDefault (threadModule , THREAD_COUNT , 1 );
233
+ } catch (UnexpectedResultException ure ) {
234
+ throw CompilerDirectives .shouldNotReachHere ();
235
+ }
236
+ lib .putInt (threadModule , THREAD_COUNT , curCount - 1 );
237
+ }
205
238
} catch (PythonThreadKillException e ) {
206
239
return ;
207
240
} catch (PException e ) {
0 commit comments