Memory & Data Management
Linux System Programming Contents 동적 메모리 관리 Memory Allocation Memory De-allocation 파일 잠금 협조형 잠금 공유파일 구역 잠금 교착상태(deadlock) 회피하기 © Yigeun Chae. Private propriraty, do not copy Linux System Programming
Linux System Programming 1. Memory Management in C C언어 에서 main memory 할당하기 특정 물리적인 주기억 공간을 직접 할당하지 않음 각 프로세스는 할당된 data 영역의 기억공간을 사용 구조체 (struct)로 선언된 데이터는 memory 할당을 한 뒤 사용해야 함 최대 할당 크기는 4GB, 32bit pointer 사용 Flat 32 bit memory Model © Yigeun Chae. Private propriraty, do not copy Linux System Programming
Linux System Programming malloc() #include <stdlib.h> void *malloc(size_t size); - size_t : unsigned int - 결과는 pointer로 반환 한다 메모리 할당은 커널(kernel)에서 담당 물리적 메모리 한계를 넘는 요구시, swap공간(swap space)를 사용 Unix에서 swapping은 4096 bytes page 단위로 동작 virtual memory management의 Paging 기법 최대 할당할 수 있는 크기는 주기억공간 + swap공간 보다 작다 malloc()의 size를 넘어서는 메모리 사용시 error(segmentation fault !) © Yigeun Chae. Private propriraty, do not copy Linux System Programming
Linux System Programming malloc() :간단한 메모리 할당 #include <unistd.h> #include <stdlib.h> #include <stdio.h> #define A_MEGABYTE (1024 * 1024) main() { char *some_memory; int megabyte = A_MEGABYTE; int exit_code = EXIT_FAILURE; some_memory = (char *)malloc(megabyte); if (some_memory != NULL) { sprintf(some_memory, "Hello World\n"); printf("%s", some_memory); exit_code = EXIT_SUCCESS; } exit(exit_code); © Yigeun Chae. Private propriraty, do not copy Linux System Programming
malloc()관련 reference codes memory1.c : 간단한 memory allocation memory2.c : 모든 physical memory allocation memory3.c : 최대 할당 가능한 memory 크기 시험(동시에 여러 프로세스가 동작 때 이상 발생) memory4.c : memory 한번 남용해 보기 © Yigeun Chae. Private propriraty, do not copy Linux System Programming
Linux System Programming memory1.c 간단한 메모리 할당 #include <unistd.h> #include <stdlib.h> #include <stdio.h> #define A_MEGABYTE (1024 * 1024) main() { char *some_memory; int megabyte = A_MEGABYTE; int exit_code = EXIT_FAILURE; some_memory = (char *)malloc(megabyte); if (some_memory != NULL) { sprintf(some_memory, "Hello World\n"); printf("%s", some_memory); exit_code = EXIT_SUCCESS; } exit(exit_code); © Yigeun Chae. Private propriraty, do not copy Linux System Programming
Linux System Programming memory2.c 모든 물리 메모리 할당 #include <unistd.h> #include <stdlib.h> #include <stdio.h> #define A_MEGABYTE (1024 * 1024) main() { char *some_memory; size_t size_to_allocate = A_MEGABYTE; int megs_obtained = 0; while (megs_obtained < 16) { some_memory = (char *)malloc(size_to_allocate); if (some_memory != NULL) { megs_obtained++; sprintf(some_memory, "Hello World"); printf("%s - now allocated %d Megabytes\n", some_memory, megs_obtained); } else { exit(EXIT_FAILURE); exit(EXIT_SUCCESS); © Yigeun Chae. Private propriraty, do not copy Linux System Programming
Linux System Programming memory3.c 유효한 메모리 크기 측정 #include <unistd.h> #include <stdlib.h> #include <stdio.h> #define ONE_K (1024) main() { char *some_memory; int size_to_allocate = ONE_K; int megs_obtained = 0; int ks_obtained = 0; while (1) { for (ks_obtained = 0; ks_obtained < 1024; ks_obtained++) { some_memory = (char *)malloc(size_to_allocate); if (some_memory == NULL) exit(EXIT_FAILURE); sprintf(some_memory, "Hello World"); } megs_obtained++; printf("Now allocated %d Megabytes\n", megs_obtained); exit(EXIT_SUCCESS); © Yigeun Chae. Private propriraty, do not copy Linux System Programming
Linux System Programming memory4.c 메모리 남용해 보기 #include <unistd.h> #include <stdlib.h> #define ONE_K (1024) main() { char *some_memory; char *scan_ptr; some_memory = (char *)malloc(ONE_K); if (some_memory == NULL) exit(EXIT_FAILURE); scan_ptr = some_memory; while(1) { *scan_ptr = '\0'; scan_ptr++; } exit(EXIT_SUCCESS); © Yigeun Chae. Private propriraty, do not copy Linux System Programming
Linux System Programming Null Pointer 접근 memory 공간에 자리 잡지 않은(즉 할당이 안된) 데이터 Unix/Linux에서는 허용하지 않음 #include <unistd.h> #include <stdlib.h> #include <stdio.h> main() { char *some_memory = (char *)0; printf("A read from null %s\n", some_memory); sprintf(some_memory, "A write to null\n"); exit(EXIT_SUCCESS); } 결과: A read from null (null) : GNU C library에서는 null 문자 제공 segmentation fault(core dumped) : null string에 쓰기는 error © Yigeun Chae. Private propriraty, do not copy Linux System Programming
Linux System Programming 또 다른 null pointer 접근 예 #include <unistd.h> #include <stdlib.h> #include <stdio.h> main() { char z = *(const char *)0; printf("I read from location zero\n"); exit(EXIT_SUCCESS); } 결과: segmentation fault(core dumped) : memory 위치 0로 부터 직접 읽기, 이는 허용되지 않음 © Yigeun Chae. Private propriraty, do not copy Linux System Programming
Linux System Programming free() : 할당된 메모리 해제 #include <stdlib.h> void free(void *ptr_to memory); - 이전에 할당된 메모리를 pointer를 통하여 접근 - 접근 한 뒤 release 한번 해제 한 memory공간은 그 프로세스에 다시 할당된다는 보장이 없음(다른 프로세스에서 사용 가능성이 있음) 따라서 free()를 시행한 memory pointer는 다시 접근 불가 © Yigeun Chae. Private propriraty, do not copy Linux System Programming
Linux System Programming free()의 예 #include <stdlib.h> #define ONE_K (1024) main() { char *some_memory; int exit_code = EXIT_FAILURE; some_memory = (char *)malloc(ONE_K); if (some_memory != NULL) { free(some_memory); exit_code = EXIT_SUCCESS; } exit(exit_code); © Yigeun Chae. Private propriraty, do not copy Linux System Programming
Linux System Programming 그외 memory관리 함수 #include <stdlib.h> void *calloc(size_t no_of_element, size_t element_size); void *realloc(void *existing_memory, size_t new_size); calloc()은 malloc()과 유사하나 동일 data형식에 대하여 array형태로 memory allocation시행(0으로 채움) 연속된 memory를 할당한다는 보장이 없음(주의!!) - realloc()은 이미 할당된 메모리 블록의 크기를 확장 이미 할당된 영역에서 연장할 수 없다면 다른 빈 공간으로 이동 따라서 반드시 새로 return되는 pointer를 사용해야 함 © Yigeun Chae. Private propriraty, do not copy Linux System Programming
Linux System Programming 2. File Locking Linux는 다중 사용자/다중 프로세스 환경 특정 파일이나 특정 device를 일시 독점적 사용이 필요 예 lpr process에 의한 특정 프린터 출력 시 충돌 방지 필요 /dev/modem의 사용 시 특정 프로세스에서 독점 사용 필요 File locking은 Linux의 중요 기능 Locking method 파일 전체 잠금: atomic way 파일 부분 잠금: 파일 내용중 특정 부분만 © Yigeun Chae. Private propriraty, do not copy Linux System Programming
Linux System Programming 잠금 표식 파일 생성 Printer daemon에 의한 다수 출력물 충돌 방지 /usr/spool/lpr/lock file을 일시 생성, 프린트 완료 후 제거 위 파일을 잠금 표식 파일(Locking Indicator file) 일종의 binary Semaphore 파일의 생성은 low level system call 사용 open(), read(), write(), close() © Yigeun Chae. Private propriraty, do not copy Linux System Programming
Linux System Programming Locking file creation #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <errno.h> main() { int file_desc; int save_errno; file_desc = open("/tmp/LCK.test", O_RDWR | O_CREAT | O_EXCL, 0444); if (file_desc == -1) { save_errno = errno; printf("Open failed with error %d\n",save_errno); } else { printf("Open succeeded\n"); exit(EXIT_SUCCESS); 동작 방법 % lock1 Open Succeeded Open failed with error 17 errno : /usr/include/errno.h참조 이 프로그램은 종료 된 뒤에도 lock file은 계속 존재 따라서 실행 중에만 lock file을 사용하는 critical section을 사용하기 위해서는 다른 방법 필요 © Yigeun Chae. Private propriraty, do not copy Linux System Programming
File locking: Critical section #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <errno.h> const char *lock_file = "/tmp/LCK.test2"; main() { int file_desc; int tries = 10; while (tries--) { file_desc = open(lock_file, O_RDWR | O_CREAT | O_EXCL, 0444); if (file_desc == -1) { printf("%d - Lock already present\n", getpid()); sleep(3); } 따라서 실행 중에만 lock file을 사용하는 critical section을 사용하기 위해서는 다른 방법 필요 프로그램 수행 중 독점적인 기능을 사용할 때는 lock file을 생성한 뒤 locking을 하고 해제(release)를 할 시점에는 close() -> unlink() 함수 사용 © Yigeun Chae. Private propriraty, do not copy Linux System Programming
Linux System Programming continue! else { /* critical region */ printf("%d - I have exclusive access\n", getpid()); sleep(1); (void)close(file_desc); (void)unlink(lock_file); /* non-critical region */ sleep(2); } } /* while */ exit(EXIT_SUCCESS); 실행 방법 % rm /tmp/LCK.test2 % lock2 & lock2 두 프로세스에서 동시에 locking을 시도하게 되고 먼저 시작된 프로세스에서 lock file을 생성하고 critical section에 들어 감 © Yigeun Chae. Private propriraty, do not copy Linux System Programming
Linux System Programming fcntl() : 파일 구역 잠그기 #include <fcntl.h> int fcntl(int fildes, int command, struct flock, *flock_struct); command: 잠금 명령 (F_GETLK, F_SETLK, F_SETLKW) struct flock : short l_type = F_RDLCK(공유잠금),F_UNLCK(해제),F_WRLCK(배타적잠금) short l_whence = SEEK_SET, SEEK_CUR, SEEK_END (unistd.h에 정의) off_t l_start = 파일내 영역중 잠금의 시작 (bytes) off_t l_len = l_start 부터의 잠금영역의 크기 (bytes) pid_t l_pid = 잠금 프로세스의 pid © Yigeun Chae. Private propriraty, do not copy Linux System Programming
Linux System Programming fcntl() continue ! command: 잠금 명령 F_GETLK : 잠금 정보 구하기, 실제 lock하지 않음, 다른 프로세스에 의한 locking 방지, flock 구조체 전체 사용 * 이미 다른 프로세스에 의해 잠긴 경우 : flock구조체에 정보 채워서 반환 * 잠겨 있지 않는 경우 : flock 구조체 변경 없이 반환 * file의 locking정보 구하기 실패하면 –1 반환 F_SETLK : 실제 locking, l_type, l_pid만 사용 F_SETLKW : F_GETLK 시행 후 다른 프로세스에 의해 잠긴 경우 waiting명령 struct flock : short l_type = F_RDLCK(공유잠금),F_UNLCK(해제),F_WRLCK(배타적잠금) short l_whence = SEEK_SET, SEEK_CUR, SEEK_END (unistd.h에 정의) off_t l_start = 파일내 영역중 잠금의 시작 (bytes) off_t l_len = l_start 부터의 잠금영역의 크기 (bytes) pid_t l_pid = 잠금 프로세스의 pid © Yigeun Chae. Private propriraty, do not copy Linux System Programming
fcntl() : example code - p1 #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> const char *test_file = "/tmp/test_lock"; main() { int file_desc; int byte_count; char *byte_to_write = "A"; struct flock region_1; struct flock region_2; int res; /* open a file descriptor */ file_desc = open(test_file, O_RDWR | O_CREAT, 0666); if (!file_desc) { fprintf(stderr, "Unable to open %s for read/write\n",test_file); exit(EXIT_FAILURE); }/* if */ lock대상 파일은 100bytes 크기 위치는 /tmp/test.lock 두개의 영역에 걸쳐 locking © Yigeun Chae. Private propriraty, do not copy Linux System Programming
fcntl() : example code – p2 /* put some data in the file */ for(byte_count = 0; byte_count < 100; byte_count++) { (void)write(file_desc, byte_to_write, 1); }/* for */ /* setup region 1, a shared lock, from bytes 10 -> 30 */ region_1.l_type = F_RDLCK; region_1.l_whence = SEEK_SET; region_1.l_start = 10; region_1.l_len = 20; /* setup region 2, an exclusive lock, from bytes 40 -> 50 */ region_2.l_type = F_WRLCK; region_2.l_whence = SEEK_SET; region_2.l_start = 40; region_2.l_len = 10; /tmp/test.lock file에 먼저 100byte의 “A”로 채우기 첫번째 locking영역 10 – 30 byte 구역 을 구조체 flock에 입력, 공유잠금 두번째 locking영역 40 – 50 bytes 구역을 구조체 flock에 입력, 배타잠금 © Yigeun Chae. Private propriraty, do not copy Linux System Programming
fcntl() : example code – p3 /* now lock the file */ printf("Process %d locking file\n", getpid()); res = fcntl(file_desc, F_SETLK, ®ion_1); if (res == -1) fprintf(stderr, "Failed to lock region 1\n"); res = fcntl(file_desc, F_SETLK, ®ion_2); if (res == -1) fprintf(stderr, "Failed to lock region 2\n"); /* and wait for a while */ sleep(60); printf("Process %d closing file\n", getpid()); close(file_desc); exit(EXIT_SUCCESS); }/* main */ Test 방법 예제 프로그램은 lock3.c reference code로 lock4.c가 있음 두 파일을 compile ! % lock3 & % lock4 두 프로세스가 경쟁적으로 lock file을 사용 © Yigeun Chae. Private propriraty, do not copy Linux System Programming