Реализация атомарной функции down в ядре Linux
static inline void down(struct semaphore * sem) { __asm__ __volatile__( "# atomic down operation\n\t" /*A*/ LOCK "decl %0\n\t" /* -sem->count */ /*B*/ "js 2f\n" "1:\n" /*C*/ LOCK_SECTION_START("") /*D*/ "2:\tcall __down_failed\n\t" "jmp 1b\n" /*E*/ LOCK_SECTION_END :"=m" (sem->count) :"c" (sem) :"memory"); }
Данная inline-функция уменьшения значения семафора написана на встроенном ассемблере gcc, которым компилируется ядро Linux. В строке, помеченной литерой A, выполняется атомарная операция уменьшения счетчика на единицу. В строке B проверяется стал ли счетчик после этого отрицательным, и если это произошло, управление передается на строку, помеченную литерой D, в которой вызывается функция __down_failed, дожидающаяся освобождения семафора и захватывающая его.
Макрос из строки C определен в файле include/linux/spinlock.h. Он заставляет компилятор собирать фрагмент кода между литерами C и E в отдельной секции ядра. Это означает, что код до строки C вставляется компилятором в тело функции, откуда вызвана down (поскольку она помечена модификатором inline), а для кода между C и E отводиться специальное место в памяти. На него исполнение передается только в случае, если семафор закрыт.