| 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 |