2015년 6월 27일 토요일

fork 를 사용해서 자식 프로세스 만든 후, 부모 프로세스가 먼저 죽으면, 자식 프로세스의 PPID(부포 프로세스 ID) 는 1 이 되는 시험.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
 
 
void error_handling( char *msg);
 
 
void read_childproc(int sig)
{
    pid_t pid;
    int status;
 
    pid = waitpid( -1, &status, WUNTRACED | WCONTINUED | WNOHANG );
    //pid = waitpid( -1, &status,  WNOHANG );
 
    if( WIFEXITED( status ) )
    {
        printf("child process : %d exit, ret value : %d\n", pid, WEXITSTATUS( status ) );
    }
    else if( WIFSIGNALED(status) )
    {
        printf("child process : %d killed by signal %d\n", pid, WTERMSIG(status) );
    }
    else if( WIFSTOPPED(status) ) 
    {
        printf("child process : %d stopped by signal %d\n", pid, WSTOPSIG(status) );
    }
    else if( WIFCONTINUED(status) )
    {
        printf("child process : %d continued\n",pid );
    }
    else
    {
        printf("Unexpected Flow!\n");
        printf("Unexpected Flow!\n");
        printf("Unexpected Flow!\n");
    }
}
 
 
 
int main(int argc, char * argv[] )
{
 
    pid_t pid_1;
    pid_t pid_2;
 
    struct sigaction act;
    act.sa_handler = read_childproc;
    sigemptyset( &act.sa_mask );
    act.sa_flags = 0;
 
    sigaction( SIGCHLD,  &act, 0 );
 
 
    printf("parent : proces ID : %3d\n",  getpid() );
 
    pid_1 = fork();
 
    if( pid_1 < 0 )
    {
        error_handling("fork() error");
    }
    else if( pid_1 == 0) // child
    {
        int j;
 
        printf("child 1:  proces ID : %3d\n",  getpid() );
 
        for(j=0; j<30; j++)
        {
            sleep(10);
        }
        printf("child 1:  finish    : %3d\n",  getpid() );
        return 10;
    }
    else // parent
    {
        printf("parent : child 1 process ID : %d\n", pid_1 );
 
        pid_2 = fork();
        if( pid_2 < 0 )
        {
            error_handling("fork() error");
        }
        else if( pid_2 == 0 ) // child
        {
            int k;
            printf("child 2: proces ID : %3d\n",  getpid() );
            for(k=0; k<30; k++)
            {
                sleep(10);
            }
            printf("child 2: finish    : %3d\n",  getpid() );
            return 20;
        }
        else //parent
        {
            int i;
            printf("parent : child 2 process ID : %d\n", pid_2 );
 
 
            for(i=0; i< 10; i++ )
            {
                printf("wait...(%d)\n", i + 1);
                sleep(5);
            }
        }
    }
    
    return 0;
}
 
void error_handling( char *msg)
{
    fputs( msg , stderr );
    fputc( '\n', stderr );
 
    fprintf(stderr, "error number : %d\n", errno );
    fprintf(stderr, "error Msg    : %s\n", strerror( errno ) );
 
    exit(1);
}
 
cs


이 코드를 실행하면, 자식 프로세스가 먼저 죽는다.
(for 문의 반복횟수 및 시간 설정에 따라 조절 가능 )

그러면, 자식 프로세스의 PPID 번호가 원래 PPID 와는 달리 1 이 되어 있는 것을 확인할 수 있다.


먼저 프로그램을 실행하고
또 다른 terminal 에서 ps -ef | grep <부모 프로세스 PID>
를 입력하면,
부모, 자식 프로세스를 다 확인할 수 있다.

그리고 부모 프로세스가 죽고 나서
ps -ef 를 이용해
자식 프로세스를 확인하면, PPID 가 1 이 되어 있는 것을 확인할 수 있다.

2015년 5월 10일 일요일

waitpid 에서 WIFSTOPPED 와 WIFCONTINUED 활성화.

