Visitar URL original
src: update node.cc and related for z/OS · nodejs/node@63a1aec · GitHub
Skip to content

Commit 63a1aec

Browse files
committed
src: update node.cc and related for z/OS
- Add new src/node_zos.h and src/node_zos.cc, used by src/node.cc. - Add new src/zos_setlibpath.cc and link its .o directly into node so the __setlibpath object's constructor finds libnode.so and add its path to LIBPATH, so it can be loaded. - Pass '-Wl,-bedit=no' when linking libnode.so to reduce its size. - Use z/OS specific signal handling logic, as signals on z/OS must be handled in a dedicated thread. - Force V8 flag --nohard_abort due to absence of XPLINK headers in JS generated code. - Include display of zoslib build version. Signed-off-by: Gaby Baghdadi <baghdadi@ca.ibm.com>
1 parent cd18965 commit 63a1aec

5 files changed

Lines changed: 387 additions & 0 deletions

File tree

‎node.gyp‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,11 @@
652652
'deps/histogram/histogram.gyp:histogram',
653653
],
654654
}],
655+
[ 'OS=="zos" and node_shared=="true"', {
656+
'sources+': [
657+
'src/zos_setlibpath.cc',
658+
],
659+
}],
655660
[ 'error_on_warn=="true"', {
656661
'cflags': ['-Werror'],
657662
'xcode_settings': {
@@ -981,6 +986,17 @@
981986
'Ws2_32',
982987
],
983988
}],
989+
[ 'OS=="zos"', {
990+
'sources+': [
991+
'src/node_zos.h',
992+
'src/node_zos.cc',
993+
],
994+
'conditions': [
995+
[ 'node_shared=="true"', {
996+
'ldflags+': [ '-Wl,-bedit=no' ],
997+
}],
998+
],
999+
}],
9841000
[ 'node_use_openssl=="true"', {
9851001
'sources': [
9861002
'<@(node_crypto_sources)',
@@ -1501,6 +1517,11 @@
15011517
],
15021518

15031519
'conditions': [
1520+
[ 'OS=="zos"', {
1521+
'sources+': [
1522+
'src/zos_setlibpath.cc',
1523+
],
1524+
}],
15041525
['OS=="solaris"', {
15051526
'ldflags': [ '-I<(SHARED_INTERMEDIATE_DIR)' ]
15061527
}],
@@ -1669,6 +1690,12 @@
16691690
[ 'OS in "linux mac openharmony"', {
16701691
'defines': ['NODE_JS2C_USE_STRING_LITERALS'],
16711692
}],
1693+
[ 'OS=="zos"', {
1694+
'dependencies+': [
1695+
'<(static_zoslib_gyp):zoslib',
1696+
'<(static_zoslib_gyp):zoslib_alnewdel',
1697+
],
1698+
}],
16721699
[ 'debug_node=="true"', {
16731700
'cflags!': [ '-O3' ],
16741701
'cflags': [ '-g', '-O0' ],

‎src/node.cc‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@
100100
#endif
101101
#endif // NODE_USE_V8_WASM_TRAP_HANDLER
102102

103+
#if defined(__MVS__)
104+
#include "node_zos.h"
105+
#endif
106+
103107
// ========== global C headers ==========
104108

105109
#include <fcntl.h> // _O_RDWR
@@ -190,7 +194,11 @@ const char* conf_section_name = STRINGIFY(NODE_OPENSSL_CONF_NAME);
190194
#ifdef __POSIX__
191195
void SignalExit(int signo, siginfo_t* info, void* ucontext) {
192196
ResetStdio();
197+
#ifdef __MVS__
198+
zosSignalExit(signo, info, ucontext);
199+
#else
193200
raise(signo);
201+
#endif
194202
}
195203
#endif // __POSIX__
196204

@@ -486,6 +494,9 @@ void RegisterSignalHandler(int signal,
486494
memset(&sa, 0, sizeof(sa));
487495
sa.sa_sigaction = handler;
488496
sa.sa_flags = reset_handler ? SA_RESETHAND : 0;
497+
#ifdef __MVS__
498+
sa.sa_flags |= SA_ONSTACK | SA_SIGINFO;
499+
#endif
489500
sigfillset(&sa.sa_mask);
490501
CHECK_EQ(sigaction(signal, &sa, nullptr), 0);
491502
}
@@ -626,6 +637,9 @@ static void PlatformInit(ProcessInitializationFlags::Flags flags) {
626637
if (!(flags & ProcessInitializationFlags::kNoDefaultSignalHandling)) {
627638
RegisterSignalHandler(SIGINT, SignalExit, true);
628639
RegisterSignalHandler(SIGTERM, SignalExit, true);
640+
#ifdef __MVS__
641+
RegisterSignalHandler(SIGABRT, SignalExit, true);
642+
#endif
629643
}
630644

631645
if (!(flags & ProcessInitializationFlags::kNoAdjustResourceLimits)) {
@@ -836,6 +850,10 @@ static ExitCode ProcessGlobalArgsInternal(std::vector<std::string>* args,
836850
v8_args_as_char_ptr.resize(argc);
837851
}
838852

853+
#ifdef __MVS__
854+
V8::SetFlagsFromString("--nohard_abort", sizeof("--nohard_abort") - 1);
855+
#endif
856+
839857
// Anything that's still in v8_argv is not a V8 or a node option.
840858
for (size_t i = 1; i < v8_args_as_char_ptr.size(); i++)
841859
errors->push_back("bad option: " + std::string(v8_args_as_char_ptr[i]));
@@ -1284,6 +1302,9 @@ InitializeOncePerProcessInternal(
12841302
if (!(flags & ProcessInitializationFlags::kNoPrintHelpOrVersionOutput)) {
12851303
if (per_process::cli_options->print_version) {
12861304
printf("%s\n", NODE_VERSION);
1305+
#if defined(__MVS__)
1306+
__build_version();
1307+
#endif
12871308
result->exit_code_ = ExitCode::kNoFailure;
12881309
result->early_return_ = true;
12891310
return result;
@@ -1481,6 +1502,9 @@ InitializeOncePerProcessInternal(
14811502
}
14821503
}
14831504
}
1505+
#ifdef __MVS__
1506+
zosCreateSignalHandler();
1507+
#endif
14841508

14851509
if (!(flags & ProcessInitializationFlags::kNoInitializeNodeV8Platform)) {
14861510
uv_thread_setname("node-MainThread");
@@ -1614,6 +1638,11 @@ void TearDownOncePerProcess() {
16141638
#if HAVE_OPENSSL
16151639
crypto::CleanupCachedRootCertificates();
16161640
#endif // HAVE_OPENSSL
1641+
1642+
#ifdef __MVS__
1643+
zosCancelSignalHandler();
1644+
zosDestroyThread();
1645+
#endif
16171646
}
16181647

16191648
ExitCode GenerateAndWriteSnapshotData(const SnapshotData** snapshot_data_ptr,
@@ -1807,6 +1836,13 @@ static ExitCode StartInternal(int argc, char** argv) {
18071836
// Hack around with the argv pointer. Used for process.title = "blah".
18081837
argv = uv_setup_args(argc, argv);
18091838

1839+
#ifdef __MVS__
1840+
ExitCode exit_code = zosStart();
1841+
if (exit_code != ExitCode::kNoFailure) {
1842+
return exit_code;
1843+
}
1844+
#endif
1845+
18101846
std::shared_ptr<InitializationResultImpl> result =
18111847
InitializeOncePerProcessInternal(
18121848
std::vector<std::string>(argv, argv + argc),
@@ -1816,6 +1852,9 @@ static ExitCode StartInternal(int argc, char** argv) {
18161852
FPrintF(stderr, "%s: %s\n", result->args().at(0), error);
18171853
}
18181854
if (result->early_return()) {
1855+
#ifdef __MVS__
1856+
zosDestroyThread();
1857+
#endif
18191858
return result->exit_code_enum();
18201859
}
18211860

@@ -1832,6 +1871,9 @@ static ExitCode StartInternal(int argc, char** argv) {
18321871
});
18331872

18341873
uv_loop_configure(uv_default_loop(), UV_METRICS_IDLE_TIME);
1874+
#ifdef __MVS__
1875+
zosIgnorePipeChildSignals();
1876+
#endif
18351877
std::string sea_config = per_process::cli_options->experimental_sea_config;
18361878
if (!sea_config.empty()) {
18371879
#if defined(DISABLE_SINGLE_EXECUTABLE_APPLICATION)

‎src/node_zos.cc‎

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
// Copyright Joyent, Inc. and other Node contributors.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a
4+
// copy of this software and associated documentation files (the
5+
// "Software"), to deal in the Software without restriction, including
6+
// without limitation the rights to use, copy, modify, merge, publish,
7+
// distribute, sublicense, and/or sell copies of the Software, and to permit
8+
// persons to whom the Software is furnished to do so, subject to the
9+
// following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included
12+
// in all copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15+
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17+
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20+
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21+
22+
#include "node_zos.h"
23+
#include "env-inl.h"
24+
#include "node_internals.h"
25+
#include "node_watchdog.h"
26+
27+
#include <pthread.h>
28+
#include <signal.h>
29+
#include <sys/msg.h>
30+
31+
#ifndef NJS_PRODUCT_OWNER
32+
#error "NJS_PRODUCT_OWNER must be defined"
33+
#endif
34+
35+
#ifndef NJS_FEATURE_NAME
36+
#error "NJS_FEATURE_NAME must be defined"
37+
#endif
38+
39+
#ifndef NJS_PRODUCT_NAME
40+
#error "NJS_PRODUCT_NAME must be defined"
41+
#endif
42+
43+
#ifndef NJS_PID
44+
#error "NJS_PID must be defined"
45+
#endif
46+
47+
namespace {
48+
49+
uv_thread_t signalHandlerThread;
50+
char* galtStack = nullptr;
51+
52+
void __zosAtExit() {
53+
if (galtStack != nullptr) {
54+
free(galtStack);
55+
galtStack = nullptr;
56+
}
57+
}
58+
} // namespace
59+
60+
namespace node {
61+
62+
void zosDestroyThread() {
63+
uv_queue_work(nullptr, nullptr, nullptr, nullptr);
64+
SigintWatchdogHelper::GetInstance()->Stop();
65+
msgctl(uv_backend_fd(uv_default_loop()), IPC_RMID, nullptr);
66+
// Tell zoslib that main process is terminating, for its diagnostics:
67+
__mainTerminating();
68+
}
69+
70+
static void SignalHandlerThread(void* data) {
71+
while (1) {
72+
CHECK_EQ(pause(), -1);
73+
CHECK_EQ(errno, EINTR);
74+
}
75+
}
76+
77+
void zosCreateSignalHandler() {
78+
uv_thread_create(&signalHandlerThread, SignalHandlerThread, nullptr);
79+
// Block all signals on the main thread
80+
sigset_t set;
81+
sigfillset(&set);
82+
CHECK_EQ(0, pthread_sigmask(SIG_BLOCK, &set, nullptr));
83+
}
84+
85+
void zosCancelSignalHandler() {
86+
if (pthread_cancel(signalHandlerThread) == -1) abort();
87+
}
88+
89+
void zosSignalExit(int signo, siginfo_t* info, void* ucontext) {
90+
zosDestroyThread();
91+
// Use alternate stack in case LE uses main thread's sp upon termination.
92+
struct sigaction new_action;
93+
new_action.sa_flags = SA_ONSTACK;
94+
new_action.sa_handler = SIG_DFL;
95+
sigaction(signo, &new_action, nullptr);
96+
if (signo == SIGABRT)
97+
abort(); // from zoslib
98+
else
99+
raise(signo);
100+
}
101+
102+
void zosIgnorePipeChildSignals() {
103+
struct sigaction new_action;
104+
new_action.sa_handler = SIG_IGN;
105+
sigfillset(&new_action.sa_mask);
106+
sigaction(SIGPIPE, &new_action, nullptr);
107+
new_action.sa_handler = SIG_IGN;
108+
sigfillset(&new_action.sa_mask);
109+
sigaction(SIGCHLD, &new_action, nullptr);
110+
}
111+
112+
static void RegisterProduct() {
113+
std::string major_version = std::to_string(NODE_MAJOR_VERSION);
114+
std::string product_owner = NJS_PRODUCT_OWNER;
115+
std::string feature_name = NJS_FEATURE_NAME;
116+
std::string product_name = NJS_PRODUCT_NAME;
117+
std::string pid = NJS_PID;
118+
119+
std::string val;
120+
if (credentials::SafeGetenv("NODE_SMF89_REGISTRATION_VERBOSE", &val))
121+
printf("Product registration data:\n"
122+
"Product Name: %s\n"
123+
"PID Name: %s\n"
124+
"Major Version: %s\n"
125+
"Product Owner: %s\n"
126+
"Feature Name: %s\n",
127+
product_name.c_str(),
128+
pid.c_str(),
129+
major_version.c_str(),
130+
product_owner.c_str(),
131+
feature_name.c_str());
132+
133+
uint64_t rc = __registerProduct(major_version.c_str(),
134+
product_owner.c_str(),
135+
feature_name.c_str(),
136+
product_name.c_str(),
137+
pid.c_str());
138+
139+
if (rc && !credentials::SafeGetenv("NODE_SMF89_SUPPRESS_WARNING", &val)) {
140+
fprintf(stderr,
141+
"WARNING: Could not register product with IFAUSAGE, "
142+
"rc = %llu\n",
143+
rc);
144+
if (const char* errorString = getIFAUsageErrorString(rc))
145+
fprintf(stderr, "%s\n", errorString);
146+
147+
fprintf(stderr,
148+
"WARNING: Product usage data may not be collected. For more "
149+
"details on the product registration data, set environment "
150+
"variable NODE_SMF89_REGISTRATION_VERBOSE=1. To suppress this "
151+
"warning message set the environment variable "
152+
"NODE_SMF89_SUPPRESS_WARNING=1.\n");
153+
}
154+
}
155+
156+
ExitCode zosStart() {
157+
// Initialize environment variables in zoslib:
158+
zoslib_config_t config{
159+
.RUNTIME_LIMIT_ENVAR = "__NODERUNTIMELIMIT",
160+
.CCSID_GUESS_BUF_SIZE_ENVAR = "__NODECCSIDGUESSBUFSIZE"};
161+
if (__update_envar_names(&config) != 0) {
162+
return ExitCode::kGenericUserError;
163+
}
164+
165+
// Create an alternate stack for signal processing
166+
const unsigned int STACK_SIZE = SIGSTKSZ + 1024 * 1024;
167+
galtStack = (char*)malloc(STACK_SIZE);
168+
if (galtStack == nullptr) {
169+
return ExitCode::kGenericUserError;
170+
}
171+
stack_t ss = {.ss_sp = galtStack, .ss_size = STACK_SIZE, .ss_flags = 0};
172+
sigaltstack(&ss, 0);
173+
174+
if (__doLogMemoryUsage()) atexit(__zosAtExit);
175+
176+
return ExitCode::kNoFailure;
177+
}
178+
179+
} // namespace node

‎src/node_zos.h‎

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright Joyent, Inc. and other Node contributors.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a
4+
// copy of this software and associated documentation files (the
5+
// "Software"), to deal in the Software without restriction, including
6+
// without limitation the rights to use, copy, modify, merge, publish,
7+
// distribute, sublicense, and/or sell copies of the Software, and to permit
8+
// persons to whom the Software is furnished to do so, subject to the
9+
// following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included
12+
// in all copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15+
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17+
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20+
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21+
22+
#ifndef SRC_NODE_ZOS_H_
23+
#define SRC_NODE_ZOS_H_
24+
25+
#include "node_exit_code.h"
26+
27+
#include <csignal>
28+
29+
namespace node {
30+
31+
// used by node.cc:
32+
ExitCode zosStart();
33+
void zosCreateSignalHandler();
34+
void zosCancelSignalHandler();
35+
void zosSignalExit(int signo, siginfo_t* info, void* ucontext);
36+
void zosIgnorePipeChildSignals();
37+
void zosDestroyThread();
38+
39+
} // namespace node
40+
#endif // SRC_NODE_ZOS_H_

0 commit comments

Comments
 (0)