OS/Linux

[펌] Kernel API 정리

아르비스 2010. 5. 26. 14:33

2장
insmod
modprobe
rmmod
실행 커널로 모듈을 적재하고 제거하는 사용자 영역 유틸리티

#include <linux/init.h>
module_init(init_function);
module_exit(cleanup_function);
모듈 초기화 함수와 정리 함수를 지정하는 매크로

#include <linux/sched.h>
sleeping관련 함수 변수, 드라이버의 Kernel API대부분의 정의
stuct task_struct *current;
현재 프로세스
current->pid
current->comm
현재 프로세스 ID와 명령 이름
obj-m
커널 빌드 시스템이 현재 디렉토리에서 빌드할 모듈을 파악하는데 사용하는 makefile심벌
/sys/module
적재된 모듈 정보를 포함하는 sys 디렉토리 층
/proc/modules
모듈 정보표시 가상 파일

#include <linux/module.h>
#include <linux/version.h>

LINUX_VERSION_CODE
버전 의존성 확인 정수 매크로 #ifdef로 사용

EXPORT_SYMBOL (symbol);
EXPORT_SYMBOL_GPL (symbol);
심벌을 외부에 공개

MODULE_AUTHOR(author);
MODULE_DESCRIPTION(description);
MODULE_LICENSE(license_string);
MODULE_VERSION(version_string);
MODULE_DEVICE_TABLE(table_info);
MODULE_ALIAS(alternate_name);
모듈 정보를 목적파일에 삽입

#include <linux/moduleparam.h>
module_param(variable, type, perm); // S_IRUGO
module_param_array(name, type, num, perm); // S_IRUGO
사용자가 지정할 수 있는 매개변수 만드는 매크로
bool, charp, int, invbool, long, short, ushort, uint, unlong, intarray

#include <linux/kernel.h>
int printk(const char* fmt, ...);


3장
#include <linux/types.h>
dev_t
디바이스 번호 타입

int MAJOR(dev_t dev);
int MINOR(dev_t dev);
디바이스 번호에서 주, 부번호를 얻어냄

dev_t MKDEV(unsigned int major, unsigned int minor);
주, 부번호에서 dev_t 자료 아이템 생성

#include <linux/fs.h>
파일시스템 함수
int register_chrdev_region(dev_t first, unsigned int count, char *name)
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name)
int unregister_chrdev_region(dev_t first, unsigned int count);
디바이스 번호를 할당/해제 reg:번호를 알때, alloc:동적 할당

int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);
major가 0이면 동적, 0이 아니면 그 번호 사용 커널 2.6버전 이전
int unregister_chrdev(unsigned int major, const char *name);
해제

struct file_operations;
문자 드라이버 메소드
struct file;
열린 파일 표현
struct inode;
디스크 상의 파일

#include <linux/cdev.h>
struct cdev *cdev_alloc(void);
void cdev_init(struct cdev *dev, struct file_operations *fops);
int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
void cdev_del(struct cdev *dev);
문자 디바이스 구조체 관리

#include <linux/kernel.h>
container_of(pointer, type, field);
다른 구조체에 포함된 구조체 포인터 받아 해당 구조체를 포함하는 구조체 포인터를 반환

#include <asm/uaccess.h>
커널 코드가 사용자 영역으로 자료 전송
unsigned long copy_from_user(void *to, const void *from, unsigned long count);
unsigned long copy_to_user(void *to, const void *from, unsigned long count);
사용자 영역과 커널 영역간 자료 복사

 

5장
#include <asm/semaphore.h>
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 down_trylock(struct semaphore *sem); // 세마포어 불가시 함수 반환
void up(struct semaphore *sem); // 락을 해제
세마포어에 락을 걸고, 해제

struct rw_semaphore;
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);
"
"
void downgrade_write(struct rw_semaphore *sem);

#include <linux/completion.h>
DECLARE_COMPLETION(name);
init_completion(struct completion *c); // 처음 초기화
INIT_COMPLETION(struct completion c); // 재초기화

void wait_for_completion(struct completion *c);
완료 시그널을 기다림
void complete(struct completion *c); // 스레드중 하나 깨움
void complete_all(struct completion *c); // 모든 대기자 깨움
완료 시그널 보냄
void complete_and_exit(struct completion *c, long retval);
완료 후 현 스레드에서 exit호출

