this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "under-signal-module.h"
3
4#include <unistd.h>
5
6#include <cerrno>
7#include <csignal>
8
9#include "builtins.h"
10#include "int-builtins.h"
11#include "module-builtins.h"
12#include "modules.h"
13#include "os.h"
14#include "runtime.h"
15#include "set-builtins.h"
16#include "symbols.h"
17#include "type-builtins.h"
18
19namespace py {
20
21void FUNC(_signal, __init_module__)(Thread* thread, const Module& module,
22 View<byte> bytecode) {
23 HandleScope scope(thread);
24 Object nsig(&scope, SmallInt::fromWord(OS::kNumSignals));
25 moduleAtPutById(thread, module, ID(NSIG), nsig);
26
27 Object sig_dfl(&scope, kDefaultHandler);
28 moduleAtPutById(thread, module, ID(SIG_DFL), sig_dfl);
29
30 Object sig_ign(&scope, kIgnoreHandler);
31 moduleAtPutById(thread, module, ID(SIG_IGN), sig_ign);
32
33 Object signum(&scope, NoneType::object());
34 for (const OS::Signal* signal = OS::kStandardSignals; signal->name != nullptr;
35 signal++) {
36 signum = SmallInt::fromWord(signal->signum);
37 moduleAtPutByCStr(thread, module, signal->name, signum);
38 }
39 for (const OS::Signal* signal = OS::kPlatformSignals; signal->name != nullptr;
40 signal++) {
41 signum = SmallInt::fromWord(signal->signum);
42 moduleAtPutByCStr(thread, module, signal->name, signum);
43 }
44
45 executeFrozenModule(thread, module, bytecode);
46
47 thread->runtime()->initializeSignals(thread, module);
48}
49
50void handleSignal(int signum) {
51 Thread* thread = Thread::current();
52 int saved_errno = errno;
53 thread->runtime()->setPendingSignal(thread, signum);
54 errno = saved_errno;
55}
56
57RawObject FUNC(_signal, default_int_handler)(Thread* thread, Arguments) {
58 return thread->raise(LayoutId::kKeyboardInterrupt, NoneType::object());
59}
60
61RawObject FUNC(_signal, getsignal)(Thread* thread, Arguments args) {
62 HandleScope scope(thread);
63 Runtime* runtime = thread->runtime();
64 Object obj(&scope, args.get(0));
65 if (!runtime->isInstanceOfInt(*obj)) {
66 return thread->raiseRequiresType(obj, ID(int));
67 }
68 word signum = intUnderlying(*obj).asWord();
69 if (signum < 1 || signum >= OS::kNumSignals) {
70 return thread->raiseWithFmt(LayoutId::kValueError,
71 "signal number out of range");
72 }
73 return runtime->signalCallback(signum);
74}
75
76RawObject FUNC(_signal, signal)(Thread* thread, Arguments args) {
77 HandleScope scope(thread);
78 Runtime* runtime = thread->runtime();
79 Object obj(&scope, args.get(0));
80 if (!runtime->isInstanceOfInt(*obj)) {
81 return thread->raiseRequiresType(obj, ID(int));
82 }
83
84 if (!thread->isMainThread()) {
85 return thread->raiseWithFmt(LayoutId::kValueError,
86 "signal only works in main thread");
87 }
88
89 word signum = intUnderlying(*obj).asWord();
90 if (signum < 1 || signum >= OS::kNumSignals) {
91 return thread->raiseWithFmt(LayoutId::kValueError,
92 "signal number out of range");
93 }
94
95 Object callback(&scope, args.get(1));
96 SignalHandler handler;
97 if (callback == kIgnoreHandler) {
98 handler = SIG_IGN;
99 } else if (callback == kDefaultHandler) {
100 handler = SIG_DFL;
101 } else {
102 Type type(&scope, runtime->typeOf(*callback));
103 if (typeLookupInMroById(thread, *type, ID(__call__)).isErrorNotFound()) {
104 return thread->raiseWithFmt(LayoutId::kTypeError,
105 "signal handler must be signal.SIG_IGN, "
106 "signal.SIG_DFL, or a callable object");
107 }
108 handler = handleSignal;
109 }
110
111 Object err(&scope, runtime->handlePendingSignals(thread));
112 if (err.isErrorException()) {
113 return *err;
114 }
115 if (OS::setSignalHandler(signum, handler) == SIG_ERR) {
116 return thread->raise(LayoutId::kOSError, NoneType::object());
117 }
118 return runtime->setSignalCallback(signum, callback);
119}
120
121RawObject FUNC(_signal, alarm)(Thread* thread, Arguments args) {
122 HandleScope scope(thread);
123 Runtime* runtime = thread->runtime();
124 Object obj(&scope, args.get(0));
125 if (!runtime->isInstanceOfInt(*obj)) {
126 return thread->raiseRequiresType(obj, ID(int));
127 }
128 obj = intUnderlying(*obj);
129 if (obj.isLargeInt()) {
130 return thread->raiseWithFmt(LayoutId::kOverflowError,
131 "Python int too large to convert to C long");
132 }
133 word seconds_remaining = ::alarm(Int::cast(*obj).asWord());
134 return SmallInt::fromWord(seconds_remaining);
135}
136
137RawObject FUNC(_signal, valid_signals)(Thread* thread, Arguments) {
138 HandleScope scope(thread);
139 Runtime* runtime = thread->runtime();
140 sigset_t mask;
141 if (sigemptyset(&mask) || sigfillset(&mask)) {
142 return thread->raiseWithFmt(LayoutId::kOSError,
143 "Error while retreiving valid signals.");
144 }
145 Set set(&scope, runtime->newSet());
146 Object value(&scope, NoneType::object());
147 for (word signal = 1; signal < NSIG; signal++) {
148 if (sigismember(&mask, signal) != 1) {
149 continue;
150 }
151 value = runtime->newInt(signal);
152 word hash = intHash(*value);
153 setAdd(thread, set, value, hash);
154 }
155 return *set;
156}
157
158RawObject FUNC(_signal, siginterrupt)(Thread* thread, Arguments args) {
159 HandleScope scope(thread);
160 Runtime* runtime = thread->runtime();
161 Object signalnum_obj(&scope, args.get(0));
162 if (!runtime->isInstanceOfInt(*signalnum_obj)) {
163 return thread->raiseWithFmt(LayoutId::kTypeError,
164 "`signalnum` must be an integer (got type %T)",
165 &signalnum_obj);
166 }
167 word signalnum = intUnderlying(*signalnum_obj).asWordSaturated();
168 Object flag_obj(&scope, args.get(1));
169 if (!runtime->isInstanceOfInt(*flag_obj)) {
170 return thread->raiseWithFmt(LayoutId::kTypeError,
171 "`flag` must be an integer (got type %T)",
172 &flag_obj);
173 }
174 word flag = intUnderlying(*flag_obj).asWordSaturated();
175
176 if (signalnum < 1 || signalnum >= NSIG) {
177 return thread->raiseWithFmt(LayoutId::kValueError,
178 "signal number out of range");
179 }
180#pragma GCC diagnostic push
181#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
182 word result = ::siginterrupt(signalnum, flag);
183#pragma GCC diagnostic pop
184 if (result < 0) {
185 return thread->raiseOSErrorFromErrno(-result);
186 }
187 return NoneType::object();
188}
189
190} // namespace py