Advanced Programming in the UNIX Environment 제 3판 책을 보다가,
waitpid 함수를 실행시킨 후,
waitpid 가 child process 의 상태를 반환할 때, 사용하는
WIFSTOPPED 와  WIFCONTINUED 의 기능을 어떻게 확인해 볼 수 있을까 궁금해졌는데,

waitpid(pid, &status, WUNTRACED | WCONTINUED) 와 같이
WUNTRACED 와 WCONTINUED 를 같이 설정해 주면 되네.


man wait 의 실행 페이지를 보니까
설명이 잘 되어 있다.

           $ ./a.out &
           Child PID is 32360
           [1] 32359
           $ kill -STOP 32360
           stopped by signal 19
           $ kill -CONT 32360
           continued
           $ kill -TERM 32360
           killed by signal 15


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>
 
void error_handling( char * msg );
 
 
int main(int argc, char * argv[] )
{
    int status;
    pid_t pid;
    int i;
 
    if( ( pid = fork() ) < 0 )
    {
        error_handling( "fork() fail!" );
    }
    else if( pid == 0 ) // child
    {
        int j;
        printf("child self print : %d\n", getpid() );
 
 
        for( j=0; j < 100; j++ )
        {
            printf("child : %d\n", j );
            sleep(2);
            //status = status / 0;
            //abort();
            //pause();
        }
 
        return 3;
    }
    else
    {
        printf( "child PID : %d\n", pid );
 
        do
        {
            if( waitpid(pid, &status, WUNTRACED | WCONTINUED)  != pid )
            {
                error_handling("wait() failed!");
            }
 
            if( WIFEXITED( status ) )
            {
                printf("child normal   termination : %d\n", WEXITSTATUS( status ) );
            }
            else if( WIFSIGNALED( status ) )
            {
                printf("child abnormal termination : %d, msg : '%s'\n",
                        WTERMSIG( status ),
                        strsignal( WTERMSIG( status ) )
                    );
            }
            else if( WIFSTOPPED( status ) )
            {
                printf("child stop : %d\n", WSTOPSIG( status ) );
            }
            else if( WIFCONTINUED( status ) )
            {
                printf("child continue\n" );
            }
        }while( !WIFEXITED(status) && !WIFSIGNALED(status) );
        
    }
 
 
    return 0;
}
 
 
void error_handling( char * msg )
{
    fputs( msg, stderr );
    putc('\n', stderr );
 
    fprintf(stderr, "error number  : %d\n", errno );
    fprintf(stderr, "error message : %s\n", strerror( errno ) );
 
    exit(1);
 
}
cs

2015년 5월 3일 일요일

setsockopt 의 SO_SNDBUF 설정 후, 설정 값이 2 개가 되는 현상.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <errno.h>
#include <string.h>
 
 
void error_handle( char * msg);
 
