Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split OS::execute into two methods #44514

Merged
merged 1 commit into from
Jan 12, 2021

Conversation

madmiraal
Copy link
Contributor

Currently, OS::execute does two different things depending on whether the third parameter (blocking) is true or not. This PR splits OS::execute into two methods:

  1. execute(): Executes a command and returns the results. The old default execute blocking = true method.
  2. create_process(): Creates a new process and returns the new process' id. The old execute blocking = false method.

Note: It now also appends the shell output String to the provided output Array instead of overwriting it.

Closes #19302.
Part of #16863.

@madmiraal madmiraal force-pushed the split-os-execute branch 2 times, most recently from e2b986e to 3159077 Compare December 21, 2020 11:53
@akien-mga akien-mga requested a review from Faless December 28, 2020 13:56
1. execute(): Executes a command and returns the results.
2. create_process(): Creates a new process and returns the new process' id.
@madmiraal
Copy link
Contributor Author

Rebased following merge of #44645.

Copy link
Collaborator

@Faless Faless left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, I don't have much experience with the Windows part, but the unix part seems good. Great job 🥇

@@ -617,7 +617,7 @@ MainLoop *test() {

List<String> args;
args.push_back("-l");
Error err = OS::get_singleton()->execute("/bin/ls", args, true, nullptr, &ret);
Error err = OS::get_singleton()->execute("/bin/ls", args, &ret);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure why this is here, but it's fine for now should probably be re-evaluated in a separate PR.

Copy link
Member

@akien-mga akien-mga Jan 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That does look like a copy paste error from OS tests to math tests. Could be removed, but this can indeed be done in another PR. The whole file should be rewritten to use the new test framework anyway.

This should likely be listed in #43440 BTW @Calinou.

@akien-mga akien-mga merged commit 1218441 into godotengine:master Jan 12, 2021
@akien-mga
Copy link
Member

Thanks!

fprintf(stderr, "**ERROR** OS_Unix::execute - Could not create child process while executing: %s\n", p_path.utf8().get_data());
raise(SIGKILL);
// The execvp() function only returns if an error occurs.
CRASH_NOW_MSG("Could not create child process: " + p_path);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRASH_NOW_MSG will may cause unnecessary crash report generation and "Godot quit unexpectedly" dialog popping up on macOS, when an invalid executable is specified (reintroduce #17615 fixed in #41188).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRASH_NOW_MSG() calls __builtin_trap(). Although __builtin_trap() is implementation dependent, it should raise a SIGTRAP (to generate a stack trace if there is one) and then raise SIGKILL.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not triggering "Godot quit unexpectedly", but, unlike SIGKILL generating a completely useless crash log twice (once it's generated by crash_handler_osx.mm and redirected to null, and second time by OS crash handler).

Click to expand crash log
Exception Type:        EXC_BAD_INSTRUCTION (SIGABRT)
Exception Codes:       0x0000000000000001, 0x0000000000000000
Exception Note:        EXC_CORPSE_NOTIFY

Application Specific Information:
*** multi-threaded process forked ***
crashed on child side of fork pre-exec

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib        	0x00007fff2039f462 __pthread_kill + 10
1   libsystem_pthread.dylib       	0x00007fff203cd610 pthread_kill + 263
2   libsystem_c.dylib             	0x00007fff20320720 abort + 120
3   godot.osx.tools.x86_64        	0x000000010068c71c handle_crash(int) + 2908 (crash_handler_osx.mm:153)
4   libsystem_platform.dylib      	0x00007fff20411d7d _sigtramp + 29
5   ???                           	0x00007ffeef56fd18 0 + 140732913876248
6   godot.osx.tools.x86_64        	0x00000001046010e4 _OS::create_process(String const&, Vector<String> const&) + 228 (core_bind.cpp:252)
7   godot.osx.tools.x86_64        	0x0000000104636aa6 void call_with_variant_args_ret_helper<__UnexistingClass, int, String const&, Vector<String> const&, 0ul, 1ul>(__UnexistingClass*, int (__UnexistingClass::*)(String const&, Vector<String> const&), Variant const**, Variant&, Callable::CallError&, IndexSequence<0ul, 1ul>) + 262 (binder_common.h:562)
8   godot.osx.tools.x86_64        	0x000000010463696e void call_with_variant_args_ret_dv<__UnexistingClass, int, String const&, Vector<String> const&>(__UnexistingClass*, int (__UnexistingClass::*)(String const&, Vector<String> const&), Variant const**, int, Variant&, Callable::CallError&, Vector<Variant> const&) + 350 (binder_common.h:397)
9   godot.osx.tools.x86_64        	0x0000000104636704 MethodBindTR<int, String const&, Vector<String> const&>::call(Object*, Variant const**, int, Callable::CallError&) + 228 (method_bind.h:451)
10  godot.osx.tools.x86_64        	0x0000000104bd787e Object::call(StringName const&, Variant const**, int, Callable::CallError&) + 1038 (object.cpp:784)
11  godot.osx.tools.x86_64        	0x000000010493f14a Variant::call(StringName const&, Variant const**, int, Variant&, Callable::CallError&) + 746 (variant_call.cpp:611)
12  godot.osx.tools.x86_64        	0x00000001014c8a8f GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) + 35711 (gdscript_vm.cpp:1372)
13  godot.osx.tools.x86_64        	0x00000001013b3a04 GDScriptInstance::call(StringName const&, Variant const**, int, Callable::CallError&) + 180 (gdscript.cpp:1555)
14  godot.osx.tools.x86_64        	0x0000000104c09cc1 ScriptInstance::call(StringName const&, Variant const&, Variant const&, Variant const&, Variant const&, Variant const&) + 273 (script_language.cpp:314)
15  godot.osx.tools.x86_64        	0x00000001030bd50d Node::_notification(int) + 4285 (node.cpp:147)
16  godot.osx.tools.x86_64        	0x0000000103027bfb Node::_notificationv(int, bool) + 155 (node.h:45)
17  godot.osx.tools.x86_64        	0x0000000103027aaf CanvasItem::_notificationv(int, bool) + 63 (canvas_item.h:164)
18  godot.osx.tools.x86_64        	0x00000001030279bf Control::_notificationv(int, bool) + 63 (control.h:47)
19  godot.osx.tools.x86_64        	0x0000000104bd4b2b Object::notification(int, bool) + 59 (object.cpp:793)
20  godot.osx.tools.x86_64        	0x00000001030beb58 Node::_propagate_ready() + 280 (node.cpp:188)
21  godot.osx.tools.x86_64        	0x00000001030beaee Node::_propagate_ready() + 174 (node.cpp:180)
22  godot.osx.tools.x86_64        	0x00000001030c4b37 Node::_set_tree(SceneTree*) + 167 (node.cpp:2561)
23  godot.osx.tools.x86_64        	0x00000001030fbf1d SceneTree::initialize() + 45 (scene_tree.cpp:395)
24  godot.osx.tools.x86_64        	0x000000010068ed22 OS_OSX::run() + 66 (os_osx.mm:315)
25  godot.osx.tools.x86_64        	0x00000001006c23f2 main + 1090 (godot_main_osx.mm:79)
26  libdyld.dylib                 	0x00007fff203e8621 start + 1

Nothing terrible, but it's a half minute of fully loaded CPU core and 70 KB of wasted disk space for each failed call, with no apparent benefits.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It also looks like it's raising a SIGABRT, so yes, it makes sense to use the previous approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Split OS.execute into blocking and non-blocking method
4 participants