#include <linux/spinlock.h>
spinlock_t lock = SPIN_LOCK_UNLOCKED;
spin_lock_init(spinlock_t *lock);
스핀락 초기화 두 방법

void spin_lock(spinlock_t *lock); //_irqrestore, _irq, _bh
void spin_trylock(spinlock_t *lock); // 스핀하지 않음
void spin_unlock(spinlock_t *lock); // 스핀락 해제


rwlock_t lock = RW_LOCK_UNLOCKED
rwlock_init(rwlock_t *lock);
읽기/쓰기 스레드 락 초기화 시키는 두 방법
void read_lock(rwlock_t *lock); //_irqrestore, _irq, _bh
void read_unlock(rwlock_t *lock);
void write_lock(rwlock_t *lock);
void write_unlock(rwlock_t *lock);


#include <asm/atomic.h>
atomic_t v = ATOMIC_INIT(value);
int atomic_read(atomic_t *v);
void atomic_set(atomic_t *v, int i);
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_add_negative(int I, atomic_t *v);
int atomic_dec_and_test(atomic_t *v);
int atomic_inc_and_test(atomic_t *v);
int atomic_inc_return(atomic_t *v);
원자 정수 변수. atomic_t 변수는 위의 함수로만 접근 가능

#include <asm/bitops.h>
void set_bit(int nr, void *addr);
void clear_bit(int nr, void *addr);
void change_bit(int nr, void *addr);
void test_and_set_bit(int nr, void *addr);
void test_and_clear_bit(int nr, void *addr);
void __set_bit(int nr, void *addr)
void __clear_bit(int nr, void *addr)
void __change_bit(int nr, void *addr)
원자 비트 변수. 플래그나 락 변수로 활용.

#include <linux/seqlock.h>
seqlock_t lock = SEQLOCK_UNLOCKED;
seqlock_init(seqlock_t *lock);
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_irqsave(seqlock_t *lock, unsigned long flags); // 쓰기 권한 얻기
void write_seqlock_irq(seqlock_t *lock); // 쓰기 권한 얻기
void write_seqlock_bh(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);


#include <linux/rcupdate.h>
Read - Copy - Update 매커니즘을 사용하기 위한 해더
void rcu_read_lock();
void rcu_read_unlock();
Atomic 읽기 접근

void call_rcu(struct rcu_head *head, void (*func)(void *arg), *void arg);
모든 프로세서가 스케줄 되어 RCU 해제해도 안전할 때 수행할 콜백 등록 함수


6장
#include <linux/ioctl.h>

#include <asm/uaccess.h>
int access_ok(int type, const void *addr, unsigned long size);
사용자 영역 포인터를 실제로 사용할 수 있는지 확인한다. 포인터를 참조해도 된다면 access_ok는 0이 아닌값 반환
type : VERIFY_READ, VERIFY_WRITE

int put_user(datum, ptr); // access_ok를 이미 호출
int __get_user(local, ptr); // __는 access_ok를 이미 호출했다고 가정
자료를 사용자 영역에서 가져오거나 저장 매크로, 전송 용량은 sizeof(*ptr)

#include <linux/capability.h>
사용자 영역 프로세스의 능력을 지정
int capable(int capability);
프로세스에 주어진 capbility가 있으면 0이 아닌값 반환

#include <linux/wait.h>
typedef struct { /*...*/ } wait_queue_head_t; // 명시적 초기화 필요
void init_waitqueue_head(wait_queue_head_t *queue); // 실행 시점에서 초기화
DECLARE_WAIT_QUEUE_HEAD(queue); // 컴파일 시점에서 초기화
리눅스 대기 큐에 대한 타입 정의

void wait_event(wait_queue_head_t q, int condition);
void wait_event_interruptible(wait_queue_head_t q, int condition);
void wait_event_timeout(wait_queue_head_t q, int condition, int time);
void wait_event_interruptible_timeout(wait_queue_head_t q, int condition, int time);
주어진 컨디션이 참이 될 때 까지 큐에서 프로세스가 자게 만든다.