int main(int argc, char * argv[] )
{
    int sock_tcp;
    int sock_udp;
 
    int option;
    socklen_t length; // sys/types.h
 
    sock_tcp = socket( PF_INET, SOCK_STREAM, 0 );
 
    if( sock_tcp == -1 )
        error_handle( "socket error()" );
 
    sock_udp = socket( PF_INET, SOCK_DGRAM, 0 );
 
    if( sock_udp == -1 )
        error_handle( "scoket error()" );
 
 
 
 
    length = sizeof( option );
    if( getsockopt( sock_tcp, SOL_SOCKET, SO_SNDBUF, (void*) &option, &length ) == -1 )
        error_handle( "getsockopt() error" );
 
    printf( "tcp send    buffer size : %d\n", option );
 
    length = sizeof( option );
    if( getsockopt( sock_tcp, SOL_SOCKET, SO_RCVBUF, (void*) &option, &length ) == -1 )
        error_handle( "getsockopt() error" );
 
    printf( "tcp receive buffer size : %d\n", option );
 
 
    option = 1024 * 10;
    if( setsockopt( sock_tcp, SOL_SOCKET, SO_SNDBUF, (void*) &option, sizeof( option ) ) == -1 )
        error_handle( "setsockopt() error" );
 
    length = sizeof( option );
    option = 1024 * 20;
    if( setsockopt( sock_tcp, SOL_SOCKET, SO_RCVBUF, (void*) &option, sizeof( option ) ) == -1 )
        error_handle( "setsockopt() error" );
 
 
    length = sizeof( option );
    if( getsockopt( sock_tcp, SOL_SOCKET, SO_SNDBUF, (void*) &option, &length ) == -1 )
        error_handle( "getsockopt() error" );
 
    printf( "tcp send    buffer size : %d\n", option );
 
    length = sizeof( option );
    if( getsockopt( sock_tcp, SOL_SOCKET, SO_RCVBUF, (void*) &option, &length ) == -1 )
        error_handle( "getsockopt() error" );
 
    printf( "tcp receive buffer size : %d\n", option );
 
 
    /*
    length = sizeof( option );
    if( getsockopt( sock_udp, SOL_SOCKET, SO_SNDBUF, (void*) &option, &length ) == -1 )
        error_handle( "getsockopt() error" );
    printf( "udp send    buffer size : %d\n", option );
    length = sizeof( option );
    if( getsockopt( sock_udp, SOL_SOCKET, SO_RCVBUF, (void*) &option, &length ) == -1 )
        error_handle( "getsockopt() error" );
    printf( "udp receive buffer size : %d\n", option );
    */
 
    close (sock_tcp);
    close (sock_udp);
 
    return 0;
}
 
 
void error_handle( char * msg )
{
    fprintf( stderr, "%s\n", msg );
    fprintf( stderr, "errno number : %d\n", errno );
    fprintf( stderr, "errno message: %s\n", strerror( errno ) );
    exit(1);
}
 
cs



위 코드의 결과.

tcp send    buffer size : 16384
tcp receive buffer size : 87380
tcp send    buffer size : 20480
tcp receive buffer size : 40960


실제
setsockopt 의 변수로, 10240 을 주면 그의 2 배인 20480,
setsockopt 의 변수로, 20480 을 주면 그의 2 배인 40960
이 나온다.

왜 그런지 확인해 보려면,

man 7 socket
명령어를 linux 에서 실행시켜 보면,

아래와 같은 안내를 볼 수 있다.

       SO_SNDBUF
              Sets  or gets the maximum socket send buffer in bytes.  The kernel doubles this value (to allow space for
              bookkeeping overhead) when it is set using setsockopt(2), and this doubled value is returned by  getsock‐
              opt(2).   The  default  value  is set by the /proc/sys/net/core/wmem_default file and the maximum allowed
              value is set by the /proc/sys/net/core/wmem_max file.  The minimum (doubled) value  for  this  option  is
              2048.



UDP와 TCP 소켓의 SND/RCV 버퍼 크기 보기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <errno.h>
#include <string.h>
void error_handle( char * msg);
int main(int argc, char * argv[] )
{
    int sock_tcp;
    int sock_udp;
    int option;
    socklen_t length; // sys/types.h
    sock_tcp = socket( PF_INET, SOCK_STREAM, 0 );
    if( sock_tcp == -1 )
        error_handle( "socket error()" );
    sock_udp = socket( PF_INET, SOCK_DGRAM, 0 );
    if( sock_udp == -1 )
        error_handle( "scoket error()" );
    length = sizeof( option );
    if( getsockopt( sock_tcp, SOL_SOCKET, SO_SNDBUF, (void*) &option, &length ) == -1 )
        error_handle( "getsockopt() error" );
    printf( "tcp send    buffer size : %d\n", option );
    length = sizeof( option );
    if( getsockopt( sock_tcp, SOL_SOCKET, SO_RCVBUF, (void*) &option, &length ) == -1 )
        error_handle( "getsockopt() error" );
    printf( "tcp receive buffer size : %d\n", option );
    length = sizeof( option );
    if( getsockopt( sock_udp, SOL_SOCKET, SO_SNDBUF, (void*) &option, &length ) == -1 )
        error_handle( "getsockopt() error" );
    printf( "udp send    buffer size : %d\n", option );
    length = sizeof( option );
    if( getsockopt( sock_udp, SOL_SOCKET, SO_RCVBUF, (void*) &option, &length ) == -1 )
        error_handle( "getsockopt() error" );
    printf( "udp receive buffer size : %d\n", option );
    close (sock_tcp);
    close (sock_udp);
    return 0;
}
void error_handle( char * msg )
{
    fprintf( stderr, "%s\n", msg );
    fprintf( stderr, "errno number : %d\n", errno );
    fprintf( stderr, "errno message: %s\n", strerror( errno ) );
    exit(1);
}


