mmap 관련 질문입니다

ixevexi의 이미지

#include<unistd.h>
#include<stdio.h>
#include<sys/mman.h>
#include<fcntl.h>
#include<sys/stat.h>

int main(int argc, char **argv)
{
    int * a;
    int rc = open ( "mmap.obj", O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);

    char * maped = mmap(0,sizeof(int)*100,PROT_READ|PROT_WRITE,MAP_PRIVATE,rc,0);
    printf("address:%d\n",maped);
    a = (int*)maped);
    printf("%c\n",(*a)++);
    printf("%c\n",(*a)++);

    rc = msync(maped,sizeof(int)*100,MS_SYNC);
    printf("%d\n",rc);
    return 0;
}

단순히 파일을 읽어들여 메모리로 맵핑시키고
그것을 파일과 동기화 시키는 용도로 mmap을 쓰려고 합니다
그런데 man에도 안나와있고 제가 원하는 동작이랑 달라서
한번 여쭤 봅니다.

1. 저위에 mmap.obj란 파일을 생성시키는데요
이 파일의 크기가 mmap에서의 size보다 작으면,
버스 오류가 생기더라구요
정확히 이야기하면 파일 생성직후 0바이트일때 읽으려 들면
버스오류가 생깁니다. 그래서 mmap.obj를 손으로 열고
데이타를 써 넣어주니 정상 작동을 합니다.
항상 mmap에서 할당하는 크기보다 파일의 크기가 커야합니까?

2. 두번째로 저 것을 컴파일 후 실행시켰는데요
다음과 같은 결과가 나옵니다.

ixevexi@kali8:~/test$ ./a.out
address:1073840128
a
b
0
ixevexi@kali8:~/test$ ./a.out
address:1073840128
a
b
0
ixevexi@kali8:~/test$

제가 생각할때는 a->b로 바뀌고 msync로 인해 파일에
바뀐 내용이 수록되어 두번째 실행시에는 b,c,0가 나와야할 것같은데요
msync가 0을 반환하는 걸로 보아 확실히 성공은 했는데..
무엇이 문제일까요?

mmap 처음 써보는 초보가 질문 올립니다.

* 소스 수정했습니다 -_-;; 부끄러워라

hb_kim의 이미지

뭔가 메모리의 내용을 바꾼다음에 싱크를 하셔야 그게 파일에 저장될것 같군요.

혹 main() 안에 있는 로컬 포인터가 프로그램 실행간에 값을 유지하기를 기대하신것은 아니겠죠?

cinsk의 이미지

mmap은 파일의 내용을 memory로 mapping시켜주는 함수입니다. mmap()으로 파일에 내용을 덧붙이는 작업은 할 수 없습니다. 즉, mmap()을 써서 파일 크기가 0인 파일에 어떤 내용을 써 넣는 것은 불가능합니다.

실제 써 넣는 내용과 파일을 항상 동기화하는 것이 목적이라면 꼭 mmap()을 쓸 필요가 없습니다. 원하는 파일에 fsync()를 불러주면 됩니다.

mmap()을 잘못썼을 때 흔히 SIGSEGV와 SIGBUS가 발생합니다. 가장 흔한 예는 read only로 mapping한 memory등, 접근이 불가능한 곳에 access했을 경우 SIGSEGV, 현재 파일의 내용과 범위가 맞지 않는 곳을 접근하려 했을 때 SIGBUS가 발생합니다. 즉, 파일 크기가 0인데, 쓰려한다면 대개 SIGBUS가 발생합니다.

배열의 범위가 벗어나는 것을 잡아주는 debugging library인 Electric Fence(efence)는 바로 read-only로 mmap()했을 때 SIGSEGV가 발생하는 것에 힌트를 얻었습니다.

또한 실제 파일 크기보다 큰 공간을 mmap()으로 할당하면 (예: 파일 크기는 100byte이고, mmap에서 1024 byte를 할당한 경우), 나머지 1024 - 100 byte의 위치에는 0으로 채워지고, 이 곳에 쓰는 데이터는 나중에 무시됩니다. 즉 파일의 내용에 반영되지 않습니다. 앞에서 mmap()으로 파일의 크기를 변경하는 연산을 수행할 수 없다고 말한 것을 기억하기 바랍니다.

cinsk의 이미지

한가지 더, mmap()의 두번째 인자에 지정하는 길이는 보통 system page size의 배수가 되어야 합니다. 주어진 예제에서 "sizeof(int)*100"의 크기로 했는데, 바람직하지 않습니다. mmap()이 에러를 내고 errno를 EINVAL로 setting할 확률이 높습니다. 따라서 이 크기는 항상 page size의 배수가 되도록 하기 바랍니다. 앞에서도 말했듯이, file size보다 같거나 크며 page size의 배수가 되도록 하고, 이 때 남은 공간에는 0이 채워지고, 여기에 쓴 내용은 무시됩니다.

System의 page size는 sysconf(3)을 써서 얻을 수 있습니다.

ixevexi의 이미지

cinsk님 답변 고맙습니다 ^^
mmap에서 쓸 파일은 항상 유효?해야하고
page size의 크기로 인자를 주어야 한다는 것 앞으로 잘 기억하겠습니다.

hb_kim wrote:
뭔가 메모리의 내용을 바꾼다음에 싱크를 하셔야 그게 파일에 저장될것 같군요.

혹 main() 안에 있는 로컬 포인터가 프로그램 실행간에 값을 유지하기를 기대하신것은 아니겠죠?

음 전 먼가 바꾼줄 알았는데요 ^^

소스가 어이 없게 이상해 져버렸지만
분명히 mmap으로 할당한 공간을
int * a; 포인터로 포인팅 하고
(*a)를 변경하면 그 mmap으로 할당된 부분이 변경되는 것 아닌가요?

제 생각에는 코드는 틀린 것이 없어보이는데요??

#include<unistd.h>
#include<stdio.h>
#include<sys/mman.h>
#include<fcntl.h>
#include<sys/stat.h>

typedef struct char_100
{
    char character[100];
}RECORD;

int main(int argc, char **argv)
{
    int rt;
    RECORD rc, *prc;


    int fd = open ( "mmap.obj", O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);

    printf("page size:%ld\n", sysconf(_SC_PAGESIZE));
    prc=(RECORD *) mmap(0,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0);
    printf("address:%d\n",prc);

    printf("%c\n",prc->character[0]);
    prc->character[0]='b';
    printf("%c\n",prc->character[0]);

    rt = msync(prc,sizeof(struct char_100),MS_SYNC);
    munmap(prc,sizeof(struct char_100));
    printf("%d\n",rt);
    close(fd);
    return 0;
}

저 코드가 맘에 안들어서 다른 방식으로 한번 해보았습니다.
하지만 여전합니다 -_-;; 저위 4096은 제 시스템에서 page size입니다.

C++, 그리고 C++....
죽어도 C++

버그소년의 이미지

flags 값을 MAP_SHARED로 해야합니다.

MAP_PRIVATE는 원본 파일이 변경되지 않습니다.

man페이지 활용... ^^;

가끔은 밥을 굶어도 살 수 있다.

ixevexi의 이미지

감사드립니다 ^^
되네요 ^^

C++, 그리고 C++....
죽어도 C++

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.