I am having some difficulty in understanding the below statement from LDD3. "down_interruptible - it allows a user-space process that is waiting on a semaphore to be interrupted by the user".
A userspace application wont be direclty making the down_interruptible call. Lets say a device driver does and the application is put to sleep by the device driver triggered by a call to down_interruptible. Now how does a signal to the user space application invokes the application from sleep because its the device driver which called the down_interruptible not the application.
Somebody please clarify this to me.
Any device driver does not run of its own, device driver run on behalf of a process via system calls.
Suppose any device driver invokes down_interruptible();, it means if semaphore is not available the respective process will be put on the semaphore wait-queue.
And task state will be change to TASK_INTERRUPTIBLE and scheduler will invoked to run any other process. Now the sleeping process can be wake up either by the event for it waiting (semaphore) or by the signal.
Example: kill -SIGINT <pid> will cause the process to change its state to TASK_RUNNING and will add the process to run queue.
Here it is the pseudo code of wait queue, how a process wait for any event.
/* ‘q’ is the wait queue we wish to sleep on */
DEFINE_WAIT(wait);
add_wait_queue(q, &wait);
while (!condition) /* condition is the event that we are waiting for */
{
prepare_to_wait(&q, &wait, TASK_INTERRUPTIBLE);
if (!signal_pending(current))
{
schedule();
continue;
}
ret = -ERESTARTSYS;
}
finish_wait(&q, &wait);
In your example the process is added to wait queue and waiting for the condition to release it. Meanwhile it checks for any pending signal also, if there is any, it will return -ERESTARTSYS, otherwise again go for sleep.
Related
The kernel code can explicitly put the process to sleep if it's waiting for some task to occur. Now, if the task is put in TASK_INTERRUPTIBLE state, it can wake either by explicit wake up call or by receiving a signal.
Let's say another process issued a signal to a process which is in the wait queue and in TASK_INTERRUPTIBLE state, it will put the process into TASK_RUNNING and the signal will be handled when the process is scheduled next. Is this correct?
An explicit wake up call by other process can also be used to wake up the slept processes. I am wondering how could another process know when the condition became true for the slept process to wake up? Suppose a disk i/o is to be completed and so the process is put to sleep. How could another process know that the i/o is completed? Or is it done by kernel threads?
What am I missing?
It is up to the code that entered the interruptible state to detect the interruption and take appropriate action when it wakes. That might involve the code that is currently handling the user operation completing it with a -ERESTARTSYS error that will be intercepted and dealt with before the system call returns to user mode.
The code that has completed some I/O can just issue a "wake up" to the queue it is responsible for without caring whether there is any task on the queue to be woken up, or the exact condition the task is waiting for.
The task that is woken up needs to decide what to do, and that could include repeating the wait if the the condition it is waiting for had not been satisfied.
When a process calls wait_event_interruptible the process goes to sleep(assuming the condition is satisfied and there are no pending signals) the scheduler removes the process from the run queue to the wait queue.
When there is wake_up call how exactly and who removes the process from wait queue and keeps it in the run queue?
Thaks
The "wake_up call" is a system call done by another thread/process/task (some kernels put state on thread rather than process) with the thread/process/task to wake up in parameter. Because the system call is an interrupt (int $0x80 on Linux, until it was recently replaced by sysenter which is basically the same), thus entering the kernel, the scheduler will be called and the requested thred/process/task will be poped out the blocked queue and pushed into the ready queue. If this thread/process/task has the highest priority, it will eventually run when returning from the interrupt, therefore going directly from the blocked state to the running state.
I have multi thread program. I have a design of my application as follows:
Suppose one is main thread, and other are slave threads. Main thread keep track of all slave thread ID's. During one of the scenario of application (one of the scenario is graceful shutdown of application), i want to delete slave threads from main thread.
Here slave threads may be executing i.e., either in sleep mode or doing some action which i cannot stop the action. So i want to delete the threads from main thread with thread IDs i stored internally.
Additional info:
While deleting i should not wait for thread current action to complete as it may take long time as i am reading from data base and taking some action in thread, in case of gracefull shut down i should not wait for action to complete as it may take time.
If i force delete a thread how can there will be a resource leaks?
Is above design is ok or there is any flow or any ways we can improve the design.
Thanks!
It's not okay. It's a bad practice to forcefully kill a thread from another thread because you'll very likely to have resource leaks. The best way is to use an event or signal to signal the client process to stop and wait until they exit gracefully.
The overall flow of the program would look like this:
Parent thread creates an event (say hEventParent). it then creates child threads and passes hEventParent as a parameter. The Parent thread keeps the hThread of the child thread(s).
Child threads do work but periodically waits for hEventParent.
When the program needs to exit, the parent thread sets hEventParent. It then waits for hThread (WaitForMultipleObjects also accepts hThread)
Child thread is notified then execute clean up routine and exits.
When all the threads exit, the parent can then exit.
The most common approach consists in the main thread sending a termination signal to all the threads, then waiting for the threads to end.
Typically the worker threads will have a loop, inside of which the work is done. You can add a boolean variable that indicates if the thread needs to end. For example:
terminate = false;
while (!terminate) {
// work here
}
If you want your worker threads to go to sleep when they have no work, then it gets a bit more complicated. In this case you could make the threads wait on semaphores. Each semaphore will be signaled when there is work to do, and that will awaken the thread. You will also signal the semaphore when the request to terminate is issued. Example worker thread:
terminate = false;
while (!terminate) {
// work here
wait(semaphore); // go to sleep
}
When the main thread wants to exit it will set terminate to true for all the threads and then signal the thread semaphores to awaken the threads and give them a chance to see the termination request. After that it will join all the threads, and only after all the threads are finished it will exit.
Note that the terminate boolean may need to be declared as volatile if you are using C/C++, to indicate to the compiler that it may be changed from another thread.
I have a test case where there are threads spawned using CLONE_THREAD option in clone() .Here if i want to kill a particular thread I suppose we should be using SYS_tgkill in systemcall(). But will the kill actually affect a thread if it is waiting in kernel space(say a futex_wait)?
I tried killing a thread created in the above manner.But when SIGKILL is sent to the same the whole process is getting killed.Am i missing something in using syscall(SYS_tgkill,pid,tid,9) ?
SIGKILL always kills the target process. There is no way around this; it's unblockable, unignorable, and uncatchable.
You could try sending another signal (like SIGUSR1 or SIGHUP or SIGRTMIN) and having a signal handler installed that calls pthread_exit (but note that this function is not async-signal-safe, so you must ensure that the signal handler did not interrupt another async-signal-unsafe function) or use cancellation (pthread_cancel) to stop the blocked thread.
This should work for normal blocking operations (like waiting for data from a pipe or socket), but it will not help you if the thread is in an uninterruptable sleep state (like trying to read from a badly scratched CD or failing hard disk).
How does a process get terminated? Lets say a process has three threads A,B & C. Now when we send a SIG_KILL signal to the process. All is fine so far, Now each process has exit status field in its structure! So, when a process is sent a kill signal, my understanding is that it is sent to all the threads. A thread gets killed either when it traps into kernel. If it is alreading in the kernel, it quits when it exits from the kernel. If a thread is sleeping it exits when it wakes up. Is my understanding right or am i misunderstading/missing something?
If my understanding is correct, when is a process put into zombie list? when all the threads exited or as soon as it receives a kill signal?
Lets say a process has three threads A,B & C.
Ok. I assume modern Linux, with kernel supporting threads (Linux 2.6 + glibc > 2.3)
Then the process (or thread group) consists of 3 threads (or, there is a 3 threads with different tids and same tgid=PID)
Now when we send a SIG_KILL signal to the process.
So, you use a tgid (PID) here. Ok.
Now each process has exit status field in its structure!
Wwwhat? Yes, but killing and exiting from thread group have a special code to get right exit code to waiter. For killing, the exit status is get from signal; for exiting (syscall sys_group_exit) it is the argument of syscall.
So, when a process is sent a kill signal,... it is sent to all the threads.
No.
Basically there can be two kinds of signals:
process-wide - it will be delivered to ANY thread in the process
thread (Can't name it correctly) - which is delivered by tid to some thread and not another.
So, SIGKILL is process-wide, it will kill entire process. It is delivered to some thread.
When kernel will deliver this signal - it will call do_group_exit() function ( http://lxr.linux.no/linux+v2.6.28/kernel/exit.c#L1156 called from http://lxr.linux.no/linux+v2.6.28/kernel/signal.c#L1870) to kill all threads in thread group (in process).
There is a zap_other_threads() function to iterate over all threads and kill them (with resending a thread-delivered SIGKILL) http://lxr.linux.no/linux+v2.6.28/kernel/signal.c#L966
when is a process put into zombie list?
After do_exit() kernel function call. It has a tsk->state = TASK_DEAD; line at the end.
when all the threads exited or as soon as it receives a kill signal?
The moment, when task get its state to TASK_DEAD is after receiving SIGKILL. This signal is already redelivered to all threads of the process at this moment. Can't find the actual exit time of threads, but all threads have a flag of pending fatal signal, so they will be killed at any resched.
UPDATE: all threads of process must be killed (must receive the KILL signal and do a cleanup), as they have some accounting information to be accumulated in the first thread (here first mention not the first-started, but the thread which got an original process-wide SIGKILL; or the thread, which called an exit_group syscall). First thread must wait all another threads; and it will change status only after that.
In FreeBSD, a zombie process cannot execute any code. Therefore, everything that needs the moribund process to do something is performed before that point. If you see a process in this state in ps(1) (usually only if it gets stuck), it has a usual state such as D, S, R or I, with E (trying to exit) appended to it.
A signal is delivered to one thread (either a particular thread or any thread, depending on how the signal was generated). The act of terminating the process (default action of various signals) has a process-global effect. One of the things that happens is that the thread that was chosen to deliver the signal (or that called _exit(2)) requests all other threads to exit.
A thread does not have an exit status at the kernel level; the value available via pthread_join() is a userland feature.