2010-02-05 19 views
5

Próbuję zaimplementować symulację mikrokontrolera. Ta symulacja nie ma na celu dokładnego odwzorowania jednego taktycznego mikrokontrolera, ale sprawdza ogólną poprawność kodu.Jak zawiesić inny wątek (nie bieżący)?

Myślałem o "głównym wątku" wykonującym normalny kod i drugim wątku wykonującym kod ISR. Ilekroć ISR musi zostać uruchomiony, wątek ISR zawiesza "główny wątek".

Oczywiście, chcę mieć funkcję blokowania przerwań. Pomyślałem o rozwiązaniu tego przy pomocy muteksu, który wątek ISR zawiera za każdym razem, gdy wykonuje kod ISR, podczas gdy główny wątek utrzymuje go tak długo, jak "przerywane są zablokowane".

POR (power on reset) może zostać zaimplementowany nie tylko zawieszając, ale zabijając główny wątek (i uruchamiając nowy wykonujący funkcję POR).

Windows API zapewnia niezbędne funkcje. Ale wydaje się, że niemożliwe jest wykonanie powyższych czynności za pomocą wątków posix (w systemie Linux).

Nie chcę zmieniać rzeczywistego kodu niezależnego od mikrokontrolera sprzętu. Więc wstawianie czegokolwiek w celu sprawdzenia oczekujących przerw jest nieopcją.

Przyjmowanie przerwania w niezbyt dobrze zachowanych punktach jest pożądane, podobnie jak w mikrokontrolerach (chyba że blokujesz przerwania).

Czy istnieje sposób zawieszenia innego wątku na Linuksie? (Debugery muszą jakoś skorzystać z tej opcji.)

Proszę, nie mówcie mi, że to zły pomysł. Wiem, że tak jest w większości przypadków. Ale główny kod nie używa standardowych bibliotek lub lock/mutexes/semaphores.

+0

Och kochanie. Zabijanie innych wątków jest bardzo niebezpieczną sprawą, która może trwale zepsuć wszelkie blokady lub inne zasoby w twoim programie. Zawieszenie kolejnego wątku w dowolnych punktach nie jest tak złe, ale nadal ... – ephemient

+0

Główny kod wątku nie będzie używał żadnych blokad (z wyjątkiem opisanego, który uniemożliwia ich zawieszanie lub zabijanie) lub alokacji zasobów dynamicznych. Nie używa standardowych bibliotek. –

+0

