diff options
author | Aditya Mandaleeka <adityam@microsoft.com> | 2015-08-06 18:43:43 -0700 |
---|---|---|
committer | Aditya Mandaleeka <adityam@microsoft.com> | 2015-08-13 12:24:59 -0700 |
commit | a0bb6f06b2313ee2cae556af4e47139329ac9098 (patch) | |
tree | 24ade4c62c63047255715ccf38bc3c5f15ebe762 /src/pal/src/exception/signal.cpp | |
parent | 6b8d992844994ac5e52344dd6f2eec2074790231 (diff) | |
download | coreclr-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.cpp | 125 |
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 |