void wake_up(struct wait_queue **q);
void wake_up_interruptible(struct wait_queue **q); // interruptible한 프로세스만 깨움
void wake_up_nr(struct wait_queue **q int nr); //
void wake_up_interruptible_nr(struct wait_queue **q, int nr);
void wake_up_all(struct wait_queue **q);
void wake_up_interruptible_all(struct wait_queue **q);
void wake_up_interruptible_sync(struct wait_queue **q);
큐에서 잠든 프로세스를 깨운다. 일반적으로 상호배제 중인 프로세서 1개만

#include <linux/sched.h>
set_current_state(int state);
현재 프로세스의 실행 상태를 설정
TASK_RUNNING
TASK_INTERRUPTIBLE
TASK_UNINTERRUPTIBLE

void schedule(void);
실행 큐에서 실행 가능 프로세스를 선택

typedef struct { /*...*/ } wait_queue_t; // 명시적 초기화 필요
init_waitqueue_entry(wait_queue_t *entry, struct task_struct *task);
wait_queue_t타입을 사용하여 프로세스를 대기 큐에 넣는다.

void prepare_to_wait(wait_queue_head_t *queue, wait_queue_t *wait, int state);
수작업으로 잠들기 구현

#include <linux/poll.h>
void poll_wait(struct file *filp, wait_queue_head_t *q, poll_table *p)
현재 프로세스를 즉시 스케줄링하지 않고 대기 큐에 넣는다. 디바이스 드라이버의 poll메소드가 사용

int fasync_helper(struct inode *inode, struct file *filp, int mod, struct fasync_struct **fa);
//몰라

 


7장
시간 맞추기
#incldue <linux/param.h>
HZ : 초당 클록 틱 수

#include <linux/jiffies.h>
volatile unsigned long jiffies
u64 jiffies_64 // 매 클럭 틱마다 1씩 증가

int time_after(unsigned long a, unsigned long b);
int time_before(unsigned long a, unsigned long b);
int time_after_eq(unsigned long a, unsigned long b);
int time_before_eq(unsigned long a, unsigned long b);
지피를 안전하게 비교(오버플로우x)
u64 get_jiffies_64(void);
경쟁없이 지피값 가져옴

#include <linux/time.h>
unsigned long timespec_to_jiffies(struct timespec *value);
void jiffies_to_timespec(unsigned long jiffies, struct timespec *value);
unsigned long timeval_to_jiffies(struct timeval *value);
void jiffies_to_timeval(unsigned long jiffies, struct timeval *value);
지피를 다른 시각 표현으로, 시각을 지피로 변환

#include <asm/msr.h>
rdtsc(low32,high32); // 32 32 둘다
rdtscl(low32); // 하위
rdtscll(var64); // 64 longlong 변수
타임스탬프 카운터를 읽는 매크로 x86 32bit*2

#include <linux/timex.h>
cycles_t get_cycles(void);
플랫폼 의존적으로 타임스탬프 카운터 반환, 기능 지원X = 0

#include <linux/time.h>
unsigned long mktime (unsigned int year, unsigned int mon,
   unsigned int day, unsigned int hour,
   unsigned int min, unsigned int sec);
년월일시분초 받아서 기준시부터 얼마나 흘렀는지 반환
void do_gettimeofday(struct timeval *tv);
현재시간을 기준 시각 이후 초와 마이크로초로 반환
struct timespec current_kernel_time(void);
1지피 resolution으로 현재시각을 반환

지연
#include <linux/wait.h>
long wait_event_interruptible_timeout(wait_queue_head_t *q, contion, signed long timeout);
현재 프로세스를 대기큐에 넣고 재움, 타임아웃은 지피값
#include <linux/sched.h>
signed long schedule_timeout(signed long timeout);
타임아웃 만료시 현재 프로세스가 깨어났음을 확인 후 스캐줄러 호출. 인터럽트 불가
호출자는 잠자기전에 set_current_state호출 해야함

#include <linux/delay.h>
void ndelay(unsigned long nsecs);
void udelay(unsigned long usecs);
void mdelay(unsigned long msecs);
각 단위 지연
void msleep(unsigned int millisecs);
unsigned long msleep_interruptible(unsigned int millisecs);
void ssleep(unsigned int seconds)
주어진 밀리초 만큼 프로세스를 재움


