Microsoft PowerPoint Driver-Time-7.ppt

Similar documents
Chapter #01 Subject

임베디드시스템설계강의자료 6 system call 2/2 (2014 년도 1 학기 ) 김영진 아주대학교전자공학과

API 매뉴얼

교육지원 IT시스템 선진화

K&R2 Reference Manual 번역본

Microsoft PowerPoint - 10-EmbedSW-11-모듈

untitled

PowerPoint 프레젠테이션

- 코드로읽는리눅스디바이스드라이버 강남용

10.

untitled

KEY 디바이스 드라이버

untitled

Microsoft PowerPoint - additional01.ppt [호환 모드]

chap 5: Trees

<4D F736F F F696E74202D20BBB7BBB7C7D15F FBEDFB0A3B1B3C0B05FC1A634C0CFC2F72E BC8A3C8AF20B8F0B5E55D>

PowerPoint 프레젠테이션

A Hierarchical Approach to Interactive Motion Editing for Human-like Figures

<443A5C4C C4B48555C B3E25C32C7D0B1E25CBCB3B0E8C7C1B7CEC1A7C6AE425CBED0C3E0C7C1B7CEB1D7B7A55C D616E2E637070>

PowerPoint 프레젠테이션

Microsoft PowerPoint - chap10-함수의활용.pptx

슬라이드 1

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

Microsoft PowerPoint - ch07 - 포인터 pm0415

커알못의 커널 탐방기 이 세상의 모든 커알못을 위해서

Frama-C/JESSIS 사용법 소개

<4D F736F F F696E74202D20BBB7BBB7C7D15F FBEDFB0A3B1B3C0B05FC1A638C0CFC2F72E BC8A3C8AF20B8F0B5E55D>

PowerPoint 프레젠테이션

6주차.key

Chapter 4. LISTS

< E20C6DFBFFEBEEE20C0DBBCBAC0BB20C0A7C7D12043BEF0BEEE20492E707074>

Microsoft PowerPoint - ch09 - 연결형리스트, Stack, Queue와 응용 pm0100

Lab 3. 실습문제 (Single linked list)_해답.hwp

<443A5C4C C4B48555C B3E25C32C7D0B1E25CBCB3B0E8C7C1B7CEC1A7C6AE425CC0E7B0EDB0FCB8AE5C53746F636B5F4D616E D656E74732E637070>

Microsoft PowerPoint - polling.pptx

금오공대 컴퓨터공학전공 강의자료

Microsoft PowerPoint - CSharp-10-예외처리

Microsoft Word - FunctionCall

Microsoft PowerPoint - es-arduino-lecture-03

Chapter 4. LISTS

슬라이드 1

