[태그:] linux

  • anonymous memory mapping, p308

    https://www.miroch.ru/2017/01/17/linux-process-memory-layout/
    proc pid maps

    여기를 참조 했다.

    #include <stdio.h>
    #include <sys/mman.h>
    
    int main(int argc, char *argv[]) {
    	char *ptr;
    	int ret;
    
    	ptr = (char *) mmap((void *) 0x10000, 512 * 1024, PROT_WRITE|PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
    	printf("page size is %0x\n",getpagesize());
    	printf("ptr is %p\n",ptr);
    
    	sleep(10);
    	/* all done with 'p', so give back the 512 KB mapping */
    	ret = munmap (ptr, 512 * 1024);
    	if (ret)
    		perror ("munmap");
    }
    
    pi@raspberrypi:~/Project/cCode/systemProgram $ ./a.out &
    [1] 3566
    pi@raspberrypi:~/Project/cCode/systemProgram $ page size is 1000
    ptr is 0xb6ff0000
    
    pi@raspberrypi:~/Project/cCode/systemProgram $ cat /proc/3566/maps
    00010000-00011000 r-xp 00000000 b3:02 386325     /home/pi/Project/cCode/systemProgram/a.out
    00020000-00021000 r--p 00000000 b3:02 386325     /home/pi/Project/cCode/systemProgram/a.out
    00021000-00022000 rw-p 00001000 b3:02 386325     /home/pi/Project/cCode/systemProgram/a.out
    014a8000-014c9000 rw-p 00000000 00:00 0          [heap]
    b6e54000-b6f8c000 r-xp 00000000 b3:02 2038       /lib/arm-linux-gnueabihf/libc-2.28.so
    b6f8c000-b6f9c000 ---p 00138000 b3:02 2038       /lib/arm-linux-gnueabihf/libc-2.28.so
    b6f9c000-b6f9e000 r--p 00138000 b3:02 2038       /lib/arm-linux-gnueabihf/libc-2.28.so
    b6f9e000-b6f9f000 rw-p 0013a000 b3:02 2038       /lib/arm-linux-gnueabihf/libc-2.28.so
    b6f9f000-b6fa2000 rw-p 00000000 00:00 0 
    b6fb1000-b6fb5000 r-xp 00000000 b3:02 12827      /usr/lib/arm-linux-gnueabihf/libarmmem-v7l.so
    b6fb5000-b6fc4000 ---p 00004000 b3:02 12827      /usr/lib/arm-linux-gnueabihf/libarmmem-v7l.so
    b6fc4000-b6fc5000 r--p 00003000 b3:02 12827      /usr/lib/arm-linux-gnueabihf/libarmmem-v7l.so
    b6fc5000-b6fc6000 rw-p 00004000 b3:02 12827      /usr/lib/arm-linux-gnueabihf/libarmmem-v7l.so
    b6fc6000-b6fe6000 r-xp 00000000 b3:02 1963       /lib/arm-linux-gnueabihf/ld-2.28.so
    b6ff0000-b6ff6000 rw-p 00000000 00:00 0 
    b6ff6000-b6ff7000 r--p 00020000 b3:02 1963       /lib/arm-linux-gnueabihf/ld-2.28.so
    b6ff7000-b6ff8000 rw-p 00021000 b3:02 1963       /lib/arm-linux-gnueabihf/ld-2.28.so
    bec5d000-bec7e000 rw-p 00000000 00:00 0          [stack]
    bef82000-bef83000 r-xp 00000000 00:00 0          [sigpage]
    bef83000-bef84000 r--p 00000000 00:00 0          [vvar]
    bef84000-bef85000 r-xp 00000000 00:00 0          [vdso]
    ffff0000-ffff1000 r-xp 00000000 00:00 0          [vectors]
    

    0x10000에 메모리를 요청했으나, 불가능하여 0xb6ff0000에 0x2000 byte를 얻었다. 512 KB로 다시 맵핑하여 cat/proc/PID/maps로 확인했다.

    메모리 영역 크기, 주소 비교.
    • heap 영역 밖 노란열에 512KB를 할당 받았다.(anonymous memory mapping)
    • a.out이 3KB(1K+1K+1K)메모리를 사용한다. 10,000~11,000까지 한 블럭, 20,000 ~ 21,000까지 한 블록. 나머지 21,000 ~ 22,000는 offset 1K를 주고 사용한다.
    • a.out 파일 크기는 8KB 이다. 나머지는 메모리의 다른 영역에 넣는 듯 하다.
    • libc-2.28.so는 817KB 메모리를 사용한다.(0x138+0x10+0x2+0x1).
    • b5dbd000 ~ d6ef5000에서 0x138KB를 사용하고, 그 다음 주소에 libc-2.28.so 파일 offset 0x138KB만큼 주고 사용한다. 그 뒤로 같은 방식으로 사용한다.
    • 별도 설정을 하지 않을 경우, heap과 stack은 같은 크기를 갖는다??
  • inotify 예제

    linux system programming, 283p

    리눅스에 파일, 디렉토리를 감시하는 watch가 있다. 특정 경로를 설정하여 감시하여 적절한 이벤트를 작성할 수 있다.

    #include <sys/inotify.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <stdio.h>
    #include <unistd.h>
    #define BUF_LEN 128 
    
    //int inotify_init1 (int flags);
    void main(){
    	int fd; //file descritor
    	int wd; //watch descriptor
    	const char path[50]="/home/now0930/test/ttt";
    	fd = inotify_init1 (0);
    	if (fd == -1) {
    		perror("inotify_init1");
    		exit(EXIT_FAILURE);
    		}
    
    	//printf("%d", IN_MODIFY);
    	wd = inotify_add_watch(fd, path, IN_OPEN);
    	if (wd == -1){
    		perror("add notify");
    		exit(EXIT_FAILURE);
    	}
    	printf("file descriptor is %d\n",fd);
    	printf("path is %s\n",path);
    	
    	//__attribute__ compiler가 제공하는 메모리 번지 정렬. 4바이트 단위로 정렬.
    	//https://blog.naver.com/PostView.nhn?blogId=msyang59&logNo=220885276415
    	char buf[BUF_LEN] __attribute__((aligned(4)));
    	//printf("buf[0] is  0x%ld\n",&buf[0]);
    	//printf("buf[1] is  0x%ld\n",&buf[1]);
    	//printf("buf[2] is  0x%ld\n",&buf[2]);
    	//printf("buf[3] is  0x%ld\n",&buf[3]);
    	//printf("buf[4] is  0x%ld\n",&buf[4]);
    	//printf("buf[5] is  0x%ld\n",&buf[5]);
    	//
    	//
    	ssize_t len, i = 0;
    
    	for (int j=0;j<5;j++){
    		i = 0;
    		/* read BUF_LEN bytes' worth of events */
    		len = read (fd, buf, BUF_LEN);
    		printf("char is %ld\n",buf);
    		printf("len is %ld\n",len);
    		//보통 이런 방식으로 사용.
    		/* loop over every read event until none remain */
    		while (i < len) {
    			struct inotify_event *event =
    			(struct inotify_event *) &buf[i];
    			printf ("wd=%d mask=%d cookie=%d len=%d dir=%s\n", event->wd, event->mask, event->cookie, event->len, (event->mask & IN_ISDIR) ? "yes" : "no");
    			/* if there is a name, print it */
    			if (event->len)
    				printf ("name=%s\n", event->name);
    				/* update the index to the start of the next event */
    			//printf("i is %d\n",i);
    			//printf("buf address is 0x%lx\n",&buf[i]);
    			if (event->mask && IN_ACCESS)
    				printf("the file was read\n");
    			i += sizeof (struct inotify_event) + event->len;
    			}
    	}
    
    
    	int ret;
    	ret = inotify_rm_watch(fd, wd);
    	if(ret)
    		perror("remove watch\n");
    	
    }
    
    
    [21:45:06]>rm ./a.out ;gcc notify.c;./a.out 
    notify.c: In function ‘main’:
    notify.c:45:21: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘char *’ [-Wformat=]
       printf("char is %ld\n",buf);
                       ~~^    ~~~
                       %s
    file descriptor is 3
    path is /home/now0930/test/ttt
    char is 140729024548928
    len is 16
    wd=1 mask=32 cookie=0 len=0 dir=no
    the file was read
    char is 140729024548928
    len is 16
    wd=1 mask=32 cookie=0 len=0 dir=no
    the file was read
    

  • mutex 예제

    linux system programming, 238p. 두 시간 삽질했다. thread arg 를 포인터로 주는데 여러 개를 쓰려면 struct로 정의해서 써야 한댄다. 맞는지 틀린지..

    #include <pthread.h>
    #include <stdio.h>
    #include <unistd.h>
    
    
    //arg를 여러 파라미터로 사용하기 위해,
    //구조체로 정의
    //https://stackoverflow.com/questions/52812004/parameter-passing-multiple-values-using-void-pointer
    //여기 참조
    //공유 자원.
    int sharedInt=0;
    //mutex 설정.
    static pthread_mutex_t the_mutex = PTHREAD_MUTEX_INITIALIZER;
    
    struct myStruct {
    	//struct는 initilizer를 지원하지 않음.
    	char *message;
    	int index;
    	//index를 보고 입력된 파라미터로 hello, one, two, three를 선택.
    	//이렇게 구현하려 했으나, 힘들어 문자열로 변경.
    	//index로 sharedInt를 업데이트 하려 했으나,
    	//잘 안됨..
    	//스레드가 시작할 때마다 sharedInt를 업데이트 하면 기존 값을
    	//버리고 다시 씀!!
    	//thread 안에서만 공유 자원을 조작..
    
    
    };
    
    
    
    void* start_routine(void* arg ){
    	int pid;
    	int threadID;
    	//struct로 arg를 받기 위해, 
    	//struct로 변경.
    	struct myStruct *temp;
    
    	temp = arg;
    	//pointer 로 global 변수 변경
    
    	//pthread_mutex_lock(&the_mutex);
    	//sharedInt = temp->index;
    
    	//printf("my thread sentence is \"%s\"\n", temp->message);
    	//printf("temp->index is %d\n", temp->index);
    
    	pthread_mutex_lock(&the_mutex);
    
    	printf("SharedInt는 %d\n",sharedInt);
    	if(sharedInt == 0){
    		//strsep(temp->message, " ");
    		//printf("my thread word is %s\n",outputword);
    		printf("zero\n");
    		//temp->index++;
    
    	}
    
    	else if(sharedInt == 1){
    		//printf("my thread word is %s\n",outputword);
    		printf("one\n");
    		//temp->index++;
    
    	}
    	else if(sharedInt == 2){
    		printf("two\n");
    		//temp->index++;
    
    	}
    
    	else{
    		printf("three or more\n");
    	}
    	sharedInt++;
    
    	pthread_mutex_unlock(&the_mutex);
    
    	}
    
    int main(){
    
    	pthread_t thread[2];
    	int ret, errorno;
    	struct myStruct message = {"hello one two three", 0 };
    	printf("myStruct message index는 %d\n", message.index);
    	//아래 부분은 불필요 부분. thread 밖에서 조작하여 무의미함.
    	//message.index=2;
    
    	ret = pthread_create(&thread[0],NULL,start_routine,(void*)&message);
    
    	if(ret<0){
    		errorno = ret;
    		//printf("%d\n",errorno);
    		perror("pthread_create");
    		return -1;
    	}
    	//아래 부분은 불필요 부분. thread 밖에서 조작하여 무의미함.
    	//message.index=1;
    
    	//printf("myStruct message index는 %d\n", message.index);
    
    	//printf("struct 출력: %d",message.index);
    	//printf("message 확인 %d",message.index);
    
    	ret = pthread_create(&thread[1],NULL,start_routine,(void*)&message);
    
    	if(ret<0){
    		errorno = ret;
    		//printf("%d\n",errorno);
    		perror("pthread_create");
    		return -1;
    	}
    
    	//각 스레드 끝나길 대기
    
    	pthread_join(thread[0],NULL);
    	pthread_join(thread[1],NULL);
    	//mutex 삭제
    	pthread_mutex_destroy(&the_mutex);
    	printf("completed\n");
    	return 0;
    
    }
    

    100번 돌리면 mutex lock을 설정한 경우와 설정하지 않은 경우 값이 다름. 나름 이해했다고 믿고 싶다.

  • thread 예제

    linux system programming, 234p

    https://bitsoul.tistory.com/m/157 여기 참조.

    #include <pthread.h>
    #include <stdio.h>
    #include <unistd.h>
    
    
    void* start_routine(void* arg ){
    	int pid;
    	int threadID;
    	pid= getpid();
    	printf("pid is %d\n", pid);
    	threadID = pthread_self();
    	printf("tid is %lu\n",threadID);
    	printf("data is %s\n",arg);
    	}
    
    int main(){
    	pthread_t thread[2];
    	const char *message1="hello one";
    	const char *message2="hello two";
    	const char *message3="hello main";
    
    	int ret, errorno;
    	ret = pthread_create(&thread[0],NULL,start_routine,(void*)message1);
    	if(ret<0){
    		errorno = ret;
    		//printf("%d\n",errorno);
    		perror("pthread_create");
    		return -1;
    	}
    	ret = pthread_create(&thread[1],NULL,start_routine,(void*)message2);
    	if(ret<0){
    		errorno = ret;
    		//printf("%d\n",errorno);
    		perror("pthread_create");
    		return -1;
    	}
    
    
    
    	/*
    	for(int i=0;i<2;i++){
    		ret = pthread_create(&thread[i],NULL,start_routine,NULL);
    		if(!ret){
    			errorno = ret;
    			printf("%d\n",errorno);
    			perror("pthread_create");
    			return -1;
    		}
    	}
    	*/
    	int thread_compare=0;
    	//스레드가 다르면 0, 같으면 0이 아는 수 리턴.
    	//다른 스레드로 0을 리턴.
    	thread_compare = pthread_equal(thread[0], thread[1]);
    	printf("thread is same? %d\n",thread_compare);
    	sleep(1);
    	//메인에서  start_routine.
    	start_routine((void*)message3);
    
    
    	//각 스레드 끝나길 대기
    
    	pthread_join(thread[0],NULL);
    	pthread_join(thread[1],NULL);
    	return 0;
    
    }
    

    위 코드를 실행하면 아래와 같다. race condition으로 매 실행 다른 결과를 보았다.

    pi@raspberrypi:~/Project/cCode/systemProgram $ gcc -lpthread mythread.c ;./a.out 
    thread is same? -1235590048
    pid is 14996
    tid is 3059377248
    data is hello two
    pid is 14996
    tid is 3067769952
    data is hello one
    pid is 14996
    tid is 3069673600
    data is hello main
    pi@raspberrypi:~/Project/cCode/systemProgram $ gcc -lpthread mythread.c ;./a.out 
    pid is 15068
    tid is 3067769952
    data is hello one
    pid is 15068
    tid is 3059377248
    data is hello two
    thread is same? 0
    pid is 15068
    tid is 3069673600
    data is hello main
    pi@raspberrypi:~/Project/cCode/systemProgram $ gcc -lpthread mythread.c ;./a.out 
    pid is 15125
    tid is 3068077152
    data is hello one
    thread is same? 0
    pid is 15125
    tid is 3059684448
    data is hello two
    pid is 15125
    tid is 3069980800
    data is hello main
    

    gnu c는 pthread가 전부인가 보다.

  • daemon 예제

    linux system programming, 174p 예제 실행.

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <linux/fs.h>
    
    int main (void)
    
    {
    	pid_t pid, sid;
    	int i;
    	int j=0;
    	/* create new process */
    	pid = fork ();
    	printf("Pid is %d \n",pid);
    	if (pid == -1)
    		return -1;
    	else if (pid != 0)
    		exit (EXIT_SUCCESS);
    
    
    	/* create new session */
    	sid =setsid();
    	if (sid == -1)
    		return -1;
    
    	printf("sid is %d \n",sid);
    	/* set the working directory to the root directory */
    	if (chdir("/") == -1){
    		printf("check");
    		return -1;
    	}
    
    	/* close all open files--NR_OPEN is overkill, but works */
    	printf("FOPEN_MAX is %d\n",FOPEN_MAX);
    	for (i = 0; i < FOPEN_MAX; i++){
    		//j=close(i);
    		close(i);
    		//printf("%d\n", j);
    		printf("%d is closed\n", i);
    	}
    
    	/* redirect fd's 0,1,2 to /dev/null */
    	open("/dev/null", O_RDWR); /* stdin */
    	dup(0); /* stdout */
    	dup(0); /* stderror */
    	/* do its daemon thing... */
    
    	while(1){
    
    		sleep(1);
    		//printf("this is test\n");
    	}
    
    	return 0;
    
    }
    

    54번 행 printf가 나오지 않음은 stdout을 죽여서 그런 듯 하다.

    NR_OPEN을 찾을 수 없는데, 옛날 프로그램이라 다른 문구로 정의된 듯 하다. FOPEN_MAX로 일단 했다.

    pi@raspberrypi:~/Project/cCode/systemProgram $ gcc daemon.c ;./a.out;ps aux | grep pi;
    Pid is 1939 
    Pid is 0 
    sid is 1939 
    FOPEN_MAX is 16
    0 is closed
    message+   346  0.0  0.0   6736  3524 ?        Ss    6월22   0:04 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
    avahi      350  0.0  0.0   5896  2960 ?        Ss    6월22   0:02 avahi-daemon: running [raspberrypi.local]
    pi         846  0.0  0.1  14716  7204 ?        Ss    6월22   0:12 /lib/systemd/systemd --user
    pi         849  0.0  0.0  16864  1772 ?        S     6월22   0:00 (sd-pam)
    pi         891  0.0  0.0   7256  3568 tty1     S+    6월22   0:00 -bash
    pi        1939  0.0  0.0   1852    64 ?        Ss   19:01   0:00 ./a.out
    pi        1940  0.0  0.0   8552  2532 pts/1    R+   19:01   0:00 ps aux
    pi        1941  0.0  0.0   6116   496 pts/1    S+   19:01   0:00 grep --color=auto pi
    root     28022  0.0  0.1  12236  6304 ?        Ss   17:16   0:00 sshd: pi [priv]
    pi       28033  0.0  0.0  12236  3532 ?        S    17:16   0:01 sshd: pi@pts/0
    pi       28036  0.0  0.0   7392  3856 pts/0    Ss   17:16   0:00 -bash
    pi       28244  0.1  0.1  11564  6728 pts/0    S+   17:19   0:06 vi daemon.c
    root     28246  0.0  0.1  12236  6252 ?        Ss   17:19   0:00 sshd: pi [priv]
    pi       28257  0.0  0.0  12236  3552 ?        S    17:19   0:00 sshd: pi@pts/1
    pi       28260  0.0  0.0   7548  3924 pts/1    Ss   17:19   0:00 -bash
    

    pid 1939가 ?로 대몬으로 변신했다.