커널 타이머
#include <asm/hardirq.h>
int in_interrupt(void); // 프로세스 context 밖
int in_atomic(void); // 스핀락, 인터럽트 스캐줄링 해서 안되는 경우
bool반환 호출 코드가 어떤 context에서 실행중인지 반환

#include <linux/timer.h>
struct timer_list {
 /* ... */
 unsigned long expires;
 void (*function)(unsigned long);
 unsigned long data;
};
void init_timer(struct timer_list *timer);
struct timer_list TIMER_INITIALIZER(_function, _expires, _data);
timer_list 자료 구조체 초기화

void add_timer(struct timer_list * timer);
현재 CPU에서 실행하도록 타이머 구조체 등록
int del_timer(struct timer_list * timer);
int del_timer_sync(struct timer_list *timer); // 다른 CPU에서 실행중 아님을 보장
활성 타이머 목록에서 타이머 제거
int mod_timer(struct timer_list *timer, unsigned long expires);
이미 스케줄된 타이머 구조체의 만료시간 변경, add대신 사용가능
int timer_pending(const struct timer_list * timer);
타이머구조체를 이미 등록했는지 bool반환

태스크릿
#include <linux/interrupt.h>
struct tasklet_struct {
 /* ... */
 void (*func)(unsigned long);
 unsigned long data;
};
void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data);
이미 할당된 태스크릿 초기화
DECLARE_TASKLET(name, func, data);
DECLARE_TASKLET_DISABLED(name, func, data); // 비활성화 상태로 표시
태스크릿 구조체 정의
void tasklet_disable(struct tasklet_struct *t); // 다른 CPU에서 실행중일 경우 끝날때 까지 대기
void tasklet_disable_nosync(struct tasklet_struct *t); // 대기 안하고 반환
void tasklet_enable(struct tasklet_struct *t);
태스크릿을 활성/비활성화
void tasklet_schedule(struct tasklet_struct *t);
void tasklet_hi_schedule(struct tasklet_struct *t);
보통/ 높은 우선순위로 태스크릿 수행토록 스캐줄링
void tasklet_kill(struct tasklet_struct *t);
활성 태스크릿 목록에서 제거 // 다른 CPU에서 실행중일 경우 끝날때 까지 대기

작업큐
#include <linux/workqueue.h>
struct workqueue_struct;
struct work_struct;
작업큐와 작업항목 구조체

struct workqueue_struct *create_workqueue(const char *name); // 프로세서마다 작업자 스레드가 있는 작업큐 생성
struct workqueue_struct *create_singlethread_workqueue(const char *name); // 작업자 스레드가 하나뿐인 작업큐 생성
void destroy_workqueue(struct workqueue_struct *queue);
작업큐 생성/해제
DECLARE_WORK(name, void (*function)(void *), void *data);
INIT_WORK(struct work_struct *work, void (*function)(void *), void *data);
PREPARE_WORK(struct work_struct *work, void (*function)(void *), void *data);
작업큐항목 선언, 초기화
int queue_work(struct workqueue_struct *queue, struct work_struct *work);
int queue_delayed_work(struct workqueue_struct *queue, struct work_struct *work, unsigned long delay);
작업큐에 작업 삽입
int cancel_delayed_work(struct work_struct *work); // 작업 항목 제거
void flush_workqueue(struct workqueue_struct *queue); // 시스템에 실행 중인 작업큐 모두 제거

int schedule_work(struct work_struct *work);
int schedule_delayed_work(struct work_struct *work, unsigned long delay);
void flush_scheduled_work(void);
공유 작업 큐로 작업용


9장
#include <linux/kernel.h>
void barrier(void)
소프트웨어 메모리 장벽은 컴파일러에게 이 명령 전후 모든 메모리를 volatile접근으로 간주하라 요청

#include <asm/system.h>
void rmb(void);
void read_barrier_depends(void);
void wmb(void);
void mb(void);
하드웨어 메모리 장벽은은 CPU와 컴파일러에게 이 명령 전후의 모든 메모리 읽기 쓰기 둘다를 점검하라 요청