[ 마이크로프로세서 1] 2 주차 3 차시. 포인터와구조체 2 주차 3 차시포인터와구조체 학습목표 1. C 언어에서가장어려운포인터와구조체를설명할수있다. 2. Call By Value 와 Call By Reference 를구분할수있다. 학습내용 1 : 함수 (Functi

강의10

Microsoft PowerPoint - chap03-변수와데이터형.pptx

프로그램을 학교 등지에서 조금이라도 배운 사람들을 위한 프로그래밍 노트 입니다. 저 역시 그 사람들 중 하나 입니다. 중고등학교 시절 학교 도서관, 새로 생긴 시립 도서관 등을 다니며 책을 보 고 정리하며 어느정도 독학으르 공부하긴 했지만, 자주 안하다 보면 금방 잊어

11장 포인터

UI TASK & KEY EVENT

임베디드시스템설계강의자료 6 system call 1/2 (2014 년도 1 학기 ) 김영진 아주대학교전자공학과

17장 클래스와 메소드

Lab 4. 실습문제 (Circular singly linked list)_해답.hwp

좀비프로세스 2

<4D F736F F F696E74202D2036C0CFC2B05FB0B4C3BCC1F6C7E2C7C1B7CEB1D7B7A1B9D62E707074>

Microsoft PowerPoint - chap06-2pointer.ppt

PowerPoint Template

<4D F736F F F696E74202D20B8AEB4AABDBA20BFC0B7F920C3B3B8AEC7CFB1E22E BC8A3C8AF20B8F0B5E55D>

목차 BUG DEQUEUE 의 WAIT TIME 이 1 초미만인경우, 설정한시간만큼대기하지않는문제가있습니다... 3 BUG [qp-select-pvo] group by 표현식에있는컬럼을참조하는집합연산이존재하지않으면결괏값오류가발생할수있습니다... 4

Mango-AM335x LCD Type 커널 Module Parameter에서 변경하기

Embeddedsystem(8).PDF

5.스택(강의자료).key


쉽게 풀어쓴 C 프로그래밍

C 언어 프로그래밊 과제 풀이

Microsoft Word doc

API 매뉴얼

PowerPoint 프레젠테이션

<4D F736F F F696E74202D20B8B6C0CCC5A9B7CEC7C1B7CEBCBCBCAD202834C1D6C2F7207E2038C1D6C2F729>

vi 사용법

Microsoft PowerPoint - C프로그래밍-chap03.ppt [호환 모드]

10주차.key

슬라이드 1

À̵¿·Îº¿ÀÇ ÀÎÅͳݱâ¹Ý ¿ø°ÝÁ¦¾î½Ã ½Ã°£Áö¿¬¿¡_.hwp

03_queue

UI TASK & KEY EVENT

제1장 Unix란 무엇인가?

chap7.key

PowerPoint 프레젠테이션

<4D F736F F F696E74202D20B8B6C0CCC5A9B7CEC7C1B7CEBCBCBCAD202839C1D6C2F7207E203135C1D6C2F >

제11장 프로세스와 쓰레드

Sena Technologies, Inc. HelloDevice Super 1.1.0

untitled

목차 포인터의개요 배열과포인터 포인터의구조 실무응용예제 C 2

PowerPoint 프레젠테이션

버퍼오버플로우-왕기초편 10. 메모리를 Hex dump 뜨기 앞서우리는버퍼오버플로우로인해리턴어드레스 (return address) 가변조될수있음을알았습니다. 이제곧리턴어드레스를원하는값으로변경하는실습을해볼것인데요, 그전에앞서, 메모리에저장된값들을살펴보는방법에대해배워보겠습

메시지큐를이용한 IPC 프로그램구현과제보고서 1. 과제의목적 1 리눅스가지원하는프로세스간통신방식중다수의프로세스사이에구조화된데이터블럭, 즉메시지를전달하는데주로사용되는메시지큐방식에대하여무엇인지, 어떻게사용하는지공부한다. 2 공부한내용을점검하기위해기작성된 epda 프로세스관

<4D F736F F F696E74202D20B8B6C0CCC5A9B7CEC7C1B7CEBCBCBCAD202834C1D6C2F7207E2038C1D6C2F729>

ABC 11장

Abstract View of System Components

06장.리스트

Microsoft PowerPoint - lab14.pptx

PowerPoint 프레젠테이션

<322EBCF8C8AF28BFACBDC0B9AEC1A6292E687770>

Microsoft PowerPoint - chap02-C프로그램시작하기.pptx

Microsoft PowerPoint - ch10 - 이진트리, AVL 트리, 트리 응용 pm0600

03장.스택.key

Microsoft PowerPoint - Lecture_Note_7.ppt [Compatibility Mode]

Microsoft PowerPoint - 09-CE-5-윈도우 핸들

(Asynchronous Mode) ( 1, 5~8, 1~2) & (Parity) 1 ; * S erial Port (BIOS INT 14H) - 1 -

Microsoft PowerPoint - 3ÀÏ°_º¯¼ö¿Í »ó¼ö.ppt

歯9장.PDF

Transcription:

Chapter 7 Time, Delays, and Deferred Work 시간경과측정 현재시간알기 실행지연 커널타이머 워크큐 순천향대학교컴퓨터학부이상정 1 시간경과측정 (Measuring Time Lapses) 순천향대학교컴퓨터학부이상정 2

타이머인터럽트 커널은시간을추적하기위해일정시간간격으로타이머인터럽트이슈 <linux/param.h> 에정의된 HZ 값에따라인터벌을세팅 HZ 는 50-12000 까지의값을가지며대부분의플랫폼에서 100 또는 1000 으로정의 X86 PC는디폴트로 HZ 값이 1000 커널 2.4 이전버전은디폴트 HZ 값이 100 HZ은주파수를의미하므로타이머인터럽트가초당 HZ에지정된값만큼발생함을의미 1000인경우타이머인터럽트는 1/1000초, 1ms 마다발생 순천향대학교컴퓨터학부이상정 3 jiffies 타이머인터럽트가발생할때마다내부커널카운터가증가 <linux/jiffies.h> 에정의 2.6 커널의내부커널카운터는 64 비트변수 jiffies_64로표현 일반적으로는 32비트변수 unsigned long 형의 jiffies 사용 시스템이부팅될때 0으로초기화되어컴퓨터가켜진이후경과시간을표시 오랜동안컴퓨터가켜져있으면오버플로우가발생 HZ 이 1000 인경우 50 일이지나후오버플로우발생 순천향대학교컴퓨터학부이상정 4

jiffies 의사용예 사용예 #include <linux/jiffies.h> unsigned long j, stamp_1, stamp_half, stamp_n; j = jiffies; /* read the current value */ stamp_1 = j + HZ; /* 1 second in the future */ stamp_half = j + HZ/2; /* half a second */ stamp_n = j + n * HZ / 1000; /* n milliseconds */ 두시점에서 jiffies 의값이 t1,t2 인경우경과시간 diff diff = (long)t2 (long)t1; msec = diff * 1000 / HZ 관련함수 #include <linux/jiffies.h> u64 get_jiffies_64(void) jiffies_64 값을읽는변수 u64 는 <linux/types.h> 에 64 비트 unnsigend 값으로정의 순천향대학교컴퓨터학부이상정 5 프로세서카운터레지스터 좀더짧은간격의정밀한시간측정을하려면 CPU 가제공하는하드웨어카운터에의존 현대 CPU 는매클럭사이클마다증가하는카운터제공 현대프로세서에서는명령스케쥴링, 분기예측, 캐시메모리등때문에명령의타이밍을예측하기가어려워이카운터가정밀한시간측정을위한유일한수단 카운터레지스터는플랫폼에따라다양 x86 계열펜티엄프로세서에서는 64비트의 TSC (timestamp counter) 카운터레지스터제공하고커널과사용자영역모두에서읽기가능 순천향대학교컴퓨터학부이상정 6

TSC 카운터레지스터 TSC 카운터레지스터는다음매크로를사용하여읽음 #include <asm/msr.h> /* machine-specific registers */ rdtsc(low32, high32); rdtscl(low32); rdscll(var64); 두개의 32비트변수, 하위 32비트값또는 64비트의값을읽는매크로 1GHz 시스템에서매 4.2초마다 32비트카운터는오버플로우 이들매크로의실행시간을측정하는예 unsigned long ini, end; rdtscl(ini); rdtscl(end); printk("time lapse: %li n", end - ini); 순천향대학교컴퓨터학부이상정 7 get_cycles() 함수 커널은 rdtsc 와유사한기능의아키텍처독립적인함수인 get_cycles 을제공 #include <linux/timex.h> cycles_t get_cycles(void); 사이클-카운터레지스터가없는플랫폼에서는 0을리턴 cycles_t는 CPU 레지스터에맞추어진 unsigned 타입으로펜티엄인경우하위 32비트값이리턴 순천향대학교컴퓨터학부이상정 8

인라인어셈블리코드 인라인어셈블리코드 (inline asssembly code) 를사용하여카운터레지스터를직접읽을수있음 x86 과같이 MIPS 에서 rdtscl 함수를구현예 MIPS 에서는내부레지스터 9 가 32 비트카운터 레지스터는커널영역에서만읽을수있고 move from coprocessor 0 어셈블리명령을실행하여읽음 매크로를다음과같이정의 #define rdtscl(dest) asm volatile ("mfc0 %0,$9; nop" : "=r" (dest)) gcc 인라인어셈블리는범용레지스터는컴파일러가할당 %0 는 argument 0 로출력 (=) 의임의의레지스터 (r) 에대응되고, C 표현의 dest 에대응됨을표시 nop 는 mfc 바로다음의명령이타겟레지스터를액세스하지못하게하기위해삽입 앞의 C 코드실행 K7 계열의 x86 프로세서실행하면 11 클럭틱이출력 MIPS VR4181 의경우 2 클럭틱이출력 MIPS 는 RISC 계열프로세서로클럭당한명령을실행 순천향대학교컴퓨터학부이상정 9 현재시간알기 (Knowing the Current Time) 순천향대학교컴퓨터학부이상정 10

현재시간측정 드라이버는 jiffies 의값을사용하여이벤트간의시간간격을측정 예를들면입력디바이스드라이버에서더블클릭과싱글클릭을구분하는용도등에사용 아주짧은시간간격을측정하기위해서는프로세서에종속적인레지스터값들을이용 일반적으로커널에서년, 월, 일, 시, 분, 초등으로표시되는현재시간을사용하는경우는드물지만이를지원하는함수, 구조체는지원 순천향대학교컴퓨터학부이상정 11 현재시간관련구조체 <linux/time.h> 에현재시간을초로환산하여표시하는두개 의구조체정의 struct timeval time_t tv_sec; // second suseconds_t tv_usec; // microsecond struct timespec // 커널 2.6에추가 time_t tv_sec; // second suseconds_t tv_usec; // nanosecond 순천향대학교컴퓨터학부이상정 12

현재시간관련함수 현재시간을읽는관련함수 #include <linux/time.h> void do_gettimeofday(struct timeval *tv); 현재시간을 struct timeval 구조체 tv 로읽음 struct timespec current_kernel_time(void); 현재시간을 struct timespec 구조체로리턴 순천향대학교컴퓨터학부이상정 13 jit_currenrtime 샘플코드소개 jit(just In Time) 샘플코드 소스 : source/ misc-modules/jit.c jit_currenttime 소스코드 다음 4가지형태로현재시간을출력하는 /proc/currentime 을생성 Makefile jiffies get_jiffies_64() do_gettimeofday() current_kernel_time() obj-m := jit.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 순천향대학교컴퓨터학부이상정 14

jit_currenrtime 실행예 # cd jit # make # insert jit.ko # lsmod Module Size Used by jit 4864 0 scull 13368 2 PhaseDvfs 15316 0 SetDvfs 2900 0 # head -8 /proc/currentime <= jiffies, jiffies_64, struct timeval, struct timespec 0x67303877 0x0000000167303877 1178222180.342232 1178222180.336045704 0x67303877 0x0000000167303877 1178222180.342239 1178222180.336045704 0x67303877 0x0000000167303877 1178222180.342245 1178222180.336045704 0x67303877 0x0000000167303877 1178222180.342250 1178222180.336045704 순천향대학교컴퓨터학부이상정 15 jit_currenrtime 코드 : jit.c #include <linux/time.h> int jit_currentime(char *buf, char **start, off_t offset, int len, int *eof, void *data) struct timeval tv1; struct timespec tv2; unsigned long j1; u64 j2; /* get them four */ j1 = jiffies; j2 = get_jiffies_64(); do_gettimeofday(&tv1); tv2 = current_kernel_time(); /* print */ len=0; len += sprintf(buf,"0x%08lx 0x%016Lx %10i.%06i n" "%40i.%09i n", j1, j2, (int) tv1.tv_sec, (int) tv1.tv_usec, (int) tv2.tv_sec, (int) tv2.tv_nsec); *start = buf; return len;... int init jit_init(void) create_proc_read_entry("currentime", 0, NULL, jit_currentime, create_proc_read_entry("jitbusy", 0, NULL, jit_fn, (void *)JIT_BUSY); create_proc_read_entry("jitsched",0, NULL, jit_fn, (void *)JIT_SCHED); create_proc_read_entry("jitqueue",0, NULL, jit_fn, (void *)JIT_QUEUE); create_proc_read_entry("jitschedto", 0, NULL, jit_fn, (void *)JIT_SCHEDTO); create_proc_read_entry("jitimer", 0, NULL, jit_timer, create_proc_read_entry("jitasklet", 0, NULL, jit_tasklet, create_proc_read_entry("jitasklethi", 0, NULL, jit_tasklet, (void *)1); return 0; /* success */. 순천향대학교컴퓨터학부이상정 16

실행지연 (Delaying Execution) 순천향대학교컴퓨터학부이상정 17 busy waiting 방식 한클럭틱보다긴지연은시스템클럭과소프트웨어루프로구현 busy waiting 방식 한클럭틱이상의긴지연시사용 코드구현 unsigned long j1= jiffies + jit_delay * HZ; while(time_before(jiffies, j1)) cpu_slack(); while (jiffies < j1) /* nothing */; 순천향대학교컴퓨터학부이상정 18

jit_busy 코드 : jit.c #include <linux/time.h> int delay = HZ; /* the default delay, expressed in jiffies */.. int jit_fn(char *buf, char **start, off_t offset, int len, int *eof, void *data) unsigned long j0, j1; /* jiffies */ wait_queue_head_t wait; init_waitqueue_head (&wait); j0 = jiffies; j1 = j0 + delay; switch((long)data) case JIT_BUSY: while (time_before(jiffies, j1)) cpu_relax(); break; j1 = jiffies; /* actual value after we delayed */ len = sprintf(buf, "%9li %9li n", j0, j1); *start = buf; return len; 순천향대학교컴퓨터학부이상정 19... int init jit_init(void) create_proc_read_entry("currentime", 0, NULL, jit_currentime, create_proc_read_entry("jitbusy", 0, NULL, jit_fn, (void *)JIT_BUSY); create_proc_read_entry("jitsched",0, NULL, jit_fn, (void *)JIT_SCHED); create_proc_read_entry("jitqueue",0, NULL, jit_fn, (void *)JIT_QUEUE); create_proc_read_entry("jitschedto", 0, NULL, jit_fn, (void *)JIT_SCHEDTO); create_proc_read_entry("jitimer", 0, NULL, jit_timer, create_proc_read_entry("jitasklet", 0, NULL, jit_tasklet, create_proc_read_entry("jitasklethi", 0, NULL, jit_tasklet, (void *)1); return 0; /* success */. jit_busy 실행예 $ dd bs=22 count=5 conv=sync < /proc/jitbusy <= /proc/jitbusy에서 22바이트의레코드 5개출력 <= 1초지연전후의jiffies 값출력 1852291723 1852291973 1852291973 1852292223 1852292223 1852292473 1852292473 1852292723 1852292723 1852292973 5+0 records in 5+0 records out 110 bytes (110 B) copied, 5.00022 seconds, 0.0 kb/s $ 순천향대학교컴퓨터학부이상정 20

jit_sched /proc/jitbusy 를읽는것은최악의시스템성능 프로세서가 1 초동안정지 정지되는동안다른프로세스를스케쥴하여성능향상 /proc/jitsched unsigned long j1= jiffies + jit_delay * HZ; while(time_before(jiffies, j1)) schedule(); 현재프로세스는아무것도하지않고 CPU 를양도하지만실행큐 (run queue) 에는그대로잔류 일단한프로세스가 schedule 로프로세서를양도하면곧다시프로세서를점유한다는보장은없음 허용되는지연시간의상한값이있는경우이방식으로 schedule 을호출하는것은바람직하지않음 실행결과는 jit_busy 와유사 순천향대학교컴퓨터학부이상정 21 jit_sched 코드 : jit.c #include <linux/time.h> int delay = HZ; /* the default delay, expressed in jiffies */.. int jit_fn(char *buf, char **start, off_t offset, int len, int *eof, void *data) unsigned long j0, j1; /* jiffies */ wait_queue_head_t wait; init_waitqueue_head (&wait); j0 = jiffies; j1 = j0 + delay; switch((long)data) case JIT_SCHED: while (time_before(jiffies, j1)) schedule(); break; j1 = jiffies; /* actual value after we delayed */ len = sprintf(buf, "%9li %9li n", j0, j1); *start = buf; return len; 순천향대학교컴퓨터학부이상정 22... int init jit_init(void) create_proc_read_entry("currentime", 0, NULL, jit_currentime, create_proc_read_entry("jitbusy", 0, NULL, jit_fn, (void *)JIT_BUSY); create_proc_read_entry("jitsched",0, NULL, jit_fn, (void *)JIT_SCHED); create_proc_read_entry("jitqueue",0, NULL, jit_fn, (void *)JIT_QUEUE); create_proc_read_entry("jitschedto", 0, NULL, jit_fn, (void *)JIT_SCHEDTO); create_proc_read_entry("jitimer", 0, NULL, jit_timer, create_proc_read_entry("jitasklet", 0, NULL, jit_tasklet, create_proc_read_entry("jitasklethi", 0, NULL, jit_tasklet, (void *)1); return 0; /* success */.

jit_sched 실행예 $ dd bs=22 count=5 < /proc/jitsched 1852519238 1852519488 1852519488 1852519738 1852519738 1852519988 1852519988 1852520238 1852520238 1852520488 5+0 records in 5+0 records out 110 bytes (110 B) copied, 4.99846 seconds, 0.0 kb/s $ 순천향대학교컴퓨터학부이상정 23 jit_queue 드라이버가대기큐를사용하는경우다음의대기수면함수의타임아웃버전을사용 #include <linux/wait.h> long wait_event_timeout(wait_queue_head_t q, condition, long timeout); long wait_event_interruptible_timeout(wait_queue_head_t q, condition, long timeout); 이두함수는주어진대기큐상에서수면을하지만어떤경우에도타임아웃 (jiffies 로표현 ) 내에리턴 /proc/jitqueue wait_queue_head_t wait; init_waitqueue_head (&wait); wait_event_interruptible_timeout(wait, 0, delay); 이구현에서는누구도대기큐상에 wake_up 을호출하지않기때문에프로세스는항상타임아웃이종료되면깨어남 순천향대학교컴퓨터학부이상정 24

jit_queue 코드 : jit.c #include <linux/time.h> int delay = HZ; /* the default delay, expressed in jiffies */.. int jit_fn(char *buf, char **start, off_t offset, int len, int *eof, void *data) unsigned long j0, j1; /* jiffies */ wait_queue_head_t wait; init_waitqueue_head (&wait); j0 = jiffies; j1 = j0 + delay; switch((long)data) case JIT_QUEUE: wait_event_interruptible_timeout(wait, 0,delay); break; j1 = jiffies; /* actual value after we delayed */ len = sprintf(buf, "%9li %9li n", j0, j1); *start = buf; return len; 순천향대학교컴퓨터학부이상정 25... int init jit_init(void) create_proc_read_entry("currentime", 0, NULL, jit_currentime, create_proc_read_entry("jitbusy", 0, NULL, jit_fn, (void *)JIT_BUSY); create_proc_read_entry("jitsched",0, NULL, jit_fn, (void *)JIT_SCHED); create_proc_read_entry("jitqueue",0, NULL, jit_fn, (void *)JIT_QUEUE); create_proc_read_entry("jitschedto", 0, NULL, jit_fn, (void *)JIT_SCHEDTO); create_proc_read_entry("jitimer", 0, NULL, jit_timer, create_proc_read_entry("jitasklet", 0, NULL, jit_tasklet, create_proc_read_entry("jitasklethi", 0, NULL, jit_tasklet, (void *)1); return 0; /* success */. jit_queue 실행예 $ dd bs=22 count=5 < /proc/jitqueue 1852697647 1852697897 1852697897 1852698147 1852698147 1852698397 1852698397 1852698647 1852698647 1852698897 5+0 records in 5+0 records out 110 bytes (110 B) copied, 4.99722 seconds, 0.0 kb/s $ 순천향대학교컴퓨터학부이상정 26

jit_schedto /proc/jitqueue 는누구도대기큐상에깨우지않기때문에프로세스는항상타임아웃이종료되면깨어남 /proc/jitschedto 깨어야할이벤트가이벤트가없는경우 schedule_timeout() 함수사용 set_current_state(task_interruptible); schedule_timeout (delay); schedule_timeout() 은주어진시간동안수면 set_current_state(task_interruptible) 함수는타임아웃까지스케쥴러가현재프로세스를실행하는것을방지 순천향대학교컴퓨터학부이상정 27 jit_schedto 코드 : jit.c #include <linux/time.h> int delay = HZ; /* the default delay, expressed in jiffies */.. int jit_fn(char *buf, char **start, off_t offset, int len, int *eof, void *data) unsigned long j0, j1; /* jiffies */ wait_queue_head_t wait; init_waitqueue_head (&wait); j0 = jiffies; j1 = j0 + delay; switch((long)data) case JIT_SCHEDTO: set_current_state(task_interruptible); schedule_timeout (delay); break; j1 = jiffies; /* actual value after we delayed */ len = sprintf(buf, "%9li %9li n", j0, j1); *start = buf; return len; 순천향대학교컴퓨터학부이상정 28... int init jit_init(void) create_proc_read_entry("currentime", 0, NULL, jit_currentime, create_proc_read_entry("jitbusy", 0, NULL, jit_fn, (void *)JIT_BUSY); create_proc_read_entry("jitsched",0, NULL, jit_fn, (void *)JIT_SCHED); create_proc_read_entry("jitqueue",0, NULL, jit_fn, (void *)JIT_QUEUE); create_proc_read_entry("jitschedto", 0, NULL, jit_fn, (void *)JIT_SCHEDTO); create_proc_read_entry("jitimer", 0, NULL, jit_timer, create_proc_read_entry("jitasklet", 0, NULL, jit_tasklet, create_proc_read_entry("jitasklethi", 0, NULL, jit_tasklet, (void *)1); return 0; /* success */.

jit_schedto 실행예 $ dd bs=22 count=5 < /proc/jitschedto 1853067602 1853067852 1853067852 1853068102 1853068102 1853068352 1853068352 1853068602 1853068602 1853068852 5+0 records in 5+0 records out 110 bytes (110 B) copied, 4.99748 seconds, 0.0 kb/s $ 순천향대학교컴퓨터학부이상정 29 짧은지연 (short delays) 하드웨어와동기를위해아주짧은지연을하는경우 jiffies 를사용할수없음 짧은지연을위한커널함수 #include <linux/delay.h> void ndelay(unsigned long nsecs); // nano-second void udelay(unsigned long usecs); // micro-second void mdelay(unsigned long msecs); // milli-second 소프트웨어루프를사용하여지연 부팅시실행되는 BogoMips 계산의결과인 loops_per_second 정수값에기반하여루프가수행 udelay와 mdelay는 busy-waiting 함수이므로지연동안다른태스크를실행할수없으므로불가피한경우에만이들함수를사용 순천향대학교컴퓨터학부이상정 30

커널타이머 (Kernel Timers) 순천향대학교컴퓨터학부이상정 31 커널타이머 커널타이머는미래의특정시간에함수 ( 타이머핸들러 ) 의실행을스케쥴하는데사용 커널타이머에등록된함수는오직한번만실행 커널타이머는이중연결리스트로구성되어여러개타이머생성가능 타이머는프로세서가시스템콜을수행하고있어도정확히제시간에타이머를만료하여태스크를실행하므로레이스조건을유발 타이머함수에서사용되는자료구조는 atomic types 과스핀락을사용하여병행접근 (concurrent access) 으로부터보호되어야함 순천향대학교컴퓨터학부이상정 32

타이머자료구조 <linux/timer.h> 에정의된타이머의자료구조 struct timer_list.. unsigned long expires; /* the timeout, in jiffies */ void (*function)(unsigned long); /* handler of the timeout unsigned long data; /* argument to the handler */ ; 타이머의타임아웃값은 jiffies로표현, jiffies의값이 timer->expires 보다크거나같으면 timer->function이실행 타임아웃은절대값으로표시되므로현재의 jiffies의값에원하는지연값을더해주어설정 순천향대학교컴퓨터학부이상정 33 타이머관련함수 void init_timer(struct timer_list *timer); struct timer_list TIMER_INITIALIZER(_function, _expires,_data); 타이머구조체를초기화 void add_timer(struct timer_list *timer); 타이머를타이머리스트에추가 int del_timer(struct timer_list *timer); 타이머가만료되기전에타이머를리스트에서삭제 타이머가만료된경우에는자동적으로리스트에서삭제됨 순천향대학교컴퓨터학부이상정 34

jit_timer 예 /proc/jitimer 매 10 jiffies 마다 6개의라인을출력 출력되는값은 time( 현재 jiffies), delta( 이전 jiffies와의차 ), 인터럽트모드여부, 프로세스번호, cpu 번호, 실행중인명령 $ cat /proc/jitimer time delta inirq pid cpu command 1853225734 0 0 13315 0 cat 1853225744 10 1 0 0 swapper <- idle 상태표시 1853225754 10 1 0 0 swapper 1853225764 10 1 0 0 swapper 1853225774 10 1 0 0 swapper 1853225784 10 1 0 0 swapper $ 순천향대학교컴퓨터학부이상정 35 #include <linux/time.h> int tdelay = 10; struct jit_data struct timer_list timer; struct tasklet_struct tlet; inthi; /* taskletor tasklet_hi*/ wait_queue_head_t wait; unsigned long prevjiffies; unsigned char *buf; int loops; ; #define JIT_ASYNC_LOOPS 5 void jit_timer_fn(unsigned long arg) struct jit_data *data = (struct jit_data *)arg; unsigned long j = jiffies; data->buf += sprintf(data ->buf, "%9li %3li %i %6i %i %s n", j, j - data->prevjiffies, in_interrupt()? 1 : 0, current->pid, smp_processor_id(), current->comm); if (--data->loops) data->timer.expires += tdelay; data->prevjiffies = j; add_timer(&data->timer); else wake_up_interruptible(&data->wait); 순천향대학교 컴퓨터학부이상정 36 jit_timer 코드 : jit.c (1) int jit_timer(char *buf, char **start, off_t offset, int len, int *eof, void *unused_data) struct jit_data *data; char *buf2 = buf; unsigned long j = jiffies; data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; init_timer(&data->timer); init_waitqueue_head (&data->wait); /* write the first lines in the buffer */ buf2 += sprintf(buf2, " time delta inirq pid cpu command n"); buf2 += sprintf(buf2, "%9li %3li %i %6i %i %s n", j, 0L, in_interrupt()? 1 : 0,current->pid, smp_processor_id(), current->comm); /* fill the data for our timer function */ data->prevjiffies = j; data->buf = buf2; data->loops = JIT_ASYNC_LOOPS;

jit_timer 코드 : jit.c (2) /* register the timer */ data->timer.data = (unsigned long)data; data->timer.function = jit_timer_fn; data->timer.expires = j + tdelay; /* parameter */ add_timer(&data->timer); /* wait for the buffer to fill */ wait_event_interruptible(data->wait,!data->loops); if (signal_pending(current)) return -ERESTARTSYS; buf2 = data->buf; kfree(data); *eof = 1; return buf2 - buf;... int init jit_init(void) create_proc_read_entry("currentime", 0, NULL, jit_currentime, create_proc_read_entry("jitbusy", 0, NULL, jit_fn, (void *)JIT_BUSY); create_proc_read_entry("jitsched",0, NULL, jit_fn, (void *)JIT_SCHED); create_proc_read_entry("jitqueue",0, NULL, jit_fn, (void *)JIT_QUEUE); create_proc_read_entry("jitschedto", 0, NULL, jit_fn, (void *)JIT_SCHEDTO); create_proc_read_entry("jitimer", 0, NULL, jit_timer, create_proc_read_entry("jitasklet", 0, NULL, jit_tasklet, create_proc_read_entry("jitasklethi", 0, NULL, jit_tasklet, (void *)1); return 0; /* success */. 순천향대학교컴퓨터학부이상정 37 태스크릿 (Tasklet) 순천향대학교컴퓨터학부이상정 38

태스크릿 (tasklets) 소개 태스크릿 (tasklet) 은커널타이머와유사하게동작 인터럽트시실행됨 커널타이머와마찬가지로소프트웨어인터럽트로처리 커널타이머와다르게등록된함수가실행되는시간을지정할수없음 인터럽트핸들러에서유용하게사용 하드웨어인터럽트처리는신속하게처리 관련된데이터처리는이후에태스크릿등으로소프트웨어인터럽트로처리 태스릿자료구조 #include <linux/interrupt.h> struct tasklet_struct ; /*... */ void (*func)(unsigned long); unsigned long data; // 실행을위해등록되는함수 // 등록된함수에전달되는인수 순천향대학교컴퓨터학부이상정 39 태스크릿함수 <linux/interrupt.h> 에정의 void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data); 태스크릿초기화, 지정된함수등록 DECLARE_TASKLET(name, function, data); 태스크릿선언 DECLARE_TASKLET_DISABLED(name, function, data); 태스크릿을선언하지만처음상태는불능 (disabled) 으로세팅 스케쥴은되지만가까운장래에가능 (enabled) 해질때까지실행되지않음 void tasklet_schedule(struct tasklet_struct *t); 태스크릿실행을위해스케쥴 void tasklet_hi_schedule(struct tasklet_struct *t); 태스크릿실행을위해스케쥴 다른소프트웨어인터럽트보다높은우선순위부여 순천향대학교컴퓨터학부이상정 40

jit_tasklet 예 /proc/jitasklet 매 10 jiffies 마다 6개의라인을출력 출력되는값은 time( 현재 jiffies), delta( 이전 jiffies와의차 ), 인터럽트모드여부, 프로세스번호, cpu 번호, 실행중인명령 $ cat /proc/jitasklet time delta inirq pid cpu command 1896945662 0 0 16943 0 cat 1896945662 0 1 2 0 ksoftirqd/0 <- 소프트웨어인터럽트핸들러 1896945662 0 1 2 0 ksoftirqd/0 1896945662 0 1 2 0 ksoftirqd/0 1896945662 0 1 2 0 ksoftirqd/0 1896945662 0 1 2 0 ksoftirqd/0 $ 순천향대학교컴퓨터학부이상정 41 #include <linux/time.h> struct jit_data struct timer_list timer; struct tasklet_struct tlet; inthi; /* taskletor tasklet_hi*/ wait_queue_head_t wait; unsigned long prevjiffies; unsigned char *buf; int loops; ; #define JIT_ASYNC_LOOPS 5 void jit_tasklet_fn(unsigned long arg) struct jit_data *data = (struct jit_data *)arg; unsigned long j = jiffies; data->buf += sprintf(data->buf, "%9li %3li %i %6i %i %s n", j, j - data->prevjiffies, in_interrupt()? 1 : 0, current->pid, smp_processor_id(), current->comm); if (--data->loops) data->prevjiffies = j; if (data->hi) tasklet_hi_schedule(&data->tlet); else tasklet_schedule(&data->tlet); else wake_up_interruptible(&data->wait); 순천향대학교컴퓨터학부이상정 42 jit_tasklet 코드 : jit.c (1) int jit_tasklet(char *buf, char **start, off_t offset, int len, int *eof, void *arg) struct jit_data *data; char *buf2 = buf; unsigned long j = jiffies; long hi = (long)arg; data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; init_waitqueue_head (&data->wait); /* write the first lines in the buffer */ buf2 += sprintf(buf2, " time delta inirq pid cpu command n"); buf2 += sprintf(buf2, "%9li %3li %i %6i %i %s n", j, 0L, in_interrupt()? 1 : 0, current->pid, smp_processor_id(), current->comm); /* fill the data for our tasklet function */ data->prevjiffies = j; data->buf = buf2; data->loops = JIT_ASYNC_LOOPS;

jit_tasklet 코드 : jit.c (2) /* register the tasklet */ tasklet_init(&data->tlet, jit_tasklet_fn, (unsigned long)data); data->hi = hi; if (hi) tasklet_hi_schedule(&data->tlet); else tasklet_schedule(&data->tlet); /* wait for the buffer to fill */ wait_event_interruptible(data->wait,!data->loops); if (signal_pending(current)) return -ERESTARTSYS; buf2 = data->buf; kfree(data); *eof = 1; return buf2 - buf;... int init jit_init(void) create_proc_read_entry("currentime", 0, NULL, jit_currentime, create_proc_read_entry("jitbusy", 0, NULL, jit_fn, (void *)JIT_BUSY); create_proc_read_entry("jitsched",0, NULL, jit_fn, (void *)JIT_SCHED); create_proc_read_entry("jitqueue",0, NULL, jit_fn, (void *)JIT_QUEUE); create_proc_read_entry("jitschedto", 0, NULL, jit_fn, (void *)JIT_SCHEDTO); create_proc_read_entry("jitimer", 0, NULL, jit_timer, create_proc_read_entry("jitasklet", 0, NULL, jit_tasklet, create_proc_read_entry("jitasklethi", 0, NULL, jit_tasklet, (void *)1); return 0; /* success */. 순천향대학교컴퓨터학부이상정 43 워크큐 (Workqueues) 순천향대학교컴퓨터학부이상정 44

워크큐소개 워크큐의동작은태스크릿과유사하지만다음과같은차이가있다. 태스크릿은인터럽트모드 ( 소프트웨어인터럽트 ) 로실행되지만워크큐는커널프로세스로실행되어더융통성이있다. 워크큐에등록된함수는실행을지연시킬수있다. 인터럽트모드실행될때코드에많은제약 프로세스컨텍스트가없기때문에임의의특정프로세스와관련된사용자영역에로접근이허용되지않음 인터럽트모드코드는 schedule이나 sleep_on을호출할수없다. 또한수면에들어갈수있는함수들도호출할수없음 수면에들어갈있기때문에세마포도사용할수없음 커널코드는 in_interrupt() 함수를사용하여인터럽트모드에서수행되는지여부를테스트 프로세서가인터럽트모드로실행되면 0 이아닌값을리턴 순천향대학교컴퓨터학부이상정 45 워크큐함수 워크큐는 <linux/workqueue.h> 에서 struct workqueue_struct 구조체의자료구조로정의워크큐생성함수 struct workqueue_struct *create_workqueue(const char *name); struct workqueue_struct *create_singlethread_workqueue(const char *name); 각각워크큐에대해독립쓰레드또는하나의단일쓰레드로실행하는워크큐생성워크에태스크를등록하는함수 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); 후자의함수는 delay 경과후에워크를실행 순천향대학교컴퓨터학부이상정 46

공유큐 (shared queue) 독자적인큐를사용하지않고공유되어사용되는큐에함수등록후실행 int schedule_work(struct work_struct *work); 공유큐에워크를등록 jiq ("just in queue") 모듈예 static struct work_struct jiq_work; /* this line is in jiq_init( ) */ INIT_WORK(&jiq_work, jiq_print_wq, &jiq_data); prepare_to_wait(&jiq_wait, &wait, TASK_INTERRUPTIBLE); schedule_work(&jiq_work); schedule( ); finish_wait(&jiq_wait, &wait); 순천향대학교컴퓨터학부이상정 47 jiq 샘플코드소개 jiq(just In Queue) 샘플코드 소스 : source/ misc-modules/jiq.c jiqwq, jiqwqdelay 소스코드 /proc/jiqwq, /proc/jiqwqdelay 을생성 Makefile obj-m := jiq.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 순천향대학교컴퓨터학부이상정 48

jiqwq, jiqwqdelay 실행예 # cd jiq # make # insert jiq.ko # lsmod Module Size Used by jiq 3928 0 jit 4864 0 scull 13368 2 PhaseDvfs 15316 0 SetDvfs 2900 0 # cat /proc/jiqwq time delta preempt pid cpu command 1903722309 0 0 4 0 events/0 <- 프린트를위한 events 프로세스 1903722309 0 0 4 0 events/0 1903722309 0 0 4 0 events/0.. cat /proc/jiqwqdelay time delta preempt pid cpu command 1903780046 1 0 4 0 events/0 1903780047 1 0 4 0 events/0 1903780048 1 0 4 0 events/0. 순천향대학교컴퓨터학부이상정 49 jiqwq, jiqwqdelay 코드 : jiq.c (1) #include <linux/workqueue.h> static long delay = 1; #define LIMIT (PAGE_SIZE-128) static DECLARE_WAIT_QUEUE_HEAD (jiq_wait); static struct work_struct jiq_work; static struct clientdata int len; char *buf; unsigned long jiffies; long delay; jiq_data; static int jiq_print(void *ptr) struct clientdata *data = ptr; int len = data->len; char *buf = data->buf; unsigned long j = jiffies; if (len > LIMIT) wake_up_interruptible(&jiq_wait); return 0; if (len == 0) len = sprintf(buf, " time delta preempt pid cpu command n"); else 순천향대학교 len 컴퓨터학부 =0; 이상정 50 len += sprintf(buf+len, "%9li %4li %3i %5i %3i %s n", j, j - data->jiffies, preempt_count(), current->pid, smp_processor_id(), current->comm); data->len += len; data->buf += len; data->jiffies = j; return 1; /* * Call jiq_print from a work queue */ static void jiq_print_wq(void *ptr) struct clientdata *data = (struct clientdata *) ptr; if (! jiq_print (ptr)) return; if (data->delay) schedule_delayed_work(&jiq_work, data->delay); else schedule_work(&jiq_work);

jiqwq, jiqwqdelay 코드 : jiq.c (2) static int jiq_read_wq(char *buf, char **start, off_t offset, int len, int *eof, void *data) DEFINE_WAIT(wait); jiq_data.len = 0; /* nothing printed, yet */ jiq_data.buf = buf; /* print in this place */ jiq_data.jiffies = jiffies; /* initial time */ jiq_data.delay = 0; prepare_to_wait(&jiq_wait, &wait, TASK_INTERRUPTIBLE); schedule_work(&jiq_work); schedule(); finish_wait(&jiq_wait, &wait); *eof = 1; return jiq_data.len; static int jiq_read_wq_delayed(char *buf, char **start, off_t offset, int len, int *eof, void *data) DEFINE_WAIT(wait); jiq_data.len = 0; /* nothing printed, yet */ jiq_data.buf = buf; /* print in this place */ jiq_data.jiffies = jiffies; /* initial time */ jiq_data.delay = delay; prepare_to_wait(&jiq_wait, &wait, TASK_INTERRUPTIBLE); schedule_delayed_work(&jiq_work, delay); schedule(); finish_wait(&jiq_wait, &wait); *eof = 1; return jiq_data.len; 순천향대학교 컴퓨터학부이상정 51 jiqwq, jiqwqdelay 코드 : jiq.c (3) static int jiq_init(void) /* this line is in jiq_init() */ INIT_WORK(&jiq_work, jiq_print_wq, &jiq_data); create_proc_read_entry("jiqwq", 0, NULL, jiq_read_wq, create_proc_read_entry("jiqwqdelay", 0, NULL, jiq_read_wq_delayed, create_proc_read_entry("jitimer", 0, NULL, jiq_read_run_timer, create_proc_read_entry("jiqtasklet", 0, NULL, jiq_read_tasklet, return 0; /* succeed */ 순천향대학교컴퓨터학부이상정 52