Zostało to również zadane na liście dyskusyjnej glibc [tutaj] (http: //sources.redhat.com/ml/libc-help/2010-05/msg00014.html). Jednak bez żadnego wyniku. – Albert

Odpowiedz

3

Jakoś myślę, że wysyłanie drugiego wątku SIGSTOP działa.

Jednak dużo lepiej jest napisać komunikację wątków obejmującą senaogires.mutexes i zmienne globalne.

Widzisz, jeśli zawiesisz drugi wątek w malloc() i zadzwonisz do malloc() -> impasu.

Czy wspomniałem, że wiele standardowych funkcji biblioteki C, nie mówiąc już o innych używanych bibliotekach, wywoła funkcję malloc() za plecami?

EDYTOWANIE:

Hmmm, bez standardowego kodu biblioteki. Być może użyj setjmp/longjump() z obsługi sygnału do symulacji POR i handler sygnału, aby symulować przerwanie.

DO TYCH, KTÓRZY PRZECHOWYWAJĄ POCHODZĄCYCH Z NIEGO: Odpowiedź została zaakceptowana dla zawartości po EDYCJI, która jest scenariuszem, którego nie można użyć w żadnym innym scenariuszu.

+0

No cóż, teoretycznie istnieją alokatory pamięci ponownego wjazdu, a Twoja libc może nawet używać domyślnie. Ale tak, prośba OP jest bardzo niebezpieczna. – ephemient

+0

Nie zamierzam używać żadnej standardowej biblioteki. Kod do symulacji to kompletny mini-system operacyjny nie oparty na standardowych bibliotekach C. –

+0

O ile wiem na temat Linux-a (jądro 2.6), nie można wysłać SIGSTOP do pojedynczego wątku. Zamiast tego wszystkie wątki procesu zostają zatrzymane. To by nie rozwiązało mojego problemu. –

1

Solaris ma wywołanie thr_suspend (3C), które zrobiłoby to, co chcesz. Czy przejście na Solaris jest możliwe?

Poza tym prawdopodobnie będziesz musiał wykonać trochę gimnastyki z muteksami i/lub semaforami. Problem polega na tym, że zawiesisz tylko, gdy sprawdzisz muteks, który prawdopodobnie będzie w dobrze zachowanym punkcie. W zależności od tego, co faktycznie chcesz osiągnąć, może to być teraz pożądane.

+0

Używam ubuntu w domu. Jeśli muszę przełączyć się na inny system operacyjny, równie dobrze mogę przełączyć się na system Windows. Ale dzięki za podpowiedź. Muteksy i semafory wpływają tylko na bieżący wątek. I nie chcę wstawiać kodu oprzyrządowania do symulacji. –

1

Lepiej jest, aby główny wątek wykonywał ISR - ponieważ tak działa prawdziwy kontroler (prawdopodobnie). Po prostu sprawdź to po każdej emulowanej instrukcji, jeśli istnieje zarówno przerwanie w toku, a przerwania są obecnie włączone - jeśli tak, emuluj wywołanie do ISR.

Drugi wątek jest nadal używany - ale po prostu nasłuchuje warunków, które powodują przerwanie, i oznaczyć odpowiednie przerwanie jako oczekujące (aby drugi wątek mógł później odebrać).

+0

Oczywiście myślałem o oddzielnych "wątkach komunikacyjnych", ale nie są one ważne dla ogólnego procesu. Nie chcę żadnych oprzyrządowania w kodzie, który sprawdza przerwania. Też nie mam tego na mikrokontrolerze. Nie chcę tak symulować określonego mikrokontrolera. Tak więc nie ma czegoś takiego jak emulowana instrukcja mikrokontrolera. –

+0

Nawiasem mówiąc, to nie jest odpowiedź na moje pytanie. –

5

Hotspot JAVA VM używa SIGUSR2 do implementacji zawieszenia/wznowienia wątków JAVA na Linuksie.

Procedura oparta na na obsługę sygnału dla SIGUSR2 może być:

Zapewnienie obsługi sygnału dla SIGUSR2 pozwala nitki do żądania blokady (która już została objęta przez wysyłanie sygnału wątku).

Spowoduje to zawieszenie wątku.

Jak tylko zawieszający się wątek zwalnia blokadę, moduł obsługi sygnału może (i będzie?) Uzyskać blokadę. Procedura obsługi sygnału zwolni blokadę natychmiast i opuszcza procedurę obsługi sygnału.

Powtarza wątek.

Prawdopodobnie konieczne będzie wprowadzenie zmiennej sterującej, aby upewnić się, że główny wątek znajduje się w procedurze obsługi sygnału przed rozpoczęciem faktycznego przetwarzania ISR. (Szczegóły zależą od tego, czy funkcja obsługi sygnału jest nazywana synchronicznie lub asynchronicznie.)

Nie wiem, jeśli tak właśnie jest w Java VM, ale myślę, że powyższa procedura robi to, czego potrzebuję .

9

SIGSTOP nie działa - zawsze zatrzymuje cały proces. Zamiast tego można użyć kilka innych sygnałów, powiedzmy SIGUSR1 do zawieszania i wznawiania SIGUSR2 dla:

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

Jestem bardzo zły z odpowiedziami typu „nie należy zawiesić inny wątek, który jest zły”. Faceci, dlaczego uważasz, że inni to idioci i nie wiedzą, co robią? Wyobraź sobie, że inni również słyszeli o impasie i nadal, w pełnej świadomości, chcą zawiesić inne wątki. Jeśli nie masz prawdziwej odpowiedzi na swoje pytanie, dlaczego marnujesz czas swoich czytelników.

Tak, IMO pthreads to bardzo krótkowzroczne api, hańba dla POSIX.

+0

Chciałbym użyć tego w kontekście C++, przerywając wątek przez wstrzyknięcie wyjątku, powodując oczyszczanie obiektów RAII. Próbuję przenieść z systemu Windows, w którym zawieszam wątek problemu i zmodyfikuję wskaźnik instrukcji na początek rzutu wyjątku, przed wznowieniem. Działa dobrze, a większość czasu mogę odzyskać po ponownym uruchomieniu podsystemów, nawet jeśli wchodzą one w nieskończone pętle, przy minimalnym ręcznym czyszczeniu stanu współdzielonego (np. Resetowanie muteksów). Jak mogę przenieść tę zdolność do mojej wersji Linux? Większość artykułów, które widzę, określa, aby uniknąć rzucania z procedur obsługi z powodu ramki stosu obsługi. –

0

Rozwiązanie wykorzystujące sygnały pthread_kill (3) i SIGUSR1, SIGUSER2 jest dobrym rozwiązaniem, ale nadal może powodować problem z współbieżnością. Czy istnieje sposób zawieszenia wszystkich wątków (z wyjątkiem wątku głównego) w bezpiecznym miejscu, tj. W czasie zawieszenia wątki nie powinny mieć żadnej blokady lub nie być uruchomione w wywołaniu systemowym?

+0

Czy to odpowiednia odpowiedź. To brzmi jak pytanie na końcu do mnie. Edytuj i bądź jasny – Freakyuser

Powiązane problemy