CreateJobObject behaviour when already inside a job - c

My scenario: I have a C program in Windows that, in running time, corresponds to process A; it needs to start another process (process B) and monitor it so that, under some external event (say, lock file removed) it can terminate B and all its eventual children (processes started by B).
My approach was to place B into a job created with CreateJobObject, so that process A can terminate it (together with its children) with TerminateJobObject - and then it can terminate itself.
HANDLE jobHandle = CreateJobObject(NULL, NULL); // creates job
...
res=CreateProcess(NULL,cmdline, .... &pi); // creates process B
AssignProcessToJobObject(jobHandle,pi.hProcess); // add process B to job
...
if(...) {
TerminateJobObject(jobHandle,exitCode); // terminate job: process B and children
....
}
This works. Except that, under certain circumstances [*] the process A happens to be already included in a job. In this case CreateJobObject(NULL, NULL) does not create a new job, but it returns the current one - which is not what I want.
How do create a wholly new job?
I don't want to rely on nested jobs, because I want to support Windows 7.
[*] I'm looking at you, Eclipse - but that does not matter much now.

From comments:
The solution was to add the flag CREATE_BREAKAWAY_FROM_JOB to the CreateProcess call:
res=CreateProcess(NULL,cmdline, NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
CREATE_BREAKAWAY_FROM_JOB, // don't place inside old job
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ); // Pointer to PROCESS_INFORMATION structure
Two caveats:
For this to work, the old job must have the JOB_OBJECT_LIMIT_BREAKAWAY_OK flag enabled - it was in my case.
I had wrongly believed that, in my original code, the call CreateJobObject(NULL, NULL) returned the old job and that's why the new process ended in the old job - if that were true, then this solution would not work. But it was not true, what happened was that AssignProcessToJobObject failed (my fault for not checking return code) because the newly created process was already placed in the old job. CreateJobObject(NULL, NULL) returns a new job.

Related

How can a Ruby C extension store a proc for later execution?

Goal: allow c extension to receive block/proc for delayed execution while retaining current execution context.
I have a method in c (exposed to ruby) that accepts a callback (via VALUE hash argument) or a block.
// For brevity, lets assume m_CBYO is setup to make a CBYO module available to ruby
extern VALUE m_CBYO;
VALUE CBYO_add_callback(VALUE callback)
{
if (rb_block_given_p()) {
callback = rb_block_proc();
}
if (NIL_P(callback)) {
rb_raise(rb_eArgError, "either a block or callback proc is required");
}
// method is called here to add the callback proc to rb_callbacks
}
rb_define_module_function(m_CBYO, "add_callback", CBYO_add_callback, 1);
I have a struct I'm using to store these with some extra data:
struct rb_callback
{
VALUE rb_cb;
unsigned long long lastcall;
struct rb_callback *next;
};
static struct rb_callback *rb_callbacks = NULL;
When it comes time (triggered by an epoll), I iterate over the callbacks and execute each callback:
rb_funcall(cb->rb_cb, rb_intern("call"), 0);
When this happens I am seeing that it successfully executes the ruby code in the callback, however, it is escaping the current execution context.
Example:
# From ruby including the above extension
CBYO.add_callback do
puts "Hey now."
end
loop do
puts "Waiting for signal..."
sleep 1
end
When a signal is received (via epoll) I will see the following:
$> Waiting for signal...
$> Waiting for signal...
$> Hey now.
$> // process hangs
$> // Another signal occurs
$> [BUG] vm_call_cfunc - cfp consistency error
Sometimes, I can get more than one signal to process before the bug surfaces again.
I found the answer while investigating a similar issue.
As it turns out, I too was trying to use native thread signals (with pthread_create) which are not supported with MRI.
TLDR; the Ruby VM is not currently (at the time of writing) thread safe. Check out this nice write-up on Ruby Threading for a better overall understanding of how to work within these confines.
You can use Ruby's native_thread_create(rb_thread_t *th) which will use pthread_create behind the scenes. There are some drawbacks that you can read about in the documentation above the method definition. You can then run the callback with Ruby's rb_thread_call_with_gvl method. Also, I haven't done it here, but it might be a good idea to create a wrapper method so you can use rb_protect to handle exceptions the callback may raise (otherwise they will be swallowed by the VM).
VALUE execute_callback(VALUE callback)
{
return rb_funcall(callback, rb_intern("call"), 0);
}
// execute the callback when the thread receives signal
rb_thread_call_with_gvl(execute_callback, data->callback);

Why does posix_spawn() fail where popen() works?

I'm successfully using popen() to run commands from within my C program. As I understand, it uses fork() and exec() (or variants of those) behind the curtains. This works very well:
FILE *fd = popen("xterm", "r");
pclose(fd);
... will bring up a new xterm window, as expected.
Now I'm trying to achieve the same with posix_spawn(), which I understand to be possibly more resource-friendly, especially if we don't plan on communicating with the new child process:
/* p.we_wordv contains the argv, index 0 holds the actual command */
pid_t pid;
posix_spawnp(&pid, p.we_wordv[0], NULL, NULL, p.we_wordv, NULL);
... but this, for xterm as the command, yields the following on the parent's output:
xterm: Xt error: Can't open display:
xterm: DISPLAY is not set
Trying to launch other processes will yield other error messages, fail silently, or, in some cases like ls, work as expected. This makes it a bit hard for me to actually see a pattern yet.
Can you point out what is causing the second approach to behave differently than the first?
The message DISPLAY is not set tells you that xterm didn't find the DISPLAY environment variable. All graphical-output programs use this environment variable to connect to your screen.
It didn't find the variable because the environment was empty (it's the last NULL in your posix_spawnp function call). It seems that popen reuses the environment of current process, so it doesn't have this problem.
You might want to pass a manually-created environment, containing only the needed stuff, or just pass whatever environment your process has. The latter is more flexible (xterm will inherit various configuration settings from your process, which inherits them from your shell) but may be a security risk.
To access the environment of your process, use the environ global variable or change your main function to receive an additional parameter:
int main(int argc, char *argv[], char *envp[])
{
...
posix_spawnp(&pid, p.we_wordv[0], NULL, NULL, p.we_wordv, envp);
}

How to use Notepad++ as editor for 7zip, without showing a console window?

