2014년 12월 17일 수요일

Process Environment

<< 프로세스 환경 >>



7.2 main 함수



* main 함수의 원형


int main(int argc, char *argv[]);

argc - 명령줄 인수들의 개수
argv[] - 그 인수들을 가리키는 포인터들의 배열


커널이 exec류 함수들(execl, execv, execle, execve, execlp, execvp) 중 하나를 통해 실행시
main 함수가 호출되기 전에 startup 루틴 호출됨.

프로그램 실행 파일에 지정되어 있는 프로그램 시작 주소는 그 시동 루틴을 가리킴
이는 C 컴파일러가 호출하는 linker 프로그램이 설정함.

시동 루틴은 커널로부터 여러 자료들(명령줄 인수들과 환경변수들)을 전달받고,
main()의 실행에 필요한 제반 사항 준비하고, main()가 반환되면 exit()를 호출함.

시동루틴을 C로 작성시(보통 어셈블러로 작성됨)
exit(main(argc, argv));


7.3 프로세스 종료



* 총 8가지의 종료 방식


1) main 함수의 반환
2) exit() 호출
3) _exit()나 Exit() 호출
4) 마지막 스레드를 시작한 스레드 시동 루틴의 반환
5) 마지막 스레드의 pthread_exit 호출

여기서부터는 비정상 종료

6) abort() 호출
7) signal 받음
8) 마지막 thread가 취소 요청에 반응함.(다른 쓰레드에게 pthread_cancel() 호출받음)



## 종료 함수



#include <stdlib.h>   -- ISO C 정의

void exit(int status);
void _Exit(int status);


# include <unistd.h>  -- POSIX.1 정의

void _exit(int status);



_Exit(), _exit()는 커널로 즉시 반환, exit()는 마무리 처리를 한 후에 커널로 반환


exit() 호출시 표준 I/O 라이브러리로 열린 모든 stream에 대해 fclose()를 호출하도록 수행됨.
이에 의해 버퍼에 남겨진 출력 자료가 모두 방출(파일에 기록)됨


int status 인수는 종료 상태(exit status)로 호칭

* 종료 상태(exit status)가 정의되지 않은 경우

1) 함수들이 종료 상태 없이 호출
2) 프로세스의 main함수가 반환값 없는 return 문에 의해 반환
3) main()가 정수를 돌려주도록 선언되지 않은 경우

main의 반환 형식이 int이고, main이 return문을 만나지 않고 마지막 코드에 도달해서 실행이 끝나면
프로세스 종료 상태(exit status)는 0이 됨. => 1999년 ISO C표준에 도입됨. 그 이전엔 종료 상태(exit status)가 정의되지 않음

main함수 종료시 아래 두 호출은 동일한 의미임.
exit(0);
return(0);
return 0;



## 고전적인 C 프로그램 예제



[wonsik@as48-x64 environ]$ cat hello1.c
#include        <stdio.h>

main()
{
        printf("hello, world\n");
}
[wonsik@as48-x64 environ]$ ./hello1
hello, world
[wonsik@as48-x64 environ]$ echo $?
13


* Solaris에서 수행

v20z:/home/wsalti] cc -o hello1 hello1.c
"hello1.c", line 4: warning: old-style declaration or incorrect type for: main
v20z:/home/wsalti] ./hello1
hello, world
v20z:/home/wsalti] echo $?
13

* HP-UX에서 수행

rx5670:[/home1/wsalti] $ cc -o hello1 hello1.c
rx5670:[/home1/wsalti] $ ./hello1
hello, world
rx5670:[/home1/wsalti] $ echo $?
0


프로그램을 컴파일하고, 실행한 후 종료 상태를 조사해보면 시스템마다 종료 상태가 무작위임.
동일한 시스템이라고 하더라도 main 함수가 반환될 당시의 스택 내용이나 레지스터 내용에 따라서도 다른 종료 상태가 나올 수 있음.



