1, 과제설명 ( 사용자 요구사항 기술: 과제에 대한 설명 및 목표 )2, 사용자 요구사항을 정형적 방법으로 기술 (UML, Pseudo code, 그림등을 이용하여 기슬)vi 편집기를 사용하여 zombie 프로세스를 c형식으로 작성해 봤습니다.pid(process identification)를 선언하여 그 값이음수인 경우에는 error인 것으로 설정하였고0이 아닌 경우 parent가 실행되니 parent pid라고 출력되게 설정하였고0인 경우 child가 실행되니 child라고 출력되게 설정하였습니다.make zombie를 실행하여 zombie.c로 만들어놓은 파일을 실행./zombie&를 이용하여 background 방식으로 하였습니다.pid가 2970인 것을 확인하였고 ps ?l 코드를 입력하여 Z(zombie)부분의 pid와 부모 pid를확인하였습니다.zombie 프로세스를 종료하기 위하여 parent를 종료시키기 위해zombie의 ppid(parent pid) 부분을 kill ?9 코드를 입력하였습니다.3. 알고리즘 및 자료구조 설계 내용zombie 코드를 c파일 형식으로 생성 -> zombie 파일을 백그라운드 방식으로 실행-> 부모 process의 pid 확인 -> 부모 process 종료 -> 프로그램 종료4. 소스코드 설명 ( 직접 작성한 소스코드중에 핵심 부분을 발췌하여 설명 )pid = fork();선언한 pid에 fork()를 실행시켜 자식 process 생성if (pid>0) , else if(!pid) , else if(pid == -1)pid의 값에 따라 부모, 자식이 실행이 되는지를 표시 및 오류 경우 표시make zombievi zombie.c 로 zombie라는 이름의 c파일을 vi편집기로 생성하였기에실행시키기 위해 zombie 파일 실행./zombie&background 방식으로 표현하여 실행되는 과정들은 보여지지 않고 출력 되게 실행ps -lzombie 프로세스의 부모, 자식부분의 pid를 확인kill ?9 2970확인한 부모 프로세스의 pid를 받아 부모 프로세스를 종료시켜 zombie프로세스를 종료시킴5. 실행결과 및 설명 ( 실행 결과를 캡쳐하여 첨부한 후 설명 )(그림을 문서에 포함, 글자처럼 취급 옵션, 잉크 절약과 잘 보이게 하기위해 그림 반전)작성된 프로그램을 실행한 결과 위와 같은 화면이 출력 되었다.6. 고찰 ( 과제를 진행하면서 배운점 이나, 시행 착오 내용, 기타 느낀점 )강의를 통해 배운 부분을 실제로 코드로 작성하여 실행시켜 보았고 그 결과를 확인해 보았습니다.7. 전체 소스코드 ( 글자크기 9에 줄간격을 120%로 유지하고 한 줄이 너무 길지 않게 작성 )vi zombie.c--------------------------------------------------------------------#include #include #include int main(void) {pid_t pid;pid = fork();if (pid > 0) {printf("I am the parent of pid=%d!n", getpid());sleep(60);
과목명학과과제명: thread 실습1, 과제설명 ( 사용자 요구사항 기술: 과제에 대한 설명 및 목표 )2, 사용자 요구사항을 정형적 방법으로 기술 (UML, Pseudo code, 그림등을 이용하여 기슬)예제1 코드를 Dev를 이용하여 작성 후 동작 시켜보았습니다.thread id를 배열형식으로 만들어서 pthread를 아이디와 넘겨줄 인자와 실행함수를 넣어생성하였습니다. 값을 포인터 형식으로 받아 마지막 출력값을 main함수로 가져올 수 있도록코드를 작성해 보았습니다. mutex를 이용하여 동기화문제를 해결해 보았습니다.예제2 코드를 Dev를 이용하여 작성 후 동작 시켜보았습니다.thread id를 배열형식으로 만들어서 pthread를 아이디와 넘겨줄 인자와 실행함수를 넣어생성하였습니다. thread id를 2가지를 하여 서로 교차하여 하나씩 들어갈 수 있도록하였고 thread가 종료시 값을 받을 수 있도록 대기함수를 작성하였습니다.그 전에는 make를 이용해 c파일을 컴파일 하였다면 이번은 pthread가 들어가 있어gcc ?lpthread방식으로 컴파일 하였습니다. -lpthread가 없으면 pthread create와 join함수를 인지하지 못하는 것을 한번 확인해보았습니다.위 Dev와 같이 코드를 작성하였고 같은 방식으로 컴파일을 하였습니다.실행결과 두 함수가 서로 들어가는 속도가 일정하지 않음을 확인하였고 그결과중간에 동기화 문제가 생기는 것을 확인하였습니다.3. 알고리즘 및 자료구조 설계 내용동작을 실행할 함수코드 작성 -> main문에서 pthread create에 실행할 함수와 인자thread id를 넣어 생성 후 실행 -> thread 종료시까지 기다려 값을 받아 출력 ->동기화 문제를 mutex를 이용하여 해결 -> gcc ?lpthread방식을 이용하여 컴파일 -> 확인4. 소스코드 설명 ( 직접 작성한 소스코드중에 핵심 부분을 발췌하여 설명 )pthread_t thread_id[2];thread id를 배열형식으로 선언하였습니다.pthread_create(&thread_id[0],NULL,t_func,(void *)&t1);thread id와 실행함수, 함수 인자를 넣어 pthread 생성함수를 작성하였습니다.attr은 NULL값으로 따로 넣어주었습니다.pthread_join(thread_id[0], (void **)&status);함수가 종료후 값을 받기 위하여 코드를 작성하였고 실행함수의 return 값을status가 받아 출력할 수 있도록 준비하였습니다.pthread_mutex_t m_lock = PTHREAD_MUTEX_INITIALIZER;pthread_mutex_lock(&m_lock);pthread_mutex_unlock(&m_lock);pthread_mutex_destroy(&m_lock);동기화 문제를 해결하기 위하여 mutex를 이용하여 동기화할 첫 부분에 lock을 걸어주고동기화의 마지막 부분에 unlock을 하는 형식으로 진행하였습니다.동기화를 이용하였기에 함수가 종료될시 동기화한 mutex를 종료시켰습니다.gcc -o test1 test1.c -lpthreadpthread 함수가 포함되어 있는 경우여서 lpthread를 추가하여 컴파일을 하였습니다.5. 실행결과 및 설명 ( 실행 결과를 캡쳐하여 첨부한 후 설명 )예제 1,2를 작성하여 실행한 결과 위와 같은 화면이 출력 되었습니다.6. 고찰 ( 과제를 진행하면서 배운점 이나, 시행 착오 내용, 기타 느낀점 )pthread를 ubuntu상에서 처음으로 컴파일을 해보았고 방법에 따라 어떤식으로 차이가 나는지를확인 할 수 있었고, 동기화 역시도 작성해보지 않아 실제로 어떻게 차이가 나는지 확인을 할 수있었습니다. 코드의 이해나 코드를 실행해보는건 어렵지 않았는데 컴파일시에 옵션 추가를 해본 것은 이번이 처음이라 컴파일 하는과정이 좀 어려웠지만 실습인만큼 쉽게 진행할 수 있었습니다.7. 전체 소스코드 ( 글자크기 9에 줄간격을 120%로 유지하고 한 줄이 너무 길지 않게 작성 )#include #include #include #include pthread_mutex_t m_lock = PTHREAD_MUTEX_INITIALIZER;void *t_func(void *data){int *count = (int *)data;int i;pthread_mutex_lock(&m_lock);for(i=0;i
과제명: 커널 모듈 프로그래밍에서의 Linked list 사용1, 과제설명 ( 사용자 요구사항 기술: 과제에 대한 설명 및 목표 )2, 이론리스트에서 노드와 노드들의 연결방식은 다음과 같다.위의 예시는 int형의 데이터를 저장하는 단순한 노드이다. struct node *prev와 struct node *next가 있는 걸 봤을 때 이중 연결리스트 임을 알 수 있다.리눅스 커널에서도 리스트를 이와 같은 자료구조의 형태로 관리할까? 실제 코드를 보면 알 수 있지만 그 구조는 다르다.실제 리눅스에서는 node내에 list_head라는 자료 구조를 두어서 관리한다. 따라서 구조는 다음과 같다.3. 알고리즘 및 자료구조 설계 내용구조체 생성후 list_head를 통한 구조체 선언 후 LIST_HEAD를 통한 리스트 선언-> list_add(), list_add_tail()을 통한 각각 리스트의 앞, 뒤쪽에 노드 추가-> 매크로 list_for_each을 사용하여 리스트 순환list_for_each 매크로의 첫 번째 인자는 순환에 사용되는 포인터 , 두 번째는 리스트의 head 이다.-> list_head()를 포인터의 인자로 사용해 list_del을 통한 리스트 삭제4. 소스코드 설명 ( 직접 작성한 소스코드중에 핵심 부분을 발췌하여 설명 )struct hello_node {int num;struct list_head list;};구조체 생성 , 데이터 구조체에 list_head가 포함되어야 한다.LIST_HEAD(my_list);리스트 선언struct hello_node *node = kmalloc(sizeof(struct hello_node), GFP_KERNEL);node->num = 1234;INIT_LIST_HEAD(&node->list);동적으로 만들어지는 list_head는 INIT_LIST_HEAD를 통해 초기화list_add(&node->list, &my_list);list_add()를 사용하여 리스트의 앞쪽에 노드 추가list_add_tail(&node->list, &my_list);list_add_tail()을 사용하여 리스트의 뒤쪽에 노드 추가list_for_each(ptr, &hello_list) {node = list_entry(ptr, struct hello_node, list);printk("node value : %dn", node->num);}list_for_each 매크로를 사용하여 리스트 순환printf("*학과석차: %d / %dn",20,107);printk("node value : %dn", node->num);리스트를 순환하면서 출력list_del(&node->list);list_head의 포인터를 인자로 list_del 사용, 리스트에서 해당 노드 삭제5. 실행결과 및 설명 ( 실행 결과를 캡쳐하여 첨부한 후 설명 )작성된 프로그램을 실행한 결과 위와 같이 출력되었다.list_add()로 앞쪽에 5개 노드를 삽입하고 list_add_tail()로 뒤에 5개 노드를 각각 삽입해주었다.그다음 순환하면서 값을 출력하고 그 뒤에 리스트를 삭제하면서 동적할당 받은 메모리를 free 해줬다.출력 결과는 4321056789 순서로 나온다.6. 고찰 ( 과제를 진행하면서 배운점 이나, 시행 착오 내용, 기타 느낀점 )아직 리눅스 환경에 익숙하지 않다보니 이번 과제 역시 HW3과 마찬가지로 적지않은 시행착오를 겪었다. 실습과제를 할 때 코드를 그대로 입력했음에도 제대로 make가 안되는 현상이 발생하여해당 오류코드를 구글에 검색해보기도하고 리눅스 헤더파일을 다시 설치하기도 하였으며혹시 list.h 파일에 손상이 있나 싶어서 새로 list.h 파일을 교체해보기도 하고ubuntu 18.04 환경에서 작동하지않자 12.04 환경에서도 실행시켜보고 했는데 해결이 안돼서코드를 하나하나 보는데 static int hello_init(void) 내부에 list print 가 아닌list_print 로 수정해줬더니 허탈할만큼 잘 돌아갔다.과제를 진행할때는 기존의 add_tail() 삽입 코드에 리스트 삭제기능과 순환 매크로 기능을 넣으려고 했으나 아직 코드를 보고 구조를 이해하는 능력이 부족해서 실패했다.결국 기존 코드 수정이 아닌 새로운 코드를 찾아 구현하게 되었다.이번 과제를 진행하면서 리눅스 커널 프로그래밍에서의 연결리스트에 대한 내용을 찾아 이해하는 것은 성공했으나 최근 타 과목에서나 캡스톤에서 주로 파이썬만 활용해보아서 추가 공부가 절실하게 필요함을 느꼈다.7. 전체 소스코드 ( 글자크기 9에 줄간격을 120%로 유지하고 한 줄이 너무 길지 않게 작성 )#include #include #include #include #include struct hello_node {int num;struct list_head list;};static int __init hello_init(void){int i;struct hello_node *node;struct list_head *ptr, *ptrn;LIST_HEAD(hello_list);/* 리스트 앞쪽에 삽입 */for (i = 0; i < 5; i++) {node = kmalloc(sizeof(struct hello_node), GFP_KERNEL);node->num = i;INIT_LIST_HEAD(&node->list);list_add(&node->list, &hello_list);}/* 리스트 뒤쪽에 삽입 */for (; i < 10; i++) {node = kmalloc(sizeof(struct hello_node), GFP_KERNEL);node->num = i;INIT_LIST_HEAD(&node->list);list_add_tail(&node->list, &hello_list);}/* 리스트 순환 */list_for_each(ptr, &hello_list) {node = list_entry(ptr, struct hello_node, list);
과목명학과과제명: 커널 모듈 프로그래밍에서의 타이머 모듈 구현1, 과제설명 ( 사용자 요구사항 기술: 과제에 대한 설명 및 목표 )2, 사용자 요구사항을 정형적 방법으로 기술 (UML, Pseudo code, 그림등을 이용하여 기슬)동적 타이머 혹은 커널 타이머로도 불리는 타이머는, 커널에서 시간의 흐름을 관리하는데 있어서 필수 불가결한 요소이다.커널코드는 종종 어떤 함수의 실행을 일정 시간만큼 지연해야하는 경우가 있다.원하는 것은 어떤 특정한 시간 만큼의 작업을 지연시킬 수 있는 방법이며, 그 방법은 바로 커널 타이머이다. 타이머는 사용하기 아주 쉽다. 즉, 초기값을 설정하고, 만료 시간을 정하고, 만료시 실행할 함수를 지정한 후 타이머를 활성화하면 된다. 여기서 지정한 함수는 타이머가 만료될 때 실행된다.또한 타이머는 주기적이 아니다. 즉 타이머는 만료가 되면 정지하게 된다. 이것이 바로 동적인 타이머가 필요한 또 하나의 이유이다. 이렇게 타이머는 끊임없이 생성되고 소멸되며, 타이머 수에는 제한이 없다. 또한 타이머는 커널 전체에서 널리 사용된다.3. 알고리즘 및 자료구조 설계 내용struct timer_list : 커널 타이머 구조체init_timer(): 커널 타이머 구초제를 초기화 한다add_timer(): 커널 타이머에 수행될 함수를 등록한다del_timer(): 커널 타이머 목록에서 등록된 것을 제거한다.커널 타이머는 동작 시간이 1/Hz 단위로 1/Hz초 이하의 호출 주기는 사용이 불가능 하다struct time_list 변수는1. unsigned long expires, 2 unsigned long data, void (*function)(unsigned long)을 일반적으로 지정하여 사용한다.1. unsigned long expires 는 다음과 같이 초기화 한다kerneltime.expires=get_jiffies_64()+(3*HZ/10);(현재 jiffies값을 얻어서 0.03초가 지난후로 설정)2. unsigned long data 는 timer 함수에 전달할 데이터를 참조하기 위한 주소를 리턴한다.3. void (*function)(unsigned long)는 타이머 시간이 만료하고 수행할 함수이다.init_timer는 timer 구조체를 초기화 한다. 앞에서 설명한 expires,data,function 필드를 초기화 한다.add_timer는 커널 타이머에 호출될 timer_list 구조체를 등록한다.del_timer는 커널 타이머를 제거한다. 일반적으로 커널 타이머가 등록되고 시간이 초과하여 커널 타이머에 등록된 함수가 호출되면 등록된 커널 타이머는 자동적으로 제거된다. 하지만 디바이스 드라이버는 등록된 커널 타이머가 확실하게 후출되어 제거될 것이라는 확신이 있더라도 모듈 형식으로 디바이스 드라이버를 작성할 경우 디바이스 드라이버의 종료 루틴에 del_timer() 함수를 호출하여 모듈이 제거 되었을때 제거된 번지에 속해 있던 함수가 호출되지 않도록 하여야 한다.4. 소스코드 설명 ( 직접 작성한 소스코드중에 핵심 부분을 발췌하여 설명 )static struct timer_list my_timer;타이머를 생성하기 위한 첫 번째 과정은 타이머를 정의하는 것이다.int init_module( void ){int ret;printk("Timer module installingn");setup_timer( &my_timer, my_timer_callback, 0 );그 다음에는 타이머의 내부 값을 초기화해야 한다. 이는 도우미 함수를 통해 이뤄지며, 타이머에 대한 어떠한 다른 함수를 호출하기 이전에 반드시 이 함수를 호출해야한다.ret = mod_timer( &my_timer, jiffies + msecs_to_jiffies(200) );mod_timer를 통해 타이머를 시작하며 mod_timer 는 새료운 만료시점을 설정하는 기능을 한다.또한 mod_timer()함수는 , 초기화됐지만 아직 활성화가 안된 타이머도 다룰 수 있다. 만약 타이머가비활성화 상태라면 mod_timer()함수를 호출할 때 자동으로 활성화 된다.ret = del_timer( &my_timer );타이머를 만료 이전에 비활성화하려면 del_timer() 함수를 사용한다.5. 실행결과 및 설명 ( 실행 결과를 캡쳐하여 첨부한 후 설명 )작성된 프로그램을 실행한 결과 위와 같은 화면이 출력되었다.타이머 초기화 -> 타이머 시작 -> 타이머 만료시 callback 호출 -> 모듈 제거시 타이머 삭제가 구현되었음을 볼 수 있다.6. 고찰 ( 과제를 진행하면서 배운점 이나, 시행 착오 내용, 기타 느낀점 )실습을 진행하면서 커널 모듈 프로그래밍에서 Makefile을 통해 컴파일 하는법그리고 커널 로드, 언로드 방법과 커널로그를 확인하는 방법을 숙지하게 되었다.그리고 과제를 진행하면서 간단하게 진행될줄 알았으나 가장 힘들었던 점은 기존에 우분투 20.04 LTS를 쓰고있었는데 코드를 아무리 작성해서 컴파일 해보아도 에러가 났다. 처음에는 20.04 버전의 불안정성 때문인줄알고 18.04 , 16.04 버전으로가서 컴파일을 해보았는데도 계속 setup_timer 부분에서 에러가 났다.setup_timer 라는 함수가 커널 4.15 버전 이상에서는 timer_setup으로 쓰인다는 정보를 보고 함수를 바꿔서도 시도해보고 커널 버전을 다운그레이드 시도 해보기도 했으나 무슨 이유인지 make 할 때 실패를해서 많은 시간을 우분투 설치, 커널 버전 변경에 할애하게 되었다.나중에서야 커널버전이 너무 높았음을 알게되어서 Ubuntu 12.04를 설치하고 나서야 문제를 해결 할 수 있었다. 이번 과제를 진행하면서 커널버전에 따라 명령어가 바뀔 수 있음을 배웠고 리눅스는 이번학기 에 처음으로 다뤄봐서 아직 미숙한 부분이 많아 너무 많은 시행착오를 겪었지만 이제 리눅스상에서 코딩을 하고 컴파일 등 기본적인 작업에는 익숙해진 것 같다. 아직까지는 불편한 점이 더 많지만앞으로 익숙해진다면 더욱 효과적으로 리눅스를 다룰 수 있을 것 같다.아직 익숙하다고는 할 수 없지만 커널 모듈 프로그래밍을 하고 Makefile을 통하여 모듈을 컴파일하는
과목명학과과제명: tftp로 간단한 파일 전송1, 과제설명 ( 사용자 요구사항 기술: 과제에 대한 설명 및 목표 )2, 사용자 요구사항을 정형적 방법으로 기술 (UML, Pseudo code, 그림등을 이용하여 기슬)0~100 사이의 수를 random하게 100개 발생하여 배열에 저장한 후 가 장 많이 발생된 수와발생횟수를 구하여 출력하는 함수를 시험해보기 위하여 DEV를 이용해서 작성해 보았습니다.tftp연결시 IPaddress를 문제 없이 연결하기 위하여 네트워크 어댑터를 브리지로 설정해주었습니다.그리고 주소를 원하는 값으로 수동적으로 설정을 해주었습니다.ifconfig를 통하여 현재 연결된 ip가 192.168.1.8임을 확인했습니다.host와 IPaddress만 다르게 client tftp를 위한 setting을 하였습니다.임의로 192.168.1.9로 설정하였습니다.컴파일한 실행파일을 tftp를 이용하여 Host로부터 받아와서 실행하여 코드가 잘 수행되는 것을확인하였습니다.3. 알고리즘 및 자료구조 설계 내용Host 서버에 C언어를 이용한 랜던함수 코드 작성 및 컴파일 -> setting 완료 후 host와 IPaddress가다른 client설정-> TFTP를 이용하여 host에게 미리 만들어둔 실행파일 받기 -> 확인4. 소스코드 설명 ( 직접 작성한 소스코드중에 핵심 부분을 발췌하여 설명 )vi /etc/xinetd.d/tftp---------------------------------service tftp{protocol = udpport = 69socket_type = dgramwait = yesuser = nobodyserver_args = /tftpbootdisable = no}/etc/xinetd.d에 tftp파일을 생성하여 밑에 내용을 파일 안에 입력하였습니다.여기서 /tftpboot는 앞에서 만든 tftpboot 디렉터리 경로를 표시한것입니다.ifconfigifconfig enp0s3 192.168.1.9ifconfig를 입력하여 host의 정보를 확인한 후 다음 코드를 통하여 IPaddress만 다른Client를 같은 방식으로 설정하였습니다.tftp 192.168.1.8tftp> get Ctest2tftp방식을 이용하여 기존에 만들어 둔 실행파일을 복사하였습니다.#include #include #include int main(int argc, char** argv){int i,j,Num[100],k,A[101],count[101];srand(time(NULL));for(i=0;i