2010-02-05 27 views
5

Sto provando ad implementare una simulazione di un microcontrollore. Questa simulazione non è pensata per eseguire una rappresentazione precisa del ciclo di clock di uno specifico microcontrollore ma controllare la correttezza generale del codice.Come sospendere un altro thread (non quello corrente)?

Ho pensato di avere un "thread principale" che eseguiva codice normale e un secondo thread che eseguiva codice ISR. Ogni volta che è necessario eseguire un ISR, il thread ISR sospende il "thread principale".

Naturalmente, voglio avere una funzione per bloccare gli interrupt. Ho pensato di risolvere questo problema con un mutex che il thread ISR contiene quando esegue il codice ISR mentre il thread principale lo tiene finché "gli interrupt sono bloccati".

Un POR (power on reset) può essere implementato non solo sospendendo ma uccidendo il thread principale (e iniziando uno nuovo eseguendo la funzione POR).

L'API di Windows fornisce le funzioni necessarie. Ma sembra impossibile fare quanto sopra con i thread posix (su linux).

Non voglio modificare il codice del microcontrollore indipendente dall'hardware. Quindi l'inserimento di qualsiasi cosa per verificare interruzioni in sospeso non è un'opzione.

La ricezione di interrupt a punti non ben funzionanti è auspicabile, come accade anche sui microcontrollori (a meno che non si blocchino interruzioni).

C'è un modo per sospendere un altro thread su linux? (I debuttanti devono usare questa opzione in qualche modo, credo.)

Per favore, non dirmi che questa è una cattiva idea. So che è vero nella maggior parte delle circostanze. Ma il codice principale non usa libs standard o lock/mutex/semaphores.

+0

Oh caro. Uccidere altri thread è un'attività molto pericolosa, che può rovinare definitivamente eventuali blocchi o altre risorse nel programma. Sospendere un altro thread in punti arbitrari non è così male, ma comunque ... – ephemient

+0

Il codice del thread principale non utilizzerà alcun blocco (tranne quello descritto che impedisce di essere sospeso o ucciso) o allocare risorse dinamiche. Non utilizza librerie standard. –

+0

Questo è stato anche chiesto sulla mailing list di glibc [qui] (http: //sources.redhat.com/ml/libc-help/2010-05/msg00014.html). Tuttavia, senza alcun risultato. – Albert

risposta

3

In qualche modo penso che l'invio dell'altro thread SIGSTOP funzioni.

Tuttavia, è molto meglio scrivere alcune comunicazioni su thread che coinvolgono senaogires.mutexes e variabili globali.

Vedete, se si sospende l'altro thread in malloc() e si chiama malloc() -> deadlock.

Ho già detto che molte funzioni della libreria standard C, per non parlare delle altre librerie che usi, chiameranno malloc() dietro le tue spalle?

EDIT:

Hmmm, nessun codice libreria standard. Forse usare setjmp/longjump() dal gestore di segnale per simulare il POR e un segnale più maneggevole per simulare l'interruzione.

PER CHI TIENE CONTO DI VENDITA: La risposta è stata accettata per i contenuti dopo EDIT, che è uno scenario specifico che non può essere utilizzato in nessun altro scenario.

+0

Beh, in teoria esistono allocatori di memoria rientranti e la tua libc potrebbe persino usarne una per impostazione predefinita. Ma sì, la richiesta dell'OP è molto pericolosa. – ephemient

+0

Non intendo utilizzare alcuna libreria standard. Il codice da simulare è un mini-OS completo non basato su librerie standard C. –

+0

Per quanto ne so su linux (kernel 2.6) non è possibile inviare SIGSTOP a un singolo thread. Invece tutti i thread di un processo vengono fermati. Questo non risolverà il mio problema. –

1

Solaris ha la chiamata thr_suspend (3C) che farebbe quello che vuoi. È possibile passare a Solaris?

Oltre a questo, probabilmente dovresti fare qualche ginnastica con mutex e/o semafori. Il problema è che ti limiterai a sospendere solo quando controlli il mutex, che probabilmente sarà a un buon punto. A seconda di ciò che stai effettivamente cercando di realizzare, questo potrebbe essere ora desiderabile.

+0

Io uso Ubuntu a casa. Se devo passare a un sistema operativo diverso, potrei anche passare a Windows. Ma grazie per il suggerimento. Mutex e semafori influenzano solo il thread corrente. E non voglio inserire il codice di strumentazione per la simulazione. –

1

Ha più senso che il thread principale esegua gli ISR ​​- perché è così che funziona il controller reale (presumibilmente). Basta fare un controllo dopo ogni istruzione emulata se c'è un interrupt in sospeso e gli interrupt sono attualmente abilitati, in tal caso emulare una chiamata all'ISR.

Il secondo thread è ancora utilizzato, ma ascolta solo le condizioni che causano un interrupt e contrassegna l'interrupt in sospeso (per l'altro thread in seguito verrà prelevato).

