package main
import (
"os"
"os/signal"
log "github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
func main() {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, unix.SIGHUP)
go func() {
s := <-sigs
log.Info("OS signal: " + s.String())
}()
DoSomething()
}
I compiled the Go code above and executed with following command:
nohup ./build_linux > /dev/null 2>&1 &
But the process still catches HANGUP signal when I exit the terminal.
Seems like signal.Notify has higher priority, and nohup command has no effect.
What's going on and why nohup does not prevent sending hangup signal to process?
TL;DR
Check signal.Ignored() first:
if !signal.Ignored(unix.SIGHUP) {
signal.Notify(sigs, unix.SIGHUP)
}
Long
tkausl's comment has the correct answer: running:
nohup ./build_linux
from the command line launches the ./build_linux program with SIGHUP set to SIG_IGN (all of these signal names being generic Linux names, rather than Go package names). If you install your own handler for SIGHUP, this overrides the current setting of SIGHUP.
In general, in Unix/Linux programs, the correct pattern is to test whether the signal is currently ignored before (or as part of) installing a signal-catch function. If the signal is ignored, restore it to being ignored.
To make this process completely reliable, the most efficient correct pattern to use is:
hold off the signal (perhaps all signals);
install any desired handler, which returns the current disposition of the signal;
if the current disposition was SIG_IGN, return the disposition to SIG_IGN;
release the signal.
The holding-and-releasing is done with the Unix/Linux sigprocmask or pthread_sigmask system call. The one to use depends on whether you're using threads. Go of course does use threads; see, e.g., this patch to the Cgo runtime startup from 2013 (fixes issue #6811).
Since Go 1.11, which introduced signal.Ignored, you can just use that, as the Go runtime has already done all the appropriate hold / set-and-test / restore sequence at startup, and cached the result. One should definitely use this for SIGHUP so as to obey the nohup convention. One should generally use this for SIGINT and other keyboard signals as well, and there's almost1 no reason not to use it for all signals.1
1Jenkins, or some version or versions of Jenkins at least, apparently (incorrectly) sets all signals to be ignored at startup when running test suites.
Related
I have an Android app that uses NDK - a regular Android Java app with regular UI and C++ core. There are places in the core where I need to call Java methods, which means I need a JNIEnv* for that thread, which in turn means that I need to call JavaVM->AttachCurrentThread() to get the valid env.
Previously, was just doing AttachCurrentThread and didn't bother to detach at all. It worked fine in Dalvik, but ART aborts the application as soon as a thread that has called AttachCurrentThread exits without calling DetachCurrentThread. So I've read the JNI reference, and indeed it says that I must call DetachCurrentThread. But when I do that, ART aborts the app with the following message:
attempting to detach while still running code
What's the problem here, and how to call DetachCurrentThread properly?
Dalvik will also abort if the thread exits without detaching. This is implemented through a pthread key -- see threadExitCheck() in Thread.cpp.
A thread may not detach unless its call stack is empty. The reasoning behind this is to ensure that any resources like monitor locks (i.e. synchronized statements) are properly released as the stack unwinds.
The second and subsequent attach calls are, as defined by the spec, low-cost no-ops. There's no reference counting, so detach always detaches, no matter how many attaches have happened. One solution is to add your own reference-counted wrapper.
Another approach is to attach and detach every time. This is used by the app framework on certain callbacks. This wasn't so much a deliberate choice as a side-effect of wrapping Java sources around code developed primarily in C++, and trying to shoe-horn the functionality in. If you look at SurfaceTexture.cpp, particularly JNISurfaceTextureContext::onFrameAvailable(), you can see that when SurfaceTexture needs to invoke a Java-language callback function, it will attach the thread, invoke the callback, and then if the thread was just attached it will immediately detach it. The "needsDetach" flag is set by calling GetEnv to see if the thread was previously attached.
This isn't a great thing performance-wise, as each attach needs to allocate a Thread object and do some internal VM housekeeping, but it does yield the correct behavior.
I'll try a direct and practical approach (with sample code, without use of classes) answering this question for the occasional developer that came up with this error in android, in cases where they had it working and after a OS or framework update (Qt?) it started to give problems with that error and message.
JNIEXPORT void Java_com_package_class_function(JNIEnv* env.... {
JavaVM* jvm;
env->GetJavaVM(&jvm);
JNIEnv* myNewEnv; // as the code to run might be in a different thread (connections to signals for example) we will have a 'new one'
JavaVMAttachArgs jvmArgs;
jvmArgs.version = JNI_VERSION_1_6;
int attachedHere = 0; // know if detaching at the end is necessary
jint res = jvm->GetEnv((void**)&myNewEnv, JNI_VERSION_1_6); // checks if current env needs attaching or it is already attached
if (JNI_EDETACHED == res) {
// Supported but not attached yet, needs to call AttachCurrentThread
res = jvm->AttachCurrentThread(reinterpret_cast<JNIEnv **>(&myNewEnv), &jvmArgs);
if (JNI_OK == res) {
attachedHere = 1;
} else {
// Failed to attach, cancel
return;
}
} else if (JNI_OK == res) {
// Current thread already attached, do not attach 'again' (just to save the attachedHere flag)
// We make sure to keep attachedHere = 0
} else {
// JNI_EVERSION, specified version is not supported cancel this..
return;
}
// Execute code using myNewEnv
// ...
if (attachedHere) { // Key check
jvm->DetachCurrentThread(); // Done only when attachment was done here
}
}
Everything made sense after seeing the The Invocation API docs for GetEnv:
RETURNS:
If the current thread is not attached to the VM, sets *env to NULL, and returns JNI_EDETACHED. If the specified version is not supported, sets *env to NULL, and returns JNI_EVERSION. Otherwise, sets *env to the appropriate interface, and returns JNI_OK.
Credits to:
- This question Getting error "attempting to detach while still running code" when calling JavaVm->DetachCurrentThread that in its example made it clear that it was necessary to double check every time (even though before calling detach it doesn't do it).
- #Michael that in this question comments he notes it clearly about not calling detach.
- What #fadden said: "There's no reference counting, so detach always detaches, no matter how many attaches have happened."
I'm trying to develop a GDB python extension that defines a command that launches a new thread, in which the user can inspect an arbitrary type of variables. The skeleton of my python extension is this:
import gdb
import threading
def plot_thread():
import time
while True:
print('Placeholder for a window event loop.')
time.sleep(1)
pass
pass
class PlotterCommand(gdb.Command):
def __init__(self):
super(PlotterCommand, self).__init__("plot",
gdb.COMMAND_DATA,
gdb.COMPLETE_SYMBOL)
self.dont_repeat()
pass
def invoke(self, arg, from_tty):
plot_thread_instance=threading.Thread(target=plot_thread)
plot_thread_instance.daemon=True
plot_thread_instance.start()
pass
pass
PlotterCommand()
As can be seen, I define a plot command here. When I try to debug the following program, GDB will hang if I:
Put a breakpoint anywhere inside the procedure() thread (say, line 9, inside the while loop).
Run the command plot after gdb hits the breakpoint.
Run continue after that.
#include <iostream>
#include <thread>
using namespace std;
void procedure() {
cout << "before loop"<<endl;
while(1) {
cout << "loop iteration"<<endl;
}
}
int main() {
thread t(procedure);
t.join();
return 0;
}
The strangest thing is that, if I change this code to call procedure() without launching a thread, GDB never hangs (and the placeholder messages are still printed as I expect).
So far, I've tried to run this procedure with GDB versions 7.5.1 and 7.10, but I always experience the same behavior.
What am I doing wrong? Aren't daemon threads not supported by GDB? That doesn't seem to be in accordance with what the section 23.2.2.1 of the documentation is suggesting: GDB may not be thread safe, but I don't think it should hang after launching such a silly daemon thread.
From this blog post:
GDB uses this function (sigsuspend, the function where GDB hangs) to wait for new events from the application execution: when something occurs in the debuggee (see how debuggers work), the kernel will inform GDB of it by sending a SIGCHLD signal. When it's received, GDB awakes and check what happened.
However, the signal is delivered to GDB process, but not necessarily to its main thread. And it practise, it occurs often that it's delivered to the second thread, who doesn't care about it (that's the default behavior), and continues its life as if nothing occurred.
The solution is to configure the thread signal handling behavior, so that only the GDB main thread gets notified by these signals:
import gdb
import threading
import pysigset, signal # Import these packages!
def plot_thread():
import time
while True:
print('Placeholder for a window event loop.')
time.sleep(1)
pass
pass
class PlotterCommand(gdb.Command):
def __init__(self):
super(PlotterCommand, self).__init__("plot",
gdb.COMMAND_DATA,
gdb.COMPLETE_SYMBOL)
self.dont_repeat()
pass
def invoke(self, arg, from_tty):
with pysigset.suspended_signals(signal.SIGCHLD): # Disable signals here!
plot_thread_instance=threading.Thread(target=plot_thread)
plot_thread_instance.daemon=True
plot_thread_instance.start()
pass
pass
pass
PlotterCommand()
The pysigset package is required, and can be installed from pip (sudo pip install pysigset).
In Jenkins I have a system groovy script build step. Is there any way to cancel a long running script, or to have some code within the system groovy script which can tell whether its build has been cancelled?
Jenkins will interrupt the thread which is running the script when you cancel the build.
So you can either manually check the thread's interrupt status and abort your script at certain points, e.g.
if (Thread.currentThread().interrupted()) {
throw new InterruptedException()
}
Or you can let Groovy do that for you by including the ThreadInterrupt annotation in your script, e.g.
#groovy.transform.ThreadInterrupt
Also make sure that none of your catch blocks will swallow an InterruptedException.
I have to stop the earlier instances of processes before starting a new instance. For this i need to system call or a C library call.
Presently i use "system("killall name"). This works but I want to replace this with any equivalent system(2)/library(3) calls. What is the option?
Also to remove files from directory as in "system("rm -f /opt/files*")",
what would be the alternate library(3)/system(2) call?
Pleas note * in file names, remove all files with one call.
regards,
AK
As far as I know there is no general way to do it, as there is no general way to get the pid by its process name.
You have to collect the pids of related processes and call the int kill(pid_t pid, int signo); function
At least you can try to check how its implemented by killall itself
A small addition from Ben's link, killall invokes following lines, i.e. collecting the pids of related process by find_pid_by_name function, implementation of which can be found here
pidList = find_pid_by_name(arg);
if (*pidList == 0) {
errors++;
if (!quiet)
bb_error_msg("%s: no process killed", arg);
} else {
pid_t *pl;
for (pl = pidList; *pl; pl++) {
if (*pl == pid)
continue;
if (kill(*pl, signo) == 0)
continue;
errors++;
if (!quiet)
bb_perror_msg("can't kill pid %d", (int)*pl);
}
}
You can see the implementation in busybox here: http://git.busybox.net/busybox/tree/procps/kill.c
You can also link with busybox as a shared library and invoke its kill_main instead of launching a separate process. It looks fairly well behaved for embedding like this -- always returns normally, never calls exit() -- although you may have difficultly getting error information beyond the return code. (But you aren't getting that via system() either).
Good day, i have next code:
server s;
namespace signals_handler
{
//sig_atomic_t is_stop=0;
void signal_handler(int sig)
{
if(sig==SIGHUP)
{
printf("recived :SIGHUP\n");
s.restart();
}
else if(sig==SIGINT)
{
printf("recived :SIGINT\n");
//is_stop = 1;
s.interupt();
}
}
}
int main(int argc, char* argv[])
{
signal(SIGHUP, signals_handler::signal_handler);
signal(SIGINT, signals_handler::signal_handler);
s.start();
s.listen();
return 0;
}
When i start execution of this code i can to catch SIGHUP, SIGINT not deliver for my application but debugger stoped in the "listen" function but not move to signalhandler function, Why this happens and what i doing wrongly?
It's normal. gdb catches the signal. From the manual:
Normally, gdb is set up to let the non-erroneous signals like SIGALRM
be silently passed to your program (so as not to interfere with their
role in the program's functioning) but to stop your program
immediately whenever an error signal happens. You can change these
settings with the handle command.
To change the behaviour, use:
handle SIGINT nostop pass
handle signal [keywords...]
Change the way gdb handles signal signal. signal can be the number of a signal or its name (with or without the ‘SIG’ at the beginning);
a list of signal numbers of the form ‘low-high’; or the word ‘all’,
meaning all the known signals. Optional arguments keywords, described
below, say what change to make.
The keywords allowed by the handle command can be abbreviated. Their
full names are:
nostop
gdb should not stop your program when this signal happens. It may still print a message telling you that the signal has come in.
stop
gdb should stop your program when this signal happens. This implies the print keyword as well.
print
gdb should print a message when this signal happens.
noprint
gdb should not mention the occurrence of the signal at all. This implies the nostop keyword as well.
pass
noignore
gdb should allow your program to see this signal; your program can handle the signal, or else it may terminate if the signal is fatal and not handled. pass and noignore are synonyms.
nopass
ignore
gdb should not allow your program to see this signal. nopass and ignore are synonyms.