#include <asm/io.h>
unsigned inb(unsigned port);
void outb(unsigned char byte, unsigned port);
unsigned inw(unsigned port);
void outw(unsigned short word, unsigned port);
unsigned inl(unsigned port);
void outl(unsigned double word, unsigned port);
I/O port를 읽고 쓰는 함수

~_p I/O연산을 짧은 시간 지연할 필요가 있을 때.

void insb(unsigned port, void *addr, unsigned long count);
void outsb(unsigned port, void *addr, unsigned long count);
void insw(unsigned port, void *addr, unsigned long count);
"
"

문자열 함수, 입력 포트 -> 메모리 영역, 메모리 영역 -> 출력 포트 count 개수 만큼 자료 전송

#include <linux/ioport.h>
struct resource *request_region(unsigned long start, unsigned long len, char *name);
void release_region(unsigned long start, unsigned long len);
int check_region(unsigned long start, unsigned long len);
I/O 포트 자원 할당자.

struct resource *request_mem_region(unsigned long start, unsigned long len, char *name);
void releas_mem_region(unsigned long start, unsigned long len);
int check_mem_region(unsigned long start, unsigned long len);
메모리 영역 자원 할당 처리 함수

#include <asm/io.h>
void *ioremap(unsigned long phys_addr, unsigned long size);
void *ioremap_nocache(unsigned long phys_addr, unsigned long size);
void *iounmap(void *virt_addr);
ioremap은 물리적 주소 영역을 프로세서의 가상 주소 영역에 재사상하여 커널에서 사용할 수 있게 함, 사상 해제

#include <asm/io.h>
unsigned int ioread8(void *addr); // 16, 32
void iowrite8(void *addr); // 16, 32
I/O 메모리 접근 함수

unsigned int ioread8_rep(void *addr); // 16, 32
void iowrite8_rep(void *addr); // 16, 32
I/O 메모리 접근 함수 반복

unsigned readb(address); /b, w, l
unsigned writeb(address); /b, w, l
memset_io(address, value, count);
memset_fromio(dest, source, nbyte);
memset_toio(dest, source, nbyte);
예전 함수

void *ioport_map(unsigned long port, unsigned int count);
void ioport_unmap(void *addr);
I/O 포트를 I/O 메모리처럼 취급하려면 포트를 ioport_map으로 넘긴다.

 

10장
#include <linux/interrupt.h>
int request_irq(unsigned int irq, irqreturn_t (*handler)(), unsigned long flags, const char *dev_name, void *dev_id);
void free_irq(unsigned int irq, void *dev_id);
인터럽트 핸들러를 등록, 해제

#include <linux/irq.h>
int can_request_irq(unsigned int irq, unsigned long flags);
x86에서 사용 인터럽트 선 할당 성공시 0이 아닌 값 반환

#include <asm/signal.h>
SA_INTERRUPT 빠른 핸들러 설치
SA_SHIRQ 공유 핸들러
SA_SAMPLE_RANDOM 시스템 엔트로피 생성에 인터럽트 타임스탬프 사용

/proc/interrupt
/proc/stat
하드웨어 인터럽트와 설치된 핸들러에 대한 정보를 보여주는 파일 시스템의 노드

unsigned long probe_irq_on(void);
int probe_irq_off(unsigned long);
탐색과정에서 디바이스가 사용할 인터럽트 선을 결정할 때 드라이버에서 사용하는 함수.
인터럽트 생성 후 probe_irq_on결과를 probe_irq_off로 넘겨야한다.
probe_irq_off의 반환값은 감지한 인터럽트 번호

IRQ_NONE
IRQ_HANDLED
IRQ_RETVAL(int x)
인터럽트 핸들러가 반환할 수 있는 값

void disable_irq(int irq);
void disable_irq_nosync(int irq);
void enable_irq(int irq);
인터럽트 보고를 활성/비활성화. 공유처리기는 사용 불가

void local_irq_save(unsigned long flags);
void local_irq_restore(unsigned long flags);
현재 프로세서에서 인터럽트 비활성화 이전상태 기억 - 복구

void local_irq_disable(void);
void local_irq_enable(void);
현재 프로세서에서 인터럽트를 무조건 활성화/비활성화