본문 바로가기
실습/리눅스 커널

커널에서 condition race 제거

by 써드아이 2021. 2. 8.

[블로그 통합으로 이전해 온 자료] - 2008. 4. 24. 17:40

 

 

 * semaphore/mutex

 * semaphore 변수를 이용해 프로세스의 임계영역 접근을 제어한다.
 
 임계영역에 들어가기 전에 down_*() 함수를 사용해서 semaphore를 잡고
 임계영역이 끝나면 up() 함수로 semaphore를 풀어준다.
 
 
 <asm/semaphore.h>
 
 void sema_init( struct semaphore *sem, int val );
 DECLARE_MUTEX( name );
 DECLARE_MUTEX_LOCKED( name );

 void init_MUTEX( struct semaphore *sem );
 void init_MUTEX_LOCKED( struct semaphore *sem );

 void down( struct semaphore *sem );
 int down_interruptible( struct semaphore *sem );  <-- 주로 사용하는게 좋다.
 int donw_trylock( struct semaphore *sem );    <-- 프로세스를 잠들게하지 않는다.

 void up( struct semaphore *sem );


 <asm/rwsem.h>           <-- 사용하지 않는 편이 좋다.
 
 void init_rwsem( struct rw_semaphore *sem );
 
 void down_read( struct rw_semaphore *sem );
 int down_read_trylock( struct rw_semaphore *sem );
 void up_read( struct rw_semaphore *sem );
 
 void down_write( struct rw_semaphore *sem );
 int down_write_trylock( struct rw_semaphore *sem );
 void up_write( struct rw_semaphore *sem );
 void downgrade_write( struct rw_semaphore *sem );
 
 

 <linux/completion.h>         <-- 한번의 사용을 위해서..
 DECLARE_COMPLETION( my_completion );
 INIT_COMPLETION( my_completion );
 
 struct completion my_completion;
 init_completion( &my_completion );
 
 void wait_for_completion( struct completion *c );
 
 
 void complete( struct completion *c );
 void complete_all( struct completion *c );
 
 
 
* spinlock

 * smp 시스템을 위한 lock (단일 cpu 시스템에서는 쓰지 말자)
 * 비 선점형 단일 프로세서 시스템에서는 아무것도 하지 않는다는데
 그렇다면 선점형 단일 프로세서 시스템에서는??
 
 스핀락을 기다리는 동안은 인터럽트가 불가능하다.
 
 ***
 스핀락을 쥐고 있는 동안에 수행할 코드는 어떠한 상황에서도 잠지기 상태에
 빠져서는 안된다. (인터럽트조자 걸려서는 안되는 경우도 있다고 한다.)
 kmalloc(), copy_*_user() 류의 함수와 같은 코드 사용은 스핀락 영역 밖에서 사용할것!!
 
 <linux/spinlock.h>          
 
 spinlock_t my_lock = SPIN_LOCK_UNLOCKED;
 void spin_lock_init( spinlock_t *lock );
 
 void spin_lock( spinlock_t *lock );   <-- 인터럽트 none disable, 인터럽트 핸들러에서 사용불가
 void spin_lock_irqsave( spinlock_t *lock, unsigned long flags ); <-- 인터럽트 disable
 void spin_lock_irq( spinlock_t *lock );        <-- 인터럽트 disable
 void spin_lock_bh( spinlock_t *lock );        <-- softirq disable

 void spin_unlock( spinlock_t *lock );
 void spin_unlock_irqstore( spinlock_t *lock, unsigned long flags );
 void spin_unlock_irq( spinlock_t *lock );
 void spin_unlock_bh( spinlock_t *lock );
 
 
 <linux/spinlock.h>       <-- 역시나 사용하지 않는 편이 좋다.
 
 rwlock_t mylock = RW_LOCK_UNLOCKED;
 
 rwlock_t mylock;
 rwlock_init( &mylock );
 
 void read/write_un/lock( rwlock_t *lock );
 void read/write_un/lock_irqsave( rwlock_t *lock, unsigned long flags );
 void read/write_un/lock_irq( rwlock_t *lock );
 void read/write_un/lock_bh( rwlock_t *lock );
 
 int write_trylock( rwlock_t *lock );
 
 
* atomic var
 
 * 정수형태만 사용 가능하며 여러개의 동작을 할 경우는 잠금이 필수~!

 <asm/atomic.h>
 
 atomic_t = ATOMIC_INIT( n );
 void atomic_set( atomic_t *v, init i );
 
 int atomic_read( atomic_t *t );
 void atomic_add( int i, atomic_t *v );
 void atomic_sub( int i, atomic_t *v );
 void atomic_inc( atomic_t *v );
 void atomic_dec( atomic_t *v );
 
 int atomic_sub_and_test( int i, atomic_t *v );
 int atomic_inc_and_test( atomic_t *v );
 int atomic_dec_and_test( atomic_t *v );

 int atomic_add_negative( int i, atomic_t *v );
 
 int atomic_add_return( int i, atomic_t *v );
 int atomic_sub_return( int i, atomic_t *v );
 int atomic_inc_return( atomic_t *v );
 int atomic_dec_return( atomic_t *v );


* bit operation

 <asm/bitops.h>
 
 void set_bit( nr, void *addr );
 void clear_bit( nr, void *addr );
 void change_bit( nr, void *addr );
 
 int test_bit( nr, void *addr );
 
 int test_and_set_bit( nr, void *addr );
 int test_and_clear_bit( nr, void *addr );
 int test_and_change_bit( nr, void *addr );
 
* seqlock

 * 보호 자원이 작고, 간단하고 접근이 잦을 때, 그리고 쓰기 접근이 드물지만 빨라야 할 때 적당
 * 일기 쓰레드가 스스로 쓰기 쓰레드와 충돌을 확인해야 하며 충돌이 발생하면 접긍늘 다시 한번 시도해야한다.
 * 포인터가 있는 자료 구조체를 보호하는 데는 적합하지 않다.
 

 <linux/seqlock.h>

 seqlock_t lock1 = SEQLOCK_UNLOCKED;
 
 seqlock_t lock2;
 seqlock_init( &lock2 );
 
 
 example>
 
 unsigned int seq;
 
 do
 {
  seq = read_seqbegin( &lock2 );
 
 } wile ( read_seqretry( &lock2, seq ) );
 
 
 - 읽기 쓰레드
 unsigned int read_seqbegin( seqlock_t *lock, unsigned long flags );
 int read_seqretry( seqlock_t *lock, unsigned int seq, unsigned long flags );
 unsigned int read_seqbegin_irqsave( seqlock_t *lock, unsigned long flags );
 int read_seqretry_irqrestore( seqlock_t *lock, unsigned int seq, unsigned long flags );
 
 - 쓰기 쓰레드
 void write_seqlock( seqlock_t *lock );
 void write_seqlock_irqsave( seqlock_t *lock, unsigned long flags );
 void write_seqlock_irq( seqlock_t *lock );
 void write_seqlock_bh( seqlock_t *lock );
 
 void write_sequnlock( seqlock_t *lock );
 void write_sequnlock_irqrestore( seqlock_t *lock, unsigned long flags );
 void write_sequnlock_irq( seqlock_t *lock );
 void write_sequnlock_bh( seqlock_t *lock );