Asembler w kodzie linuxa | ||
---|---|---|
<<< Wstecz | Przykłady | Dalej >>> |
W wielowejściowym systemie operacyjnym istnieje niekiedy potrzeba używania operacji niepodzielnych. Operacje takie można zaimplementować korzystając z faktu, że w architekturze Intela, w sysytemie wieloprocesorowym (SMP), mamy niepodzielne:
pojedyncze instrukcje asemblera pobierające wartości z pamięci (lub zapisujące do pamięci) zero lub jeden raz;
instrukcje asemblera takie jak inc (zwiększ) lub dec (zmniejsz), jeśli żaden inny procesor nie przejmie szyny pamięci po wczytaniu a przed zapisaniem wartości argumentu;
pojedyncze instrukcje asemblera poprzedzone rozkazem lock.
Konkretnym przykładem operacji niepodzielnych mogą być operacje na zmiennej typu atomic_t zaimplementowane w pliku include/asm-i386/atomic.h. Typ ten jest później wykorzystywany między innymi przy realizacji semaforów.
Na początek definicja potrzebna dla zapewnienia atomowości w systemach SMP.
#ifdef CONFIG_SMP #define LOCK "lock ; " #else #define LOCK "" #endif |
Następnie mamy definicję typu i podstawowych operacji.
typedef struct { volatile int counter; } atomic_t; #define ATOMIC_INIT(i) { (i) } #define atomic_read(v) ((v)->counter) #define atomic_set(v,i) (((v)->counter) = (i)) |
W asemblerze zaimplementowano atomowe operacje dodawania, odejmowania, odejmowania ze sprawdzeniem, czy wynik nie jest zerem:
static __inline__ void atomic_add(int i, atomic_t *v) { __asm__ __volatile__( LOCK "addl %1,%0" :"=m" (v->counter) :"ir" (i), "m" (v->counter)); } static __inline__ void atomic_sub(int i, atomic_t *v) { __asm__ __volatile__( LOCK "subl %1,%0" :"=m" (v->counter) :"ir" (i), "m" (v->counter)); } /** * Atomically subtracts @i from @v and returns * true if the result is zero, or false for all * other cases. */ static __inline__ int atomic_sub_and_test(int i, atomic_t *v) { unsigned char c; __asm__ __volatile__( LOCK "subl %2,%0; sete %1" :"=m" (v->counter), "=qm" (c) :"ir" (i), "m" (v->counter) : "memory"); return c; } |
Jak widać niepodzielność całej operacji jest uzyskana przez wykorzystanie niepodzielnych instrukcji asemblera. W ostatnim przypadku jako niepodzielna instrukcja asemblera jest traktowany blok:
lock; subl %2.%0; sete %1 |
Zapisanie tych instrukcji w jezyku wyższego poziomu jest niemożliwe, gdyż wtedy nie mamy bezpośredniej kontroli nad wygenerowanym kodem.
<<< Wstecz | Spis treści | Dalej >>> |
Hello world! dla procesora SPARC | Początek rozdziału | Operacje bitowe |