this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "builtins.h"
3#include "exception-builtins.h"
4#include "frame.h"
5#include "globals.h"
6#include "handles.h"
7#include "modules.h"
8#include "os.h"
9#include "runtime.h"
10#include "sys-module.h"
11#include "thread.h"
12
13namespace py {
14
15RawObject FUNC(_thread, get_ident)(Thread* thread, Arguments) {
16 return thread->runtime()->newIntFromCPtr(thread);
17}
18
19static void* threadBegin(void* arg) {
20 Thread* thread = reinterpret_cast<Thread*>(arg);
21 thread->begin();
22 {
23 HandleScope scope(thread);
24 Object func(&scope, thread->stackPeek(2));
25 Object result(
26 &scope, Interpreter::callEx(thread, CallFunctionExFlag::VAR_KEYWORDS));
27 if (result.isErrorException()) {
28 if (thread->pendingExceptionMatches(LayoutId::kSystemExit)) {
29 thread->clearPendingException();
30 } else {
31 // TODO(T89490118): call sys.unraisablehook instead
32 Object exc(&scope, thread->pendingExceptionType());
33 Object val(&scope, thread->pendingExceptionValue());
34 Object tb(&scope, thread->pendingExceptionTraceback());
35 thread->clearPendingException();
36
37 Object func_str(&scope,
38 thread->invokeFunction1(ID(builtins), ID(str), func));
39 if (func_str.isErrorException()) {
40 writeStderr(thread, "Exception ignored in thread started by: \n");
41 } else {
42 Str str(&scope, strUnderlying(*func_str));
43 word length = str.length();
44 unique_c_ptr<byte[]> buf(
45 reinterpret_cast<byte*>(std::malloc(length + 1)));
46 str.copyTo(buf.get(), length);
47 buf[length] = '\0';
48 writeStderr(thread, "Exception ignored in thread started by: %s\n",
49 buf.get());
50 }
51
52 thread->setPendingExceptionType(*exc);
53 thread->setPendingExceptionValue(*val);
54 thread->setPendingExceptionTraceback(*tb);
55 printPendingException(thread);
56 }
57 }
58 }
59 thread->runtime()->deleteThread(thread);
60 return nullptr;
61}
62
63static RawObject startNewThread(Thread* thread, Arguments args) {
64 HandleScope scope(thread);
65 Runtime* runtime = thread->runtime();
66 // TODO(T66337218): remove this guard once threading is safe
67 if (runtime->lookupNameInModule(thread, ID(_thread), ID(_enable_threads))
68 .isErrorNotFound()) {
69 UNIMPLEMENTED(
70 "PyRO runtime is not thread-safe. "
71 "Set `_thread._enable_threads = True` to bypass.");
72 }
73 Object func(&scope, args.get(0));
74 if (!runtime->isCallable(thread, func)) {
75 return thread->raiseWithFmt(LayoutId::kTypeError,
76 "first arg must be callable");
77 }
78 Object args_obj(&scope, args.get(1));
79 if (!runtime->isInstanceOfTuple(*args_obj)) {
80 return thread->raiseWithFmt(LayoutId::kTypeError,
81 "2nd arg must be a tuple");
82 }
83 Object kwargs(&scope, args.get(2));
84 if (kwargs.isUnbound()) {
85 kwargs = runtime->newDict();
86 } else if (!runtime->isInstanceOfDict(*kwargs)) {
87 return thread->raiseWithFmt(LayoutId::kTypeError,
88 "optional 3rd arg must be a dictionary");
89 }
90 Thread* new_thread = runtime->newThread();
91 new_thread->stackPush(*func);
92 new_thread->stackPush(*args_obj);
93 new_thread->stackPush(*kwargs);
94 OS::createThread(threadBegin, new_thread);
95 return runtime->newIntFromCPtr(new_thread);
96}
97
98RawObject FUNC(_thread, start_new)(Thread* thread, Arguments args) {
99 return startNewThread(thread, args);
100}
101
102RawObject FUNC(_thread, start_new_thread)(Thread* thread, Arguments args) {
103 return startNewThread(thread, args);
104}
105
106} // namespace py