summaryrefslogtreecommitdiff
path: root/src/pal/src/exception/signal.cpp
diff options
context:
space:
mode:
authorAditya Mandaleeka <adityam@microsoft.com>2015-08-06 18:43:43 -0700
committerAditya Mandaleeka <adityam@microsoft.com>2015-08-13 12:24:59 -0700
commita0bb6f06b2313ee2cae556af4e47139329ac9098 (patch)
tree24ade4c62c63047255715ccf38bc3c5f15ebe762 /src/pal/src/exception/signal.cpp
parent6b8d992844994ac5e52344dd6f2eec2074790231 (diff)
downloadcoreclr-a0bb6f06b2313ee2cae556af4e47139329ac9098.tar.gz
coreclr-a0bb6f06b2313ee2cae556af4e47139329ac9098.tar.bz2
coreclr-a0bb6f06b2313ee2cae556af4e47139329ac9098.zip
Add support for injecting activation functions into threads.
Use signals to interrupt the specified thread and have it call the activation function passed in.
Diffstat (limited to 'src/pal/src/exception/signal.cpp')
-rw-r--r--src/pal/src/exception/signal.cpp125
1 files changed, 125 insertions, 0 deletions
diff --git a/src/pal/src/exception/signal.cpp b/src/pal/src/exception/signal.cpp
index a2e276284c..8ece9ee24e 100644
--- a/src/pal/src/exception/signal.cpp
+++ b/src/pal/src/exception/signal.cpp
@@ -46,6 +46,8 @@ using namespace CorUnix;
SET_DEFAULT_DEBUG_CHANNEL(EXCEPT);
+#define INJECT_ACTIVATION_SIGNAL SIGRTMIN
+
/* local type definitions *****************************************************/
#if !HAVE_SIGINFO_T
@@ -73,6 +75,8 @@ void CorUnix::resume_handler(int code, siginfo_t *siginfo, void *context);
static void common_signal_handler(PEXCEPTION_POINTERS pointers, int code,
native_context_t *ucontext);
+static void inject_activation_handler(int code, siginfo_t *siginfo, void *context);
+
static void handle_signal(int signal_id, SIGFUNC sigfunc, struct sigaction *previousAction);
static void restore_signal(int signal_id, struct sigaction *previousAction);
@@ -138,6 +142,8 @@ BOOL SEHInitializeSignals()
handle_signal(SIGUSR2, resume_handler, &g_previous_sigusr2);
#endif
+ handle_signal(INJECT_ACTIVATION_SIGNAL, inject_activation_handler, NULL);
+
/* The default action for SIGPIPE is process termination.
Since SIGPIPE can be signaled when trying to write on a socket for which
the connection has been dropped, we need to tell the system we want
@@ -561,6 +567,125 @@ static void sigbus_handler(int code, siginfo_t *siginfo, void *context)
/*++
Function :
+ inject_activation_handler
+
+ Handle the INJECT_ACTIVATION_SIGNAL signal. This signal interrupts a running thread
+ so it can call the activation function that was specified when sending the signal.
+
+Parameters :
+ POSIX signal handler parameter list ("man sigaction" for details)
+
+(no return value)
+--*/
+static void inject_activation_handler(int code, siginfo_t *siginfo, void *context)
+{
+ // Only accept activations from the current process
+ if (siginfo->si_pid == getpid())
+ {
+ PAL_ActivationFunction activation = (PAL_ActivationFunction)siginfo->si_value.sival_ptr;
+ if (activation != NULL)
+ {
+ native_context_t *ucontext = (native_context_t *)context;
+
+ CONTEXT winContext;
+ CONTEXTFromNativeContext(
+ ucontext,
+ &winContext,
+ CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT);
+
+ activation(&winContext);
+
+ // Activation function may have modified the context, so update it.
+ CONTEXTToNativeContext(&winContext, ucontext);
+ }
+ }
+}
+
+/*++
+Function :
+ InjectActivationInternal
+
+ Interrupt the specified thread and have it call the activationFunction passed in
+
+Parameters :
+ pThread - target PAL thread
+ activationFunction - function to call
+
+(no return value)
+--*/
+void InjectActivationInternal(CorUnix::CPalThread* pThread, PAL_ActivationFunction activationFunction)
+{
+ sigval value;
+ value.sival_ptr = (void*)activationFunction;
+ int status = pthread_sigqueue(pThread->GetPThreadSelf(), INJECT_ACTIVATION_SIGNAL, value);
+ if (status != 0)
+ {
+ // Failure to send the signal is fatal. There are only two cases when sending
+ // the signal can fail. First, if the signal ID is invalid and second,
+ // if the thread doesn't exist anymore.
+ abort();
+ }
+}
+
+/*++
+Function:
+PAL_InjectActivation
+
+Interrupt the specified thread and have it call the activation function passed in
+
+Parameters:
+hThread - handle of the target thread
+activationFunction - function to call
+
+Return:
+TRUE if it succeeded, FALSE otherwise.
+--*/
+BOOL
+PALAPI
+PAL_InjectActivation(
+ IN HANDLE hThread,
+ IN PAL_ActivationFunction pActivationFunction)
+{
+ PERF_ENTRY(PAL_InjectActivation);
+ ENTRY("PAL_InjectActivation(hThread=%p, pActivationFunction=%p)\n", hThread, pActivationFunction);
+
+ CPalThread *pCurrentThread;
+ CPalThread *pTargetThread;
+ IPalObject *pobjThread = NULL;
+
+ pCurrentThread = InternalGetCurrentThread();
+
+ PAL_ERROR palError = InternalGetThreadDataFromHandle(
+ pCurrentThread,
+ hThread,
+ 0,
+ &pTargetThread,
+ &pobjThread
+ );
+
+ if (palError == NO_ERROR)
+ {
+ InjectActivationInternal(pTargetThread, pActivationFunction);
+ }
+ else
+ {
+ pCurrentThread->SetLastError(palError);
+ }
+
+ if (pobjThread != NULL)
+ {
+ pobjThread->ReleaseReference(pCurrentThread);
+ }
+
+ BOOL success = (palError == NO_ERROR);
+ LOGEXIT("PAL_InjectActivation returns:d\n", success);
+ PERF_EXIT(PAL_InjectActivation);
+
+ return success;
+}
+
+/*++
+Function :
SEHSetSafeState
specify whether the current thread is in a state where exception handling