[wonsik@as48-x64 environ]$ cc -std=c99 -o hello1 hello1.c
hello1.c:4: warning: return type defaults to `int'
[wonsik@as48-x64 environ]$ ./hello1
hello, world
[wonsik@as48-x64 environ]$ echo $?
0

[wonsik@as48-x64 environ]$ cc -std=c99 -Wall -o hello1 hello1.c
hello1.c:4: warning: return type defaults to `int'
[wonsik@as48-x64 environ]$ gcc -std=c99 -Wall -o hello1 hello1.c
hello1.c:4: warning: return type defaults to `int'
[wonsik@as48-x64 environ]$ gcc  -Wall -o hello1 hello1.c
hello1.c:4: warning: return type defaults to `int'
hello1.c: In function `main':
hello1.c:6: warning: control reaches end of non-void function

-Wall 옵션 : 컴파일러가 제시하는 모든 경고가 표시되도록 하는 gcc 옵션
반환 형식이 void가 아닌 함수에서 return문을 만나지 않고 함수의 끝에 도달했음



## atexit 함수


종료 처리부(exit handler) -  프로세스가 exit 실행시 자동으로 호출될 함수, 최대 32개까지 등록 가능(ISO C에 정의되어 있음)
                             sysconf()를 이용해 주어진 플랫폼이 지원하는 최대 종료 처리부 개수 조회 가능함.

#include <stdlib.h>

int atexit(void(*func) (void));

반환값 : 성공시 0, 오류 시 0이 아닌 값

func 인수 : exit 함수에 의해 호출될 함수(어떠한 인수도 받지 않고, 어떠한 값도 반환하지 않은 함수)를 가리키는 포인터

1) 등록된 함수들을  등록된 순서의 역순으로 호출,
2) 하나의 함수를 여러 번 등록 가능하고 여러 번 호출 가능함



exit 함수는 종료 처리부들을 먼저 호출한 후에 open된 stream들을 모두 close 수행(fclose함수 호출) <= ISO C, POSIX.1에 명시
exec류 함수들(execl, execv, execle, execve, execlp, execvp)을 호출하는 경우 종료 처리부들이 모두 해제


* C 프로그램의 시작, 종료 방식 그림 상입



* 기억해야 할 것

1) 프로그램은 오직 커널이 exec류 함수들(execl, execv, execle, execve, execlp, execvp)중 하나를 호출함으로써 실행
2) 직접적 종료 - 프로세스가 자발적으로 _exit()나 _Exit 호출
3) 간접적 종료 - 프로세스가 자발적으로 exit() 호출
4) 비자발적 종료 - 외부로부터 signal 받을 때


* atexit 함수 용례



#include "../include/apue.h"

static void     my_exit1(void);
static void     my_exit2(void);

int
main(void)
{
        if (atexit(my_exit2) != 0)
                err_sys("can't register my_exit2");

        if (atexit(my_exit1) != 0)
                err_sys("can't register my_exit1");
        if (atexit(my_exit1) != 0)
                err_sys("can't register my_exit1");

        printf("main is done\n");
        return(0);
}

static void
my_exit1(void)
{
        printf("first exit handler\n");
}

static void
my_exit2(void)
{
        printf("second exit handler\n");
}


[wonsik@as48-x64 environ]$ ./doatexit
main is done
first exit handler
first exit handler
second exit handler


exit() 함수가 호출되지 않았는데, return 함수에 의해 내부적으로 호출됨.




7.4 명령줄 인수들


프로그램내에서 exec를 통해 다른 프로그램을 실행할 때, 명령줄 인수(arguement)들을 전달 가능함.
Unix shell을 수행할 때도 이런



* 명령줄 인수들을 모두 표준 출력 기록 예


#include "../include/apue.h"

int
main(int argc, char *argv[])
{
        int             i;

        for (i = 0; i < argc; i++)              /* echo all command-line args */
                printf("argv[%d]: %s\n", i, argv[i]);
        exit(0);
}



[wonsik@as48-x64 proc]$ ./echoarg wonsik is very handsome guy.
argv[0]: ./echoarg
argv[1]: wonsik
argv[2]: is
argv[3]: very
argv[4]: handsome
argv[5]: guy.



참고) ISO C와 POSIX.1 모두 argv[argc]가 반드시 null pointer임을 보장함.
    위 프로그램의 for문을 아래와 같이 변환 가능함.  
    for (i = 0; argv[i] != NULL; i++)




7.5 환경 목록


프로그램에 명령줄 인수(arguement)외에도 환경 변수 전달가능함.

APUE에서는 환경 변수들의 묶음을 환경 목록(environment list)라고 칭함


인수 목록 처럼 환경 목록도 문자 포인터들의 배열이고, 각 포인터는 null 종료 C 문자열의 주소를 포함.
포인터들의 배열 자체의 주소는 전역 변수 environ에 들어 있음



* 다섯 개의 C 문자열을 이루어진 환경 그림 삽입



envion 변수(environment pointer)에 접근하기 위해서는 getenv()와 putenv()를 사용하는 것이 일반적임.




7.6 C 프로그램의 메모리 구성



* 텍스트 구역(Text segment) 

 CPU가 실행하는 기계어 명령들을 담는 곳, 공유 가능함. 읽기 전용

* 초기화된 자료 구역(data segment) 

 명시적으로 초기화된 전역 변수 담는 곳
                    ex) int maxcount = 99;

* 초기화되지 않은 자료구역(일명 bss 구역, block started by symbol)

    프로그램 실행 전 커널에 의해 0 또는 null pointer로 초기화
    ex) int sum[1000];

* 스택(stack) 

 지역 변수와 함수 호출 정보 저장
    함수가 호출될 때마다 반환 주소 및 호출자의 환경에 대한 일정한 정보(CPU 몇몇 레지스터들 등)
    함수내 변수들에 대한 공간을 스택에서 할당함.

    함수의 재귀호출시 함수의 복사본이 stack 영역에 할당됨. 각 함수 복사본들의 지역변수들은 서로 겹치지 않음

* 힙(heap) 

 동적 메모리 할당이 주로 일어나는 곳
    bss영역과 stack 사이에 위치함.  





* 성긴 주소 공간

heap과 stack 사이의 공백(hole)도 가상 주소 공간의 일부임. 이 공백을 포함하는 가상 주소 공간을 성긴(sparse) 주소 공간이라고 함.
이 주소 공간은 stack이나 heap이 확장될때 사용되거나, 프로그램 실행 중 동적 라이브러리를 링크할 때 사용

Intel x86 프로세서상의 Linux 경우 text구역은 0x08048000에서 시작함. 스택의 하단은 0xC0000000 바로 아래임


프로그램의 실행파일에는 기호 테이블, 디버깅 정보, 동적 공유 라이브러리를 위한 링크 테이블등 다양한 종류의 구역들이 존재하지만
메모리에 적재하지 않음.
bss구역의 내용은 프로그램 실행 전 커널이 0이나 null pointer로 초기화하기 때문에 디스크상의 프로그램에 저장되지 않음
디스크에 저장될 필요가 있는 것은 text 구역과 data segment(초기화된 자료 구역)


[wonsik@as48-x64 bin]$ size altibase isql
   text    data     bss     dec     hex filename
25905719 432608 1448144 27786471  7fce7 altibase
9963100  123248   85496 10171844  b35c4 isql



7.7 공유 라이브러리

* 장점

1) 공유 라이브러리로 인해 실행파일의 크기를 줄일 수 있음.
    공통의 라이브러리 루틴들의 복사본 하나를 메모리에 둔 후 실행 파일에 그 루틴으로 연결하는 데 필요한 정보만 담아주면 됨.
2) 임의의 라이브러리가 갱신되었을 경우 그 라이브러리 함수를 사용하는 모든 프로그램을 link하지 않고도
    라이브러리를 새 버전으로 대체 가능함.(해당 함수의 인수 개수와 타입이 변경되지 않는다고 할때)

* 공유 라이브러리 사용 여부 설정

    컴파일시 static 옵션 지정

[wonsik@as48-x64 environ]$ cc -static -o hello1 hello1.c
[wonsik@as48-x64 environ]$ ls -ailtr hello1
58064910 -rwxr-xr-x  1 wonsik wsalti 519951 Dec 18 14:12 hello1
[wonsik@as48-x64 environ]$ size hello1
   text    data     bss     dec     hex filename
 456403    5768    9392  471563   7320b hello1
[wonsik@as48-x64 environ]$ cc -o hello1 hello1.c
[wonsik@as48-x64 environ]$ ls -ailtr hello1
58064910 -rwxr-xr-x  1 wonsik wsalti 6733 Dec 18 14:12 hello1
[wonsik@as48-x64 environ]$ size hello1
   text    data     bss     dec     hex filename
   1079     512       8    1599     63f hello1




7.8 메모리 할당


#include <stdlib.h>

void *malloc(size_t size);
void *calloc(size_t nobj, size_t size);
void *realloc(void *ptr, size_t newsize);

반환값 : 성공시 null 아닌 포인터, 오류시 NULL

void free(void *ptr);


malloc()은 지정된 개수의 바이트들을 할당함. 초기화하지 않음. 쓰레기값으로 채워짐
calloc()은 할당된 메모리를 0으로 초기화는 것외엔 malloc()과 동일함.
    nobj 인수는 할당할 블록의 개수 정보, size인수는 블록 하나당 byte 크기의 정보가 전달됨.
realloc은 이미 할당된 메모리 영역의 크기를 조절함.
    *ptr 인수는 이전에 할당된 동적 메모리 영역의 주소
    newsize는 반환되는 새로운 동적 메모리 영역의 크기(byte 수)
  



#include <stdio.h>
#include <string.h>
#include <malloc.h>
int main()
{
        char** inList = 0, buf[256];   /* 라인 배열로 사용할 변수와 버퍼 변수 선언 */
        int numin = 0, max_size = 0;   /* 라인 수와 라인 배열 값을 위한 메모리 할당 변수 선언 */

        /* get all input lines from a user */
        while (scanf("%s", buf) != -1)      /* 키보드로부터 문자열을 받아옴 */
        {
                if( ++numin > max_size ) {   /* 라인 수와 라인 배열 값의 크기 비교 */
                        max_size += 2;       /* 라인 수가 크면 라인 배열값을 2 증가 */
                        if(!inList)
                                inList = (char**)calloc( max_size, sizeof(char*));   /* 초기 라인 배열값이 정의되지 않았을 경우 메모리에 할당 */
                        else
                                inList = (char**)realloc(inList, sizeof(char*)*max_size);  /* 라인 배열 값을 재정의하여 메모리에 할당 */
                }
        /* store an input line */
        inList[numin-1] = (char*)malloc(strlen(buf)+1);   /* 라인 배열에 들어갈 값에 대한 메모리 설정 */
        strcpy(inList[numin-1], buf);       /* 버퍼의 내용을 라인 배열에 복사  */
        }

        /* now print back all input lines from a user */
        while ( --numin >= 0 )
        {
                printf("%d: %s \n", numin, inList[numin]);     /* 라인 배열 내용을 역순으로 출력 */
                free( inList[numin] );      /* 라인 배열에 할당된 메모리 삭제   */
        }
        free( inList );
        exit(0);
}


[wonsik@as48-x64 environ]$ ./mem_alloc
Hi
wonsik
this is mem alloc test
could you tell me about this program's result?
14: result?
13: program's
12: this
11: about
10: me
9: tell
8: you
7: could
6: test
5: alloc
4: mem
3: is
2: this
1: wonsik
0: Hi



malloc(), realloc(), calloc()과 메모리 할당관련 함수는 sbrk() 시스템 콜을 이용해 구현됨.


#include <unistd.h>
int brk(void *endds);
void *sbrk(int incrt);

반환값 : 정상 종료시 brk는 0 반환,  sbrk는 증가한 다음의 주소값 반환

호출 프로세스의 데이터 세그먼트를 위해 할당된 공간을 동적으로 변경,
프로세스의 break값(data segment의 가장 큰 가상 주소)의 재설정과 적절한 양의 공간 할당에 의해 이런 변경이 이루어짐.
브레이크 값은 데이터 세그먼트 끝의 다음에 있는 첫번째 위치의 주소

할당된 공간의 양은 break 값이 증가된 만큼 증가함.
새롭게 할당된 공간은 0으로 설정됨.

brk는 break 값을 endds로 설정하고 할당된 공간을 변경함.
sbrk는 break값에 incr byte를 더하고, 할당된 공간을 변경, 할당된 양을 줄이기 위해서 incr는 음수 사용 가능
     내부적으로 brk()를 호출함.

* kldp 사이트 malloc과 sbrk간의 관계 설명

malloc을 부르면 system library가 알아서 sbrk를 불러서 넉넉하게 받아놓은 다음,
차후 malloc이 들어올 때마다 미리 받아온 공간에서 잘라줍니다.
따라서 malloc으로 받아온 영역의 끝부분과 커널이 sbrk로 준 영역의 끝부분은 일반적으로 일치하지 않습니다.

그렇게 안 하면 malloc을 한번 부를 때마다 kernel system call을 부르는 오버헤드가 생기겠죠.



[wonsik@as48-x64 environ]$ cat brk.c
#include <stdio.h>
#include <unistd.h>

extern int etext, edata, end;    /* 프로세스 영역을 나타내는 외부 변수 선언 */

int main()
{
        int brk(), ret;
        void *sbrk();
        char *bv;

        system("clear");

    /* text, data 영역의 가상 주소 출력 */
        printf("The program text ends at %07o\n", &etext);
        printf("The initialized data ends at %07o\n", &edata);
        printf("The uninitialized data(bss) ends at %07o\n", &end);

        bv = sbrk(0);   /* 현재 brk의 물리적 주소값 , 현재 데이터 세그멘트의 마지막 포인터 */
        printf("Current break value is %07o\n\n", bv);

        ret = brk(bv+512);    /* 512는 8진수로 1000 */
        printf("brk returned .... %d\n", ret);
        bv=sbrk(0);
        printf("Current break value is %07o\n\n", bv);

        ret = brk(&ret);     /* break값을 ret변수 주소값(stack영역의 주소)으로 설정 */
        printf("brk returned .... %d\n", ret);
        bv = sbrk(0);
        printf("Current break value is %07o\n\n", bv);

        bv = sbrk(64);      /* 64는 8진수 100, break값을 64만큼 증가  */
        printf("sbrk returned %07o\n", bv);
        bv = sbrk(0);
        printf("Current break value is %07o\n\n", bv);

        bv = sbrk(-1024);    /* 메모리를 2000(8진수) 만큼 줄인 */
        printf("sbrk returned %07o\n", bv);
        printf("Current break value is %07o\n\n", bv);

        exit(0);
}


The program text ends at 20004026
The initialized data ends at 24005700
The uninitialized data(bss) ends at 24005710
Current break value is 24010000

brk returned .... 0
Current break value is 24011000

brk returned .... -1
Current break value is 24011000

sbrk returned 24011000
Current break value is 24011100

sbrk returned 24011100
Current break value is 24011100


* 대안적인 메모리 할당자들


libmalloc, vmalloc, quick-fit, alloca(stack 영역에 할당함, 함수 반환시 자동으로 해제)

* vmalloc()

http://egloos.zum.com/embedded21/v/530514


* quick-fit Memory allocation algorithm

The Quick Fit algorithm (LIB$K_VM_QUICK_FIT) maintains a set of lookaside lists indexed by request size for request sizes in a specified range. For request sizes that are not in the specified range, a First Fit list of free blocks is maintained. An allocation request is satisfied by removing a block from the appropriate lookaside list; if the lookaside list is empty, a First Fit allocation is done. When a block is freed, it is placed on either a lookaside list or the First Fit list according to its size.
Free blocks that are placed on a lookaside list are neither merged with adjacent free blocks nor split to satisfy a request for a smaller block.




7.9 환경 변수


UNIX 커널이 환경 변수 문자열을 직접 참조하는 경우는 결코 없음.
환경 변수 문자열을 해석해서 적절한 값을 얻고 사용하는 것은 전적으로 application 몫임.

ex) unix 로그인시 HOME과 USER와 같은 환경 변수 자동 설정되나, 그 외의 환경변수들은 사용자가 설정하기 나름


* ISO C 표준에 정의된 환경 변수 값 가져오는 함수


#include <stdlib.h>

char *getenv(const char *name);
반환값 : name으로 주어진 이름에 해당하는 환경 변수 값을 가리키는 포인터
    환경 변수 이름이 없는 경우 Null 반환

예제 )
#include <stdlib.h>

#include <stdio.h>

int main(int argc, char **argv)
{
    char *value;
    value = getenv(argv[1]);

    if (value != NULL)
    {
        printf("%s=%s\n", argv[1], value);
    }

    return 0;
}
[wonsik@as48-x64 environ]$ cc -o getenv getenv.c
[wonsik@as48-x64 environ]$ ./getenv ALTIBASE_HOME
ALTIBASE_HOME=/home/wonsik/altibase_home
[wonsik@as48-x64 environ]$ ./getenv PATH
PATH=/home/wonsik/altibase_home/bin:/home/wonsik/hbase/bin:/home/wonsik/zookeeper/bin:/home/wonsik/hive/bin:/home/wonsik/pig/bin:/home/wonsik/hadoop/bin:/usr/java/jdk1.6.0_30/bin:/usr/lib64/qt-3.3/bin:/usr/kerberos/bin:/usr/java/jdk1.6.0_30/jre/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/usr/sbin:/usr/bin:/home/asadal3/altibase_client/bin:/home/wonsik/bin
[wonsik@as48-x64 environ]$ ./getenv JAVA_HOME
JAVA_HOME=/usr/java/jdk1.6.0_30


예제) 자신의 쉘 환경에서 설정된 환경 변수 모두를 출력하고, 환경 변수 TZ(Time Zone)을 변경한 후 변경된 내용을 출력하여 확인, 그리고 새 환경변수 WARNING 값 설정 후 그 내용 출력하는 프로그램

[wonsik@as48-x64 environ]$ cat getenv2.c
#include <stdlib.h>
#include <stdio.h>

extern char **environ;  /* environment variables들이 저장된 테이블의 시작 주소 */

main(int argc,char **argv,char **envp)   /* envp는 여러 개의 string들이 저장된 테이블 주소 */
{
        char *getenv();

        printenv("initially", &envp);
        putenv("TZ=PST8PDT");
        printenv("After changing TZ", &envp);
        putenv("WARNING=Don't use envp after putenv()");
        printenv("After setting a new variable", &envp);
        printf("value of WARNING is %s\n", getenv("WARNING"));

        exit(0);
}

printenv(char *label, char ***envpp)
{
        char **p;

        printf("---- %s ---\n", label);
        printf(" envp is at %8o and contains %8o\n", envpp, *envpp);
        printf("environ is at %8o and contains %8o\n", &environ, environ);
        printf("My environment variables are:\n");
        for(p=environ; *p; p++)
                printf("(%8o) = %8o -> %s\n", p,*p,*p);
        printf(" (%8o) = %8o\n", p, *p);
}


[wonsik@as48-x64 environ]$ ./getenv2
---- initially ---
 envp is at 27777772250 and contains 27777772650
environ is at 24006110 and contains 27777772650
My environment variables are:
(27777772650) = 27777774007 -> HOSTNAME=as48-x64
(27777772660) = 27777774031 -> PIG_HOME=/home/wonsik/pig
(27777772670) = 27777774063 -> TERM=vt100
(27777772700) = 27777774076 -> SHELL=/bin/bash
(27777772710) = 27777774116 -> HADOOP_HOME=/home/wonsik/hadoop
(27777772720) = 27777774156 -> HISTSIZE=1000
(27777772730) = 27777774174 -> SSH_CLIENT=::ffff:192.168.6.26 1619 22
(27777772740) = 27777774243 -> QTDIR=/usr/lib64/qt-3.3
(27777772750) = 27777774273 -> QTINC=/usr/lib64/qt-3.3/include
(27777772760) = 27777774333 -> SSH_TTY=/dev/pts/11
(27777772770) = 27777774357 -> USER=wonsik
(27777773000) = 27777774373 -> LD_LIBRARY_PATH=/usr/java/jdk1.6.0_30/lib:/home/wonsik/altibase_home/lib:
(27777773010) = 27777774505 -> LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.sh=01;32:*.csh=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tz=01;31:*.rpm=01;31:*.cpio=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:
(27777773020) = 27777775410 -> HBASE_HOME=/home/wonsik/hbase
(27777773030) = 27777775446 -> SSH_AUTH_SOCK=/tmp/ssh-ksaZY18031/agent.18031
(27777773040) = 27777775524 -> KDEDIR=/usr
(27777773050) = 27777775540 -> ALTIBASE_PORT_NO=40501
(27777773060) = 27777775567 -> MAIL=/var/spool/mail/wonsik
(27777773070) = 27777775623 -> PATH=/home/wonsik/altibase_home/bin:/home/wonsik/hbase/bin:/home/wonsik/zookeeper/bin:/home/wonsik/hive/bin:/home/wonsik/pig/bin:/home/wonsik/hadoop/bin:/usr/java/jdk1.6.0_30/bin:/usr/lib64/qt-3.3/bin:/usr/kerberos/bin:/usr/java/jdk1.6.0_30/jre/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/usr/sbin:/usr/bin:/home/asadal3/altibase_client/bin:/home/wonsik/bin
(27777773100) = 27777776376 -> HIVE_HOME=/home/wonsik/hive
(27777773110) = 27777776432 -> INPUTRC=/etc/inputrc
(27777773120) = 27777776457 -> PWD=/home/wonsik/apue/environ
(27777773130) = 27777776515 -> JAVA_HOME=/usr/java/jdk1.6.0_30
(27777773140) = 27777776555 -> HADOOP_CONF_DIR=/home/wonsik/hadoop/conf
(27777773150) = 27777776626 -> PIG_CLASSPATH=/home/wonsik/hadoop/conf
(27777773160) = 27777776675 -> LANG=en_US.UTF-8
(27777773170) = 27777776716 -> ZOOKEEPER_HOME=/home/wonsik/zookeeper
(27777773200) = 27777776764 -> ALTIBASE_NLS_USE=MS949
(27777773210) = 27777777013 -> SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass
(27777773220) = 27777777076 -> SHLVL=1
(27777773230) = 27777777106 -> HOME=/home/wonsik
(27777773240) = 27777777130 -> LOGNAME=wonsik
(27777773250) = 27777777147 -> QTLIB=/usr/lib64/qt-3.3/lib
(27777773260) = 27777777203 -> CLASSPATH=/usr/java/jdk1.6.0_30/jre/lib:/usr/java/jdk1.6.0_30/lib/tools.jar:/home/wonsik/altibase_home/lib/Altibase.jar:/home/wonsik/altibase_home/lib/Altibase5.jar:.
(27777773270) = 27777777452 -> SSH_CONNECTION=::ffff:192.168.6.26 1619 ::ffff:192.168.1.35 22
(27777773300) = 27777777551 -> LESSOPEN=|/usr/bin/lesspipe.sh %s
(27777773310) = 27777777613 -> ALTIBASE_HOME=/home/wonsik/altibase_home
(27777773320) = 27777777664 -> G_BROKEN_FILENAMES=1
(27777773330) = 27777777711 -> _=./getenv2
(27777773340) = 27777777725 -> OLDPWD=/home/wonsik/apue
 (27777773350) =        0
---- After changing TZ ---
 envp is at 27777772250 and contains 27777772650
environ is at 24006110 and contains 24010020
My environment variables are:
(24010020) = 27777774007 -> HOSTNAME=as48-x64
(24010030) = 27777774031 -> PIG_HOME=/home/wonsik/pig
(24010040) = 27777774063 -> TERM=vt100
(24010050) = 27777774076 -> SHELL=/bin/bash
(24010060) = 27777774116 -> HADOOP_HOME=/home/wonsik/hadoop
(24010070) = 27777774156 -> HISTSIZE=1000
(24010100) = 27777774174 -> SSH_CLIENT=::ffff:192.168.6.26 1619 22
(24010110) = 27777774243 -> QTDIR=/usr/lib64/qt-3.3
(24010120) = 27777774273 -> QTINC=/usr/lib64/qt-3.3/include
(24010130) = 27777774333 -> SSH_TTY=/dev/pts/11
(24010140) = 27777774357 -> USER=wonsik
(24010150) = 27777774373 -> LD_LIBRARY_PATH=/usr/java/jdk1.6.0_30/lib:/home/wonsik/altibase_home/lib:
(24010160) = 27777774505 -> LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.sh=01;32:*.csh=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tz=01;31:*.rpm=01;31:*.cpio=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:
(24010170) = 27777775410 -> HBASE_HOME=/home/wonsik/hbase
(24010200) = 27777775446 -> SSH_AUTH_SOCK=/tmp/ssh-ksaZY18031/agent.18031
(24010210) = 27777775524 -> KDEDIR=/usr
(24010220) = 27777775540 -> ALTIBASE_PORT_NO=40501
(24010230) = 27777775567 -> MAIL=/var/spool/mail/wonsik
(24010240) = 27777775623 -> PATH=/home/wonsik/altibase_home/bin:/home/wonsik/hbase/bin:/home/wonsik/zookeeper/bin:/home/wonsik/hive/bin:/home/wonsik/pig/bin:/home/wonsik/hadoop/bin:/usr/java/jdk1.6.0_30/bin:/usr/lib64/qt-3.3/bin:/usr/kerberos/bin:/usr/java/jdk1.6.0_30/jre/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/usr/sbin:/usr/bin:/home/asadal3/altibase_client/bin:/home/wonsik/bin
(24010250) = 27777776376 -> HIVE_HOME=/home/wonsik/hive
(24010260) = 27777776432 -> INPUTRC=/etc/inputrc
(24010270) = 27777776457 -> PWD=/home/wonsik/apue/environ
(24010300) = 27777776515 -> JAVA_HOME=/usr/java/jdk1.6.0_30
(24010310) = 27777776555 -> HADOOP_CONF_DIR=/home/wonsik/hadoop/conf
(24010320) = 27777776626 -> PIG_CLASSPATH=/home/wonsik/hadoop/conf
(24010330) = 27777776675 -> LANG=en_US.UTF-8
(24010340) = 27777776716 -> ZOOKEEPER_HOME=/home/wonsik/zookeeper
(24010350) = 27777776764 -> ALTIBASE_NLS_USE=MS949
(24010360) = 27777777013 -> SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass
(24010370) = 27777777076 -> SHLVL=1
(24010400) = 27777777106 -> HOME=/home/wonsik
(24010410) = 27777777130 -> LOGNAME=wonsik
(24010420) = 27777777147 -> QTLIB=/usr/lib64/qt-3.3/lib
(24010430) = 27777777203 -> CLASSPATH=/usr/java/jdk1.6.0_30/jre/lib:/usr/java/jdk1.6.0_30/lib/tools.jar:/home/wonsik/altibase_home/lib/Altibase.jar:/home/wonsik/altibase_home/lib/Altibase5.jar:.
(24010440) = 27777777452 -> SSH_CONNECTION=::ffff:192.168.6.26 1619 ::ffff:192.168.1.35 22
(24010450) = 27777777551 -> LESSOPEN=|/usr/bin/lesspipe.sh %s
(24010460) = 27777777613 -> ALTIBASE_HOME=/home/wonsik/altibase_home
(24010470) = 27777777664 -> G_BROKEN_FILENAMES=1
(24010500) = 27777777711 -> _=./getenv2
(24010510) = 27777777725 -> OLDPWD=/home/wonsik/apue
(24010520) = 20004052 -> TZ=PST8PDT
 (24010530) =        0
---- After setting a new variable ---
 envp is at 27777772250 and contains 27777772650
environ is at 24006110 and contains 24010020
My environment variables are:
(24010020) = 27777774007 -> HOSTNAME=as48-x64
(24010030) = 27777774031 -> PIG_HOME=/home/wonsik/pig
(24010040) = 27777774063 -> TERM=vt100
(24010050) = 27777774076 -> SHELL=/bin/bash
(24010060) = 27777774116 -> HADOOP_HOME=/home/wonsik/hadoop
(24010070) = 27777774156 -> HISTSIZE=1000
(24010100) = 27777774174 -> SSH_CLIENT=::ffff:192.168.6.26 1619 22
(24010110) = 27777774243 -> QTDIR=/usr/lib64/qt-3.3
(24010120) = 27777774273 -> QTINC=/usr/lib64/qt-3.3/include
(24010130) = 27777774333 -> SSH_TTY=/dev/pts/11
(24010140) = 27777774357 -> USER=wonsik
(24010150) = 27777774373 -> LD_LIBRARY_PATH=/usr/java/jdk1.6.0_30/lib:/home/wonsik/altibase_home/lib:
(24010160) = 27777774505 -> LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.sh=01;32:*.csh=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tz=01;31:*.rpm=01;31:*.cpio=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:
(24010170) = 27777775410 -> HBASE_HOME=/home/wonsik/hbase
(24010200) = 27777775446 -> SSH_AUTH_SOCK=/tmp/ssh-ksaZY18031/agent.18031
(24010210) = 27777775524 -> KDEDIR=/usr
(24010220) = 27777775540 -> ALTIBASE_PORT_NO=40501
(24010230) = 27777775567 -> MAIL=/var/spool/mail/wonsik
(24010240) = 27777775623 -> PATH=/home/wonsik/altibase_home/bin:/home/wonsik/hbase/bin:/home/wonsik/zookeeper/bin:/home/wonsik/hive/bin:/home/wonsik/pig/bin:/home/wonsik/hadoop/bin:/usr/java/jdk1.6.0_30/bin:/usr/lib64/qt-3.3/bin:/usr/kerberos/bin:/usr/java/jdk1.6.0_30/jre/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/usr/sbin:/usr/bin:/home/asadal3/altibase_client/bin:/home/wonsik/bin
(24010250) = 27777776376 -> HIVE_HOME=/home/wonsik/hive
(24010260) = 27777776432 -> INPUTRC=/etc/inputrc
(24010270) = 27777776457 -> PWD=/home/wonsik/apue/environ
(24010300) = 27777776515 -> JAVA_HOME=/usr/java/jdk1.6.0_30
(24010310) = 27777776555 -> HADOOP_CONF_DIR=/home/wonsik/hadoop/conf
(24010320) = 27777776626 -> PIG_CLASSPATH=/home/wonsik/hadoop/conf
(24010330) = 27777776675 -> LANG=en_US.UTF-8
(24010340) = 27777776716 -> ZOOKEEPER_HOME=/home/wonsik/zookeeper
(24010350) = 27777776764 -> ALTIBASE_NLS_USE=MS949
(24010360) = 27777777013 -> SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass
(24010370) = 27777777076 -> SHLVL=1
(24010400) = 27777777106 -> HOME=/home/wonsik
(24010410) = 27777777130 -> LOGNAME=wonsik
(24010420) = 27777777147 -> QTLIB=/usr/lib64/qt-3.3/lib
(24010430) = 27777777203 -> CLASSPATH=/usr/java/jdk1.6.0_30/jre/lib:/usr/java/jdk1.6.0_30/lib/tools.jar:/home/wonsik/altibase_home/lib/Altibase.jar:/home/wonsik/altibase_home/lib/Altibase5.jar:.
(24010440) = 27777777452 -> SSH_CONNECTION=::ffff:192.168.6.26 1619 ::ffff:192.168.1.35 22
(24010450) = 27777777551 -> LESSOPEN=|/usr/bin/lesspipe.sh %s
(24010460) = 27777777613 -> ALTIBASE_HOME=/home/wonsik/altibase_home
(24010470) = 27777777664 -> G_BROKEN_FILENAMES=1
(24010500) = 27777777711 -> _=./getenv2
(24010510) = 27777777725 -> OLDPWD=/home/wonsik/apue
(24010520) = 20004052 -> TZ=PST8PDT
(24010530) = 20004110 -> WARNING=Don't use envp after putenv()
 (24010540) =        0
value of WARNING is Don't use envp after putenv()


* 단일 UNIX 규격에 정의되어 있는 환경 변수들(ISO C 표준은 어떠한 환경 변수도 정의하지 않음)






* 여러 환경 목록 함수들의 지원 여부




현재 프로세스가 추가 및 변경한 환경 변수는 해당 프로세스와 그 자식 프로세스들에만 적용됨.


* putenv 함수



#include <stdlib.h>

int putenv(char *str);
반환값: 성공시 0, 오류시 0이 아닌값

변수이름=값 형태의 문자열을 받아서 환경 목록에 포함시킴.
해당 변수가 이미 존재한다면 새로운 값으로 대체함


* 환경 변수 설정 관련 함수



#incldue <stdlib.h>

int setenv(const char *name, const char *value, int rewrite);
int unsetenv(const char *name);

반환값(둘 다); 성공 시 0, 오류시 -1

setenv 함수 - name으로 주어진 이름의 환경 변수의 값을 value로 설정
이미 존재하는 경우 rewrite 인수 값에 따라 달라짐
rewrite가 0일 경우 name에 해당하는 기존 이름의 정의대로 남겨짐. 이 경우 오류(-1)을 반환하지 않음
rewrite가 0이 아닐 경우 name에 해당하는 기존 이름의 정의가 먼저 삭제됨


unsetenv 함수 - name에 해당하는 정의 들을 모두 삭제



#include <unistd.h>

int main()
{
    setenv("TEST", "YUNDREAM", 1);
    execl("/bin/bash", "bash", NULL);
}

[wonsik@as48-x64 environ]$ ./setenv
[wonsik@as48-x64 environ]$ echo $TEST
YUNDREAM
[wonsik@as48-x64 environ]$ echo $SHLVL
2
[wonsik@as48-x64 environ]$ exit
exit
[wonsik@as48-x64 environ]$ echo $SHLVL
1
[wonsik@as48-x64 environ]$ exit

* setenv()와 putenv()의 차이


setenv()는 반드시 메모리를 할당해서 변수이름=값 문자열을 저장해야 함.
putenv()는 주어진 문자열의 주소를 환경 목록에 직접 집어넣는 형태로 구현 가능함.



* 환경 목록이 수정되는 방식


1) 기존 이름을 수정하는 경우
    a. 새 값의 크기가 기존 값의 크기 이하이면 그냥 새 값을 기존 값에 overwrite
    b. 새 값의 크기가 기존 값의 크기보다 크다면 새 환경 문자열을 담을 공간을 malloc으로 할당,
       새 문자열을 그 곳에 복사하고, 환경 목록에서 기존 이름을 가리키던 포인터를 새로 할당된 영역을 가리키는 포인터로 대체

2) 새로운 이름을 추가하는 경우 우선적으로 malloc()을 이용해 '변수이름=값' 문자열을 담을 공간을 할당해야 함
    a. 환경 목록(포인터들의 목록)에 변수이름을 처음으로 추가하는 경우
        환경 변수 문자열을 가리키는 새로운 포인터가 추가된 환경 목록를 담기 위한 공간을 malloc()으로 할당
        =>  MALLOC된 공간에 기존 환경 목록을 복사하고, 목록 끝에 새로운 변수이름=값 문자열을 가리키는 포인터를 추가함.
        =>  목록 끝에 NULL POINTER 저장
        =>  environ 변수(envrionment pointer)가 해당 환경 목록을 가르키도록 변경

기본적으로 환경목록은 stack영역에 생성되나, 위의 과정을 거치게 되면 환경 목록은 heap 영역으로 옮겨지게 됨.
그러나, 환경 목록에 담긴 대부분 포인터들은 stack 위쪽의 '변수이름=값' 문자열을 가리키고 있는 상황

    b. 처음으로 추가하는 경우가 아니라면, 환경 목록은 이미 heap 영역에 할당되어 있기 때문에 realloc()를 이용해 포인터를 추가할 공간 마련





7.10 setjmp함수와 longjmp 함수

goto문은 함수내에서 다른 소스코드로 분기하는데 사용하는 반면,
setjmp()와 longjmp()는 함수 경계를 넘나드는 분기를 수행

사용자가 interrupt를 발생시면 프로그램을 이전의 상태로 복구해야 할때 주로 사용됨.

setjmp()는 프로그램의 현재 상태를 저장(stack 영역에 jmp_buf type의 env인수에 저장), longjmp는 저장된 상태를 다시 복구함.(env인수로 복구)


#include <setjmp.h>

int setjmp(jmp_buf env);
    반환값: 직접 호출된 경우에는 0, longjmp를 통해서 호출된 경우에는 0이 아닌 값
void longjmp(jmp_buf env, int val);


* jmp_buf타입 인수 관련

    스택 상태를 나중에 longjmp가 호출되었을 때의 스택 상태로 되돌리는 데 필요한 모든 정보를 담는 일종의 배열


# if __WORDSIZE == 64
typedef long int __jmp_buf[8];
# else
typedef int __jmp_buf[6];
# endif



#include <signal.h>
#include <setjmp.h>
jmp_buf env1;

main(int argc, char *argv[])
{
    int retcode, setjmp()
    void ljmain();

    signal(SIGINT, ljmain);
    retcode = setjmp(env1);   /* 분기에 필요한 정보를 jmpbuffer에 기록후 0 반환 */
    if(retcode != 0 )
        printf("\nBefore loop\n");

    while(1) menu();
}

menu() {
    char resp[2];
    prompt: printf("cmd: ");
    scanf("%s", resp);
    switch(resp[0])
    {
        case 's' : sfn(); break;
        case 't' : tfn(); break;
        case 'q' : exit(0);
        default: println("?\n"); goto prompt;
    }
    exit(0);
}

void ljmain()
{
    void longjmp();
    signal(SIGINT, ljmain);
    printf("\nINTERRUPTED\n");
    longjmp(env1, 1);
}

sfn()
{
    int i, j=0;
    for(i=0; ;i++) {
        printf("%d\t", i*i);
        if(++j %8 ==0)
            printf("\n");
    }
}

tfn()
{
    long now, time();
    char *ctime();

    (void) time(&now);
    printf("%s", ctime(&now));
}

[wonsik@as48-x64 environ]$ ./setjmp
cmd: s
0       1       4       9       16      25      36      49
64      81      100     121     144     169     196     225
256     289     324     361     400     441     484     529



INTERRUPTED

Before loop
cmd:


longjmp가 호출되면 sfn(), tfn(), menu()에 대한 스택프레임이 제거됨.(이를 스택이 풀린다라고 함)



* longjmp()가 호출되기 전 스택 프레임



* longjmp()가 호출된 후의 스택 프레임



* 자동(지역) 변수, 레지스터 변수, 휘발성 변수


#include "../include/apue.h"
#include <setjmp.h>

static void     f1(int, int, int, int);
static void     f2(void);

static jmp_buf  jmpbuffer;
static int              globval;

int
main(void)
{
        int                             autoval;
        register int    regival;
        volatile int    volaval;
        static int              statval;

        globval = 1; autoval = 2; regival = 3; volaval = 4; statval = 5;


        if (setjmp(jmpbuffer) != 0) {
                printf("after longjmp:\n");
                printf("globval = %d, autoval = %d, regival = %d,"
                    " volaval = %d, statval = %d\n",
                    globval, autoval, regival, volaval, statval);
                exit(0);
        }

        /*
         * Change variables after setjmp, but before longjmp.
         */
        globval = 95; autoval = 96; regival = 97; volaval = 98;
        statval = 99;

        f1(autoval, regival, volaval, statval); /* never returns */
        exit(0);
}

static void
f1(int i, int j, int k, int l)
{
        printf("in f1():\n");
        printf("globval = %d, autoval = %d, regival = %d,"
            " volaval = %d, statval = %d\n", globval, i, j, k, l);
        f2();
}

static void
f2(void)
{
        longjmp(jmpbuffer, 1);
}

[wonsik@as48-x64 environ]$ ./testjmp
in f1():
globval = 95, autoval = 96, regival = 97, volaval = 98, statval = 99
after longjmp:
globval = 95, autoval = 96, regival = 97, volaval = 98, statval = 99


* -O 옵션(완전한 최적화) 적용하여 compile시

[wonsik@as48-x64 environ]$ ./testjmp
in f1():
globval = 95, autoval = 96, regival = 97, volaval = 98, statval = 99
after longjmp:
globval = 95, autoval = 2, regival = 3, volaval = 98, statval = 99



C 컴파일시 최적화 옵션을 O로 설정하면 지역변수와 register 변수의 값이 변함.
=> 최적화 옵션을 끄면 위 5개 변수는 모두 메모리에 저장되지만, 최적화 옵션을 키면
지역 변수 및 resister 변수는 CPU register 영역에 들어감.volatile 변수는 메모리에 유지


7.11 getrlimit 함수와 setrlimit 함수


#include <sys/resource.h>

int getrlimit(int resource, struct rlimit *rlptr);
int setrlimit(int resource, const struct rlimit *rlptr);

반환값 : 성공 시 0, 오류 시 0이 아닌 값

보통의 경우 자원 한계들은 시스템 초기화 시점에서 0 번 프로세스가 설정하며, 이후의 프로세스들은 그 자원 한계들을 물려받음



* rlimit 구조체


struct rlimit {
    rlim_t rlim_cur;    /* soft limit : 현재의 한계 */
    rlim_t rlim_max;    /* hard limit : rlim_cur의 최대값 */
}

#ifndef __USE_FILE_OFFSET64
typedef __rlim_t rlim_t;
#else
typedef __rlim64_t rlim_t;
#endif
#ifdef __USE_LARGEFILE64
typedef __rlim64_t rlim64_t;
#endif

__STD_TYPE __RLIM_T_TYPE __rlim_t;      /* Type for resource measurement.  */

#define __RLIM_T_TYPE           __ULONGWORD_TYPE

* 자원 한계 변경 규칙


1) 프로세스는 자신의 soft limit을 hard limit보다 작거나 같은 값으로만 변경 가능
2) 프로세스는 자신의 hard limit을 soft limit보다 크거나 같은 값으로만 낮출 수 있음
    일반 사용자는 hard limit을 내릴 수만 있고, 올릴 수 없음
3) super user만이 hard limit 올릴 수 있음


한계의 값이 무한대인 경우 RLIM_INFINITY 상수 사용



* resource 인수로 들어올 수 있는 자원 한계 값









                            
RESOURCE 인수
설명
RLIMIT_AS
한 프로세스의 총 가용 메모리 용량의 최대값(byte 단위), sbrk(), mmap()에 영향
RLIMIT_CORE
corefile의 최대 크기(byte 단위), 0이면 core file 생성 안됨
RLIMIT_CPU
프로세스가 소비할 수 있는 최대 CPU time( sec ), soft limit을 초과하면 SIGXCPU signal 전송
RLIMIT_DATA
data segment 전체( 초괴된 영역, bss영역, heap까지 포함)의 최대 크기(byte 단위)
RLIMIT_FSIZE
파일 생성시 파일의 최대 크기(byte 단위), soft limit을 초과하면 SIGXFSZ signal 전송
RLIMIT_LOCKS
프로세스가 소유할 수 있는 file lock 최대 개수
RLIMIT_MEMLOCK
한 프로세스가 mlock()으로 잠글 수 있는 메모리의 최대 용량(byte 단위)
RLIMIT_NOFILE
한 프로세스가 열 수 있는 최대 파일 개수, sysconf() __SC_OPEN_MAX인자 설정시 반환값에 영향
RLIMIT_NPROC
실제 user id당 최대 자식 프로세스 개수, sysconf() __SC_CHILD_MAX인자 설정시 반환값에 영향
RLIMIT_RSS
프로세스의 rss(resident set size)의 최대값(byte), 가용 물리 메모리가 낮을 때, 커널은 프로세스의 메모리에서 rss를 초과한 크기만큼 빼앗음
RLIMIT_SBSIZE
한 사용자가 한 시점에서 사용할 수 있는 소켓 버퍼들의 최대 크기(byte 단위)
RLIMIT_STACK
stack의 최대 크기(byte 단위)
RLIMIT_VMEM
RLIMIT_AS와 동일함.



자원 한계 변경시 부모 프로세스에는 영향을 미치지 않고, 자기 자신 및 하위 프로세스에 영향을 미침



* 현재 자원 한계들을 출력하는 프로그램


[wonsik@as48-x64 environ]$ cat getrlimit.c
#include "../include/apue.h"
#if defined(BSD) || defined(MACOS)
#include <sys/time.h>
#define FMT     "%10lld  "
#else
#define FMT     "%10ld  "
#endif
#include <sys/resource.h>

#define doit(name)      pr_limits(#name, name)

static void     pr_limits(char *, int);

int
main(void)
{
#ifdef  RLIMIT_AS
        doit(RLIMIT_AS);
#endif
        doit(RLIMIT_CORE);
        doit(RLIMIT_CPU);
        doit(RLIMIT_DATA);
        doit(RLIMIT_FSIZE);
#ifdef  RLIMIT_LOCKS
        doit(RLIMIT_LOCKS);
#endif
#ifdef  RLIMIT_MEMLOCK
        doit(RLIMIT_MEMLOCK);
#endif
        doit(RLIMIT_NOFILE);
#ifdef  RLIMIT_NPROC
        doit(RLIMIT_NPROC);
#endif
#ifdef  RLIMIT_RSS
        doit(RLIMIT_RSS);
#endif
#ifdef  RLIMIT_SBSIZE
        doit(RLIMIT_SBSIZE);
#endif
        doit(RLIMIT_STACK);
#ifdef  RLIMIT_VMEM
        doit(RLIMIT_VMEM);
#endif
        exit(0);
}

static void
pr_limits(char *name, int resource)
{
        struct rlimit   limit;

        if (getrlimit(resource, &limit) < 0)
                err_sys("getrlimit error for %s", name);
        printf("%-14s  ", name);
        if (limit.rlim_cur == RLIM_INFINITY)
                printf("(infinite)  ");
        else
                printf(FMT, limit.rlim_cur);
        if (limit.rlim_max == RLIM_INFINITY)
                printf("(infinite)");
        else
                printf(FMT, limit.rlim_max);
        putchar((int)'\n');
}
[wonsik@as48-x64 environ]$ ./getrlimit
RLIMIT_AS       (infinite)  (infinite)
RLIMIT_CORE              0  (infinite)
RLIMIT_CPU      (infinite)  (infinite)
RLIMIT_DATA     (infinite)  (infinite)
RLIMIT_FSIZE    (infinite)  (infinite)
RLIMIT_LOCKS    (infinite)  (infinite)
RLIMIT_MEMLOCK       32768       32768
RLIMIT_NOFILE      1048576     1048576
RLIMIT_NPROC        143360      143360
RLIMIT_RSS      (infinite)  (infinite)
RLIMIT_STACK      10485760  (infinite)
[wonsik@as48-x64 environ]$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
file size               (blocks, -f) unlimited
pending signals                 (-i) 1024
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1048576
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 143360
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited