I have process worker which launches executor. Executor is a process which creates a 10-sec task and executes it. But after 2 sec worker kills executor process. SimGrid gives me a log after killing executor:
[ 2.000000] (0:maestro#) dp_objs: 1 pending task?
How should I properly destroy tasks and task_data when another process kill currently working process?
int worker(int argc, char *argv[])
{
msg_process_t x = MSG_process_create("", executor, NULL, MSG_host_self());
MSG_process_sleep(2);
MSG_process_kill(x);
}
int executor(){
MSG_process_on_exit(my_onexit, NULL);
task = MSG_task_create("", 1e10, 10, NULL);
MSG_task_execute(task);
return 0;
}
int my_onexit() {
MSG_task_cancel(task);
XBT_INFO("Exiting now (done sleeping or got killed).");
return 0;
}
UPD:
I declared a global variable msg_task_t task.
Now when I run code I have:
[ 2.000000] (0:maestro#) Oops ! Deadlock or code not perfectly clean.
[ 2.000000] (0:maestro#) 1 processes are still running, waiting for something.
[ 2.000000] (0:maestro#) Legend of the following listing: "Process <pid> (<name>#<host>): <status>"
[ 2.000000] (0:maestro#) Process 2 (#Worker2)
Process finished with exit code 134 (interrupted by signal 6: SIGABRT)
I expected that simgrid would show xbt_info message, but it didn't and interrupted with SIGABRT error.
You should MSG_task_cancel() the task that you want to "kill". You could do that in a function that is registered in the MSG_process_on_exit() callback.
Thinking again about it, the message that you see is not an error message but merely a warning. You can ignore it safely. I am pretty sure that executed tasks are automatically canceled when the processor is killed.
So you don't have anything to do anything to get it working, I'd say. Just ignore that message.
Related
I have come across a problem with my application and the spawnProcess.
If the main application for some reason dies/is killed then the spawned processes seem to live on and I can't reach them unless I use terminal to kill them via their PIDs. My goal is if the main application dies then the spawned processes should be killed also, somehow.
My code is like this
auto appPid = spawnProcess("path/to/process");
scope(exit){ auto exitcode = wait(appPid);
stderr.writeln(...);}
And if I use the same approach when the main process dies, using wait(thisProcessID) I get an error. "No overload matches". Any ideas how to solve this problem?
Here's some code that will do it on Linux. It doesn't have all the features of the stdlib's spawnProcess, it just shows the bare basics, but expanding it from here isn't hard if you need more.
import core.sys.posix.unistd;
version(linux) {
// this function is Linux-specific
import core.stdc.config;
import core.sys.posix.signal;
// we can tell the kernel to send our child process a signal
// when the parent dies...
extern(C) int prctl(int, c_ulong, c_ulong, c_ulong, c_ulong);
// the constant I pulled out of the C headers
enum PR_SET_PDEATHSIG = 1;
}
pid_t mySpawnProcess(string process) {
if(auto pid = fork()) {
// this branch is the parent, it can return the child pid
// you can:
// import core.sys.posix.sys.wait;
// waitpid(this_ret_value, &status, 0);
// if you want the parent to wait for the child to die
return pid;
} else {
// child
// first, tell it to terminate when the parent dies
prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0);
// then, exec our process
char*[2] args;
char[255] buffer;
// gotta copy the string into another buffer
// so we zero terminate it and have a C style char**...
buffer[0 .. process.length] = process[];
buffer[process.length] = 0;
args[0] = buffer.ptr;
// then call exec to run the new program
execve(args[0], args.ptr, null);
assert(0); // never reached
}
}
void main() {
mySpawnProcess("/usr/bin/cat");
// parent process sleeps for one second, then exits
usleep(1_000_000);
}
So the lower level functions need to be used, but Linux does have a function that does what you need.
Of course, since it sends a signal, your child might want to handle that to close more gracefully than the default termination, but try this program and run ps while it sleeps to see cat running, then notice the cat dies when the parent exits.
void cpu_idle (void)
{
/* endless idle loop with no priority at all */
while (1) {
void (*idle)(void) = pm_idle;
if (!idle)
idle = default_idle;
if (!current->need_resched)
idle();
schedule();
check_pgt_cache();
}
}
this code existed in : "arch/i386/kernel/process.c" related to linux 2.4.18-14
this code is responsable of the ( cpu idle loop ).
the question is : can I change the while(1) loop with bust wait ?
The loop here properly schedules processes so the system continues to run properly. Switching to a pure busy wait would lock up the system when the cpu goes idle, meaning other processes would cease to be scheduled. You definitely do not want that.
Is it possible to pause a different task than the one on behalf of which the kernel is currently executing? To stop the current task, one can just set it to inactive and call schedule, but what about a different one?
What I have currently:
void disable_thread(struct task_struct *tsk) {
if (tsk->state == TASK_RUNNING) {
/*
* A running task - mark it stopped and wait for it to be descheduled
*/
tsk->state = TASK_INTERRUPTIBLE;
wait_task_inactive(tsk, TASK_INTERRUPTIBLE);
} else if (tsk->state == TASK_INTERRUPTIBLE || tsk->state == TASK_UNINTERRUPTIBLE) {
/*
* // TODO: what to do with tasks already waiting for something else?
*/
} else {
/*
* This task's state seems to indicate that it's dead, no need to disable it anymore.
*/
}
}
Stopping a running thread seems to work this way, but what can we do if the thread is already waiting for something else (e.g. waiting to acquire a lock), to prevent it from restarting even if it would get the lock?
I'm implementing a security feature, and can give more context if needed.
Thanks in advance.
I have this piece of code in a program function.
And there is a test script which hits this code path.
script goes through this function multiple times (~1000).
fork() call is successful as I can see child pid from parent block syslog but I don't see anything from child block.
This does NOT happen always. Happens only once in a hundred attempts.
Any idea what can be the general reasons for this to happen.
And what should I look for to get more information about the failure.
int i;
if ((i = fork()) < 0) {
syslog(LOG_NOTICE, "(%s): fork failed!\n", __func__);
}
if (i) {
syslog(LOG_NOTICE, "(%s): fork Parent: id: %d\n", __func__, i);
} else {
syslog(LOG_NOTICE, "(%s): fork child\n", __func__);
/* Do something */
}
Output:
telnetd[24600]: (startslave): fork Parent: id: 24601
<Thats it, no log after this!!>
To be exact, this is a part of freeBSD telnetd startslave() code, and script is just trying to login using telnet and logout for 1000 times and it fails sometimes. Failure is guaranteed, it can happen may be after 100 attempts or may be after 700 attempts.
I am trying some simple code on fork. When I give code like this, it works fine. It will print
I am the child
I am the parent
and then waits for 30 seconds. I understand this is due to switching between these two process. First child executes then parent and then child...
#include<stdio.h>
#include<stdlib.h>
main()
{
int pid;
pid=fork();
if(pid==0)
{
printf("\nI am the child\n");
sleep(30);
exit(0);
}
if(pid>0)
{
printf("\nI am the parent\n");
wait();
}
}
But when I gave like (without wait in parent)
#include<stdio.h>
#include<stdlib.h>
main()
{
int pid;
pid=fork();
if(pid==0)
{
printf("\nI am the child\n");
sleep(30);
exit(0);
}
if(pid>0)
{
printf("\nI am the parent\n");
}
}
it just prints
I am the child
I am the parent
and exits ( no waiting for 30 seconds).
So is it because without wait call parent exits and child still executing? But why is it not showing up in terminal (the waiting)?
Whether parent becomes zombie here?
Your observations are correct.
The terminal waits for the original processes (which is the parent) to exit. It doesn't wait for any child processes to exit.
Zombies: A process is a zombie if it has exited but its parent has not called wait() on it.
In your case, the parent does not become a zombie because the terminal is waiting for it.
Yes.
The grandparent never waits on children; children without a parent are reparented to init.
No, it dies.
The shell is waiting for the parent to finish but not the child.
The child becomes a zombie after 30 seconds (that the shell will clean up with the next prompt).
On the second example the child becomes orphan because the parent had returned while the child is alive. Orphan process belong to init and not the shell, that's why it's not showing up. There is no zombies in your two code samples. Zombies are when a parent is alive an child is dead and the parent doesnt call wait the child becomes zombie.