+0

Ovviamente, ho pensato di avere "fili di comunicazione" separati, ma non sono importanti per il processo generale. Non voglio alcuna strumentazione nel codice che controlla gli interrupt. Inoltre, non ho questo sul microcontrollore. Non voglio simulare un microcontroller specifico. Quindi non esiste un'istruzione emulata del microcontrollore. –

+0

A proposito, questa non è una risposta alla mia domanda. –

5

L'Hotspot JAVA VM utilizza SIGUSR2 per implementare il suspend/resume per i thread JAVA su linux.

Una procedura basata su un gestore di segnale per SIGUSR2 potrebbe essere:

Fornire un gestore di segnale per SIGUSR2 permette un filo di richiedere una serratura (già acquisita dal filo segnale di invio).

Questo sospende la discussione.

Non appena il filo di sospensione rilascia il blocco, il gestore di segnale può (e lo farà?) Ottenere il blocco. Il gestore del segnale rilascia immediatamente il blocco e lascia il gestore di segnale.

Riprende la discussione.

Probabilmente sarà necessario introdurre una variabile di controllo per assicurarsi che il thread principale si trovi nel gestore di segnale prima di iniziare l'elaborazione effettiva dell'ISR. (I dettagli variano a seconda che il gestore di segnale viene chiamato sincrono o asincrono.)

non so, se questo è esattamente come si è fatto in Java VM, ma penso che la procedura di cui sopra fa quello che mi serve .

9

SIGSTOP non funziona: interrompe sempre l'intero processo. Invece è possibile utilizzare alcuni altri segnali, dire SIGUSR1 per la sospensione e SIGUSR2 per la ripresa:

// 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); 
} 

Sono molto infastidito da risposte come "non si sospenda un altro thread, che è male". Ragazzi, perché pensate che gli altri siano degli idioti e non sappiano cosa stanno facendo? Immagina che anche altri abbiano sentito parlare di stallo e, in piena coscienza, vogliano sospendere altri thread. Se non hai una vera risposta alla loro domanda, perché sprechi il tuo tempo e quello dei lettori.

Un sì, i pthread IMO sono api molto miopi, una vergogna per POSIX.

+0

Mi piacerebbe usare questo in un contesto C++, interrompendo un thread iniettando un'eccezione, causando la pulizia degli oggetti RAII. Sto provando a eseguire il porting da Windows, dove sospendo il thread del problema e modifico il puntatore dell'istruzione all'inizio di un lancio di eccezione, prima di riprendere. Funziona bene e il più delle volte riesco a recuperare dopo aver riavviato i sottosistemi anche se entrano in loop infiniti, con una pulizia manuale minima dello stato condiviso (ad esempio, i mutex di ripristino). Come porto questa capacità alla mia versione Linux? La maggior parte degli articoli che vedo specificano per evitare il lancio da parte degli handler a causa del frame stack del gestore. –

0

La soluzione che utilizza i segnali pthread_kill (3) e SIGUSR1, SIGUSER2 è una buona soluzione ma può comunque causare problemi di concorrenza. C'è un modo per sospendere tutti i thread (ad eccezione del thread principale) in un punto sicuro, ad esempio, al momento della sospensione i thread non avrebbero dovuto acquisire alcun blocco o non essere in esecuzione in una chiamata di sistema?

+0

È una risposta adatta. Sembra una domanda alla fine per me. Si prega di modificare ed essere chiari – Freakyuser

Problemi correlati