This question could be generalized as: How to launch a given process with any intermediate process spawned having the same lifetime as the launched process, and without showing a console window. Specific arguments must be passed to the final process, but no arguments can be passed in the initial call.
To use Notepad++ as editor for 7zip you would need to launch notepad++.exe with the -multiInst command line parameter, otherwise it instantly closes and forwards arguments to the existing instance. Since 7zip picks up the changes you did to its temp file when the invoked program closes, you never get a chance to edit it.
Problem is, 7zip doesn't allow you to enter arguments for whatever program you're configuring as editor.
Obvious solutions that don't work, already tried:
Call a batch file, but then I'm stuck with an unsightly (and easy to close accidentally) console window for the duration of the edition - not acceptable.
Call a batch file which uses start to call Notepad++ : the console window does close, but unfortunately the batch executor process which is what Notepad++ was watching is gone, so it thinks you're already done editing, i.e. back to the initial problem.
Use wscript, which doesn't show a console window. Tracking the process lifetime is complex however (Wait for program to complete) and it makes you rely on old tech in maintenance mode that has a malware connotation.
How would you go about this? No solution I've tried myself or read about has been fully satisfying.
Note: this is not exactly the same question as Execute Batch File without Command line visible since this has the added requirement that whatever launcher used must stay open for the whole lifetime of the launched process, and that you can't pass command line arguments to the launcher.
I ended up writing my own utility which I'm tentatively calling NoConsoleProgramLauncher to serve as an intermediate between 7z and Notepad++. It's rough first draft code, but I thought sharing it might still be useful since this question has been without answer for three years.
#include <fstream>
#include <string>
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <filesystem>
HINSTANCE hInst;
void launchProcess(std::wstring commandLine);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
//Get current executable's location
HMODULE hModule = GetModuleHandleW(NULL);
WCHAR executableFolder[MAX_PATH];
GetModuleFileNameW(hModule, executableFolder, MAX_PATH);
std::experimental::filesystem::v1::path path(executableFolder);
path.remove_filename();
path.append(L"NoConsoleProgramLauncher_Arguments.txt");
std::wifstream infile(path);
std::wstring commandLine;
std::getline(infile, commandLine);
commandLine += L" ";
commandLine += lpCmdLine;
launchProcess(commandLine);
}
void launchProcess(std::wstring commandLine)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// Start the child process.
if (!CreateProcess(NULL, // No module name (use command line)
&commandLine[0], // Command line - C++ 11 guarantees that string's internal buffer is contiguous and null-terminated.
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
CREATE_NO_WINDOW, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
printf("CreateProcess failed (%d).\n", GetLastError());
return;
}
// Wait until child process exits.
WaitForSingleObject(pi.hProcess, INFINITE);
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
Basically, if you've done a minimum of C++ coding before, it's a matter of pasting this into a new Visual Studio 2017 Windows Desktop Application project, fixing up the includes if needed, and building.
As you can see in the source code, when launched the executable looks for a file in the same folder as itself named "NoConsoleProgramLauncher_Arguments.txt", and calls the command line it finds in there. As specified in the question, no console window will be shown, and the program will wait for the spawned process to terminate before exiting, so 7zip keeps waiting to pick up the changes.
This is what I put in my NoConsoleProgramLauncher_Arguments.txt file:
"C:\Program Files (x86)\Notepad++\notepad++.exe" -multiInst -nosession
And in the 7zip configuration, I've set the editor to point to my NoConsoleProgramLauncher.exe program.
The real solution would of course be to gently pester the 7z authors about this, or better, submit a pull request to 7z to implement passing arguments to your editor of choice.

run external .exe under thread

I need to run an external exe "embed.exe" under my WPF project,
here's a snippet
ProcessStartInfo processInf = new ProcessStartInfo("embed.exe");
processInf.Arguments = string.Format(#"Some arguments");
processInf.WindowStyle = ProcessWindowStyle.Hidden;
Process run = Process.Start(processInf);
my problem is that it's block my UI,
is there a way to include embed.exe using a thread or any code that won't block the UI ?
OK,
Try to put your previous snippet inside a method, then create a new thread and initialize it to that method.
here's how to make it
//hone code
private void EmbedMethod()
{
ProcessStartInfo processInf = new ProcessStartInfo("embed.exe");
processInf.Arguments = string.Format(#"Some arguments");
processInf.WindowStyle = ProcessWindowStyle.Hidden;
Process run = Process.Start(processInf);
}
Thread embedThread=new Thread(EmbedMethod);
embedThread.start();
The process you started is running on its own thread, not the thread your application used to start it.
To terminate your embed.exe process you need to keep a reference to the Process started. In this case the run variable. To terminate the process call either:
run.CloseMainWindow() or run.Kill().
Kill forces a termination of the process, while CloseMainWindow only requests a termination.

How Do I Compile a C Program to Run Without a Command Box?

I need a very simple program to run on any version of Windows, let's say >= Win 98, without requiring any pre-installed framework like dotnet. I thought C would be a great idea to do this.
The program should start a process from the parent directory by using a system command.
Start C program (invisible) > program starts process > program exits
This is how it looks:
#include <stdio.h>
#include <stdlib.h>
int main() {
system("..\\someprogram.exe");
return 0;
}
I call this program from a Flash projector, which only allows to start programs in a specific subfolder "fscommand" – but I have to start a process located in the same directory as the projector.
Anyway, it works fine! But the C program opens a command box, then starts the process and leaves the command box open as long as the process runs. So here is how it should work, in order how i would appreciate it:
Do not open a command box at all (I'd like that, really ;)
Both 3) and 4)
Close the command box after starting the process (exit the C program)
Open the command box minimized by default
I can't change any Windows settings for the C executable or use a shortcut, as this will run directly from a CD later.
I use Open Watcom to compile my program. Both image types (target options) that produce an executable (Character-mode Executable / Windowed Executable) have the same result.
I did a google search and found http://www.ntwind.com/software/utilities/hstart.html
Your using a console app, you could change it to a windows app using winmain()
You can use a shortcut to a file in the same folder, not sure why your discounting that method.
start will give you a fork so your intermediate app can close - not sure about win98 tho.
system("start ..\\someprogram.exe");
Instead of system you can use createProcess to launch the app, theis will avoid the system commands console.
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
if( !CreateProcess( "..\\someprogram.exe", // module name
NULL, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
return;
}
// Wait until child process exits. In your case you don't care to wait anyway
// WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
The console window shows up because you built your program as a console application. I don't know how to avoid that in C, but in Delphi is was a simple {$Console Off} pragma in the project file.
GCC has a command line option -mwindows, which I think achieves the same, so you could search into this direction.
I think the _exec and/or _spawn functions do what you need, though I'm not sure.
If not, you can always use CreateProcess, though it can be a little more tedious in some ways.
You could (for example) use hstart instead of your own program to start that exe.
(This would result in no black box at all.)
CreateProcess with CREATE_NO_WINDOW flag is what you want, but I want to add something. To support also cmd style commands (such as DIR, SET, ... ) which have no executables and can't be passed to CreateProcess alone, you should call cmd.exe /C someprogram where someprogram is name of executable, bat file, or command.
A friend came up with a completely different solution. Now I use AutoIt with a short compiled script to start the process. This is very simple and the launcher process is completely invisible. :)
filename = ..\someprogram.exe
if FileExist(filename) {
Run, open %filename%
}

Resources