How do I suspend another thread (not the current one)?

戏子无情 提交于 2019-12-06 03:32:20

问题


I'm trying to implement a simulation of a microcontroller. This simulation is not meant to do a clock cycle precise representation of one specific microcontroller but check the general correctness of the code.

I thought of having a "main thread" executing normal code and a second thread executing ISR code. Whenever an ISR needs to be run, the ISR thread suspends the "main thread".

Of course, I want to have a feature to block interrupts. I thought of solving this with a mutex that the ISR thread holds whenever it executes ISR code while the main thread holds it as long as "interrupts are blocked".

A POR (power on reset) can then be implemented by not only suspending but killing the main thread (and starting a new one executing the POR function).

The windows API provides the necessary functions. But it seems to be impossible to do the above with posix threads (on linux).

I don't want to change the actual hardware independent microcontroller code. So inserting anything to check for pending interrupts is not an option.

Receiving interrupts at non well behaved points is desirable, as this also happens on microcontrollers (unless you block interrupts).

Is there a way to suspend another thread on linux? (Debuggers must use that option somehow, I think.)

Please, don't tell me this is a bad idea. I know that is true in most circumstances. But the main code does not use standard libs or lock/mutexes/semaphores.


回答1:


Somehow I think sending the other thread SIGSTOP works.

However, you are far better off writing some thread communication involving senaogires.mutexes and global variables.

You see, if you suspend the other thread in malloc() and you call malloc() -> deadlock.

Did I mention that lots of C standard library functions, let alone other libraries you use, will call malloc() behind your back?

EDIT:

Hmmm, no standard library code. Maybe use setjmp/longjump() from signal handler to simulate the POR and a signal handier to simulate interrupt.

TO THOSE WHO KEEP DOWNVOTING THIS: The answer was accepted for the contents after EDIT, which is a specific scenario that cannot be used in any other scenario.




回答2:


SIGSTOP does not work - it always stops the entire process. Instead you can use some other signals, say SIGUSR1 for suspending and SIGUSR2 for resuming:

// at process start call init_pthread_suspending to install the handlers
// to suspend a thread use pthread_kill(thread_id, SUSPEND_SIG)
// to resume a thread use pthread_kill(thread_id, RESUME_SIG)

#include <signal.h>

#define RESUME_SIG SIGUSR2
#define SUSPEND_SIG SIGUSR1

static sigset_t wait_mask;
static __thread int suspended; // per-thread flag

void resume_handler(int sig)
{
    suspended = 0;
}

void suspend_handler(int sig)
{
    if (suspended) return;
    suspended = 1;
    do sigsuspend(&wait_mask); while (suspended);
}

void init_pthread_suspending()
{
    struct sigaction sa;

    sigfillset(&wait_mask);
    sigdelset(&wait_mask, SUSPEND_SIG)
    sigdelset(&wait_mask, RESUME_SIG);

    sigfillset(&sa.sa_mask);
    sa.sa_flags = 0;
    sa.sa_handler = resume_handler;
    sigaction(RESUME_SIG, &sa, NULL);

    sa.sa_handler = suspend_handler;
    sigaction(SUSPEND_SIG, &sa, NULL);
}

I am very annoyed by replies like "you should not suspend another thread, that is bad". Guys why do you assume others are idiots and don't know what they are doing? Imagine that others, too, have heard about deadlocking and still, in full consciousness, want to suspend other threads. If you don't have a real answer to their question why do you waste your and the readers' time.

An yes, IMO pthreads are very short-sighted api, a disgrace for POSIX.




回答3:


The Hotspot JAVA VM uses SIGUSR2 to implement suspend/resume for JAVA threads on linux.

A procedure based on on a signal handler for SIGUSR2 might be:

Providing a signal handler for SIGUSR2 allows a thread to request a lock (which has already been acquired by the signal sending thread).

This suspends the thread.

As soon as the suspending thread releases the lock, the signal handler can (and will?) get the lock. The signal handler releases the lock immediately and leaves the signal handler.

This resumes the thread.

It will probably be necessary to introduce a control variable to make sure that the main thread is in the signal handler before starting the actual processing of the ISR. (The details depend on whether the signal handler is called synchronously or asynchronously.)

I don't know, if this is exactly how it is done in the Java VM, but I think the above procedure does what I need.




回答4:


Solaris has the thr_suspend(3C) call that would do what you want. Is switching to Solaris a possibility?

Other than that, you're probably going to have to do some gymnastics with mutexes and/or semaphores. The problem is that you'll only suspend when you check the mutex, which will probably be at a well-behaved point. Depending on what you're actually trying to accomplish, this might now be desirable.




回答5:


It makes more sense to have the main thread execute the ISRs - because that's how the real controller works (presumably). Just have it check after each emulated instruction if there is both an interrupt pending, and interrupts are currently enabled - if so, emulate a call to the ISR.

The second thread is still used - but it just listens for the conditions which cause an interrupt, and mark the relevant interrupt as pending (for the other thread to later pick up).




回答6:


The solution using pthread_kill(3) and SIGUSR1, SIGUSER2 signals is a good solution but can still cause concurrency issue. Is there a way to suspend all threads (except main thread) at a safe point i.e. at the time of suspend threads should not have acquired any lock or not running in a system call?



来源:https://stackoverflow.com/questions/2208833/how-do-i-suspend-another-thread-not-the-current-one

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!