위와 같은 코드를 사용해서,
UDP와 TCP 소켓의 send buffer 와 receive buffer 크기를 살펴보니,
기본적으로 다르게 설정되어 있음을 알았다.


이를 실행하면,

tcp send buffer size : 16384
tcp receive buffer size : 87380
udp send buffer size : 112640
udp receive buffer size : 112640
이 나왔다.

Linux 에서 기본 설정하는 TCP SND/RCV 버퍼 크기는
sysctl -n net.ipv4.tcp_wmem ( SND 크기 )
sysctl -n net.ipv4.tcp_rmem ( RCV 크기 )
명령어로 확인할 수 있다.


UDP 의 경우 아래로 확인하면 될 것 같다.
sysctl -n net.core.wmem_default sysctl -n net.core.rmem_default


https://wwwx.cs.unc.edu/~sparkst/howto/network_tuning.php

cs

2015년 1월 31일 토요일

영어 행성 이름 순서 외우는 방법.

how to memorize the order of planets in solar system.

My very educated mother just served us nine pies.
아주 교양있는 우리 어머니께서 방금 우리에게 파이 아홉 개를 주셨다.

Mercury
Venus
Earch
Mars
Jupiter
Saturn
Uranus
Neptune
Pluto

출처
행성이야기 (The Planets)
작가 : 데이바 소벨 (Dava Sobel )

2015년 1월 22일 목요일

ddd 를 이용하여 구조체 내에 padding 된 byte 의 쓰레기값 관찰하기.

#include

typedef struct _a
{
char a;
int  i;
}PAD;

typedef struct __attribute__((packed)) _b
{
char a;
int  i;
}PACK;

int main(int argc, char * argv[] )
{
PAD  pad = { 'a', 10 };
PACK pack= { 'b', 20 };

printf( "PAD  char  : %c\n", pad.a );
printf( "PACK char  : %c\n", pack.a );


printf( "size PAD  : %d\n", sizeof(PAD ) );
printf( "size PACK : %d\n", sizeof(PACK) );

return 0;
}


위 코드를 이용하여 ddd 를 사용해보자.


(gdb) print pad.a
$9 = 97 'a'

(gdb) print pad
$10 = {a = 97 'a', i = 10}

pad 의 주소를 출력
(gdb) print &pad
$13 = (PAD *) 0xbffff240


pad.a 의 주소를 출력(값도 같이 나온다.)
(gdb) print &pad.a
$14 = 0xbffff240 "a\324\025"    

a 는 초기화된 값인데, 그 뒤의 값은 왜 저렇게 나오는지 모르겠다.


pad.a 의 주소를 이용하여 word(32bit 컴에서 4 byte) 를 출력
(gdb) x /wx &pad.a
0xbffff240: 0x0015d461

pad.a 의 주소를 이용하여 1 byte 를 출력
(gdb) x /bx &pad.a
0xbffff240: 0x61

( pad.a + 1 ) 주소를 이용하여 1 byte 를 출력
(gdb) x /bx &pad.a + 1
0xbffff241: 0xd4

( pad.a + 2 ) 주소를 이용하여 1 byte 를 출력
(gdb) x /bx &pad.a + 2
0xbffff242: 0x15

( pad.a + 3 ) 주소를 이용하여 1 byte 를 출력
(gdb) x /bx &pad.a + 3
0xbffff243: 0x00





2015년 1월 12일 월요일

ddd 에서 인자주기

http://www.delorie.com/gnu/docs/gdb/gdb_19.html

set args
Specify the arguments to be used the next time your program is run. If set args has no arguments, run executes your program with no arguments. Once you have run your program with arguments, using set args before the next run is the only way to run it again without arguments.
show args
Show the arguments to give your program when it is started.

또는 

After you invoke ddd, goto Program->Run and then provide your arguments.

팔로어