mmap관련 급질문. MAP_SHARED 와 MAP_PRIVATE

meconfidence의 이미지

제가 mmap이라는 함수를 쓰게 됬는데요,

   int read_file,write_file,count;
    void * read_buf;    void * write_buf;
    const int field_width = 136;

    read_file = open("1min_file.txt",O_RDONLY);
    write_file = open("1min_file.txt",O_RDWR); // 
    count = lseek(read_file,0,SEEK_END);

    read_buf = mmap(0,count,PROT_READ,MAP_SHARED,read_file,0);
    write_buf = mmap(0,count,PROT_WRITE,MAP_SHARED,write_file,0); // 문제가 되는 부분..
    memcpy(write_buf,read_buf+field_width,count-field_width);

    memcpy(write_buf+count-field_width,"20040408,100800,100.000,100.000,100.000,100.000,100.000,100.000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000\n",field_width);


    munmap(read_buf,count);
    munmap(write_buf,count);

    close(read_file);close(write_file);

이 코드 이전에, 다른 곳에서 이미 open("1min_file.txt",O_RDWR|O_CREAT|O_TRUNC|0777);로 열려 있는 상태입니다.
그랬더니 위의 코드에서
write_buf = mmap(0,count,PROT_WRITE,MAP_SHARED,write_file,0);
가 에러 EINVAL을 반환하더라구여..
EINVAL을 찾아보니, start나 length나 offset가 적당하지 않다 (즉, 너무 크거나 PAGESIZE 경계로 정렬되어 있지 않다.) 이렇게 나와있네요...

MAP_SHARED를 MAP_PRIVATE으로 고쳤더니 코드는 이상없이 돌아가는데,write_buf의 변경 내용이 해당 파일에 반영되지가 않습니다.

다른 곳에서 open해서 이렇게 된건지는 모르겠지만, 위의 코드만을 돌리면 잘 돌아갑니다.. 어디가 문제인지, 또 어떻게 해결해야될지 모르겠네요..
고수님들 한수 배우겠습니다.. :D

최종호의 이미지

meconfidence wrote:
제가 mmap이라는 함수를 쓰게 됬는데요,
...
이 코드 이전에, 다른 곳에서 이미 open("1min_file.txt",O_RDWR|O_CREAT|O_TRUNC|0777);로 열려 있는 상태입니다.
...

이렇게 하시면 1min_file.txt 이 정상적으로 open되지 않을 것 같습니다.

O_TRUNCATE 를 주시면, 이미 파일이 있는 경우 그 파일의 내용을 모두 없앱니다. (아마 이것을 의도하셨을 수도 있으셨겠네요.)

그 후, 0777 은 아마 파일생성시에 파일 모드를 지정해 주신 것으로 생각되는데,
파일모드는 open()의 두번째 파라메터인 flag와 OR 시키는 것이 아니라

세번째 파라메터로 주게 되어 있습니다.

컴파일러 에러를 안 낸 것은 파일모드가 optional 파라메터이기 때문입니다.

파일 생성모드에 garbage 값이 들어가서 생성한 파일의 모드가 이상하게 되어 있을 것입니다.
구현에 따라 | 0777 때문에 O_EXCL 과 O_CREAT 가 동시에 flag로 지정되는 경우에는 open() 이 실패할 수도 있을 것이고요.

일단 다른 쪽에서 open 하는 부분을 아래와 같이 수정해서 해 보시기 바랍니다.

open("1min_file.txt", O_RDWR|O_CREAT|O_TRUNC, 0777);

O_TRUNC 는 해당하는 로직에 맞도록 생략하시거나 유지하시거나 하시고요.

meconfidence wrote:
read_file = open("1min_file.txt",O_RDONLY);
write_file = open("1min_file.txt",O_RDWR); //
count = lseek(read_file,0,SEEK_END);

read_buf = mmap(0,count,PROT_READ,MAP_SHARED,read_file,0);
write_buf = mmap(0,count,PROT_WRITE,MAP_SHARED,write_file,0); // 문제가 되는 부분..
memcpy(write_buf,read_buf+field_width,count-field_width);

memcpy(write_buf+count-field_width,"20040408,100800,100.000,100.000,100.000,100.000,100.000,100.000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000,0.00000\n",field_width);

munmap(read_buf,count);
munmap(write_buf,count);

close(read_file);close(write_file);[/code]

일단 count 값을 찍어보세요.
Solaris 메뉴얼 상에는 mmap()의 두번째 파라메터 len 이 0보다 작거나 같은 경우에는
EINVAL 이 발생한다고 되어 있습니다.

mmap()에서 에러가 발생하지않고 넘어간다고 하더라도
파일이 존재하지않거나 사이즈가 0인상태, 또는 사이즈가 field_width 보다 작은 상태에서는 memcpy 에서 오류가 발생합니다.

그리고 파일크기가 field_width 보다 작은 경우에는 mmap된 영역의 field_width 까지 메모리 연산을 성공적으로 했다고 해도
그 내용이 실제 파일에 반영되지 않습니다.

파일 크기를 확인하셔서 크기가 적어도 field_width만큼 되는지 확인하시고,
그렇지 않은 경우에는 파일크기를 적어도 그 만큼으로 늘려주신 다음에
mmap()을 수행하셔야 됩니다.
(이 경우는 로직상 mmap을 안 쓰고 그냥 field 를 파일에 쓰는 것이 빠를 것 같긴 합니다만...)

open()과 mmap()을 두번 사용하셨는데, 한번만 사용하셔도 될듯합니다.
open()시에 읽기/쓰기 가능하게 주시고, PROT_READ | PROT_WRITE 되게 하면 될듯 싶습니다.

MAP_PRIVATE 시에 mmap()이 성공한 것은 일단 count가 0이라는 가정하에 의외의 결과입니다.
open()을 포함해서 mmap()의 리턴값과 에러 코드를 확인하는 부분을 올려줘봐 주실 수 있는지요?

meconfidence의 이미지

우선 답변 올려주신데 대해서 정말 감사드립니다.. :D :) :o

Quote:
이렇게 하시면 1min_file.txt 이 정상적으로 open되지 않을 것 같습니다.

open하는 부분을 잘 못 올렸네요..
| 0777 가 아니라 , 말씀하신것과 같이 열었습니다.
open("1min_file.txt", O_RDWR|O_CREAT|O_TRUNC, 0777);

Quote:
일단 count 값을 찍어보세요.
Solaris 메뉴얼 상에는 mmap()의 두번째 파라메터 len 이 0보다 작거나 같은 경우에는
EINVAL 이 발생한다고 되어 있습니다.

count값을 찍어보니 208이 나옵니다..

Quote:
mmap()에서 에러가 발생하지않고 넘어간다고 하더라도
파일이 존재하지않거나 사이즈가 0인상태, 또는 사이즈가 field_width 보다 작은 상태에서는 memcpy 에서 오류가 발생합니다.
그리고 파일크기가 field_width 보다 작은 경우에는 mmap된 영역의 field_width 까지 메모리 연산을 성공적으로 했다고 해도
그 내용이 실제 파일에 반영되지 않습니다.

field_width는 104로 count값 208(파일사이즈)보다 작습니다.
현재 문제가 되는 부분이 memcpy 하기 이전인 mmap입니다.

Quote:
(이 경우는 로직상 mmap을 안 쓰고 그냥 field 를 파일에 쓰는 것이 빠를 것 같긴 합니다만...)

말씀하신대로 하면 편리하긴 한데, 제가 쓸 파일이 MB단위라서 mmap을 쓰려구 합니당..

Quote:

open()과 mmap()을 두번 사용하셨는데, 한번만 사용하셔도 될듯합니다.
open()시에 읽기/쓰기 가능하게 주시고, PROT_READ | PROT_WRITE 되게 하면 될듯 싶습니다.

MAP_PRIVATE 시에 mmap()이 성공한 것은 일단 count가 0이라는 가정하에 의외의 결과입니다.
open()을 포함해서 mmap()의 리턴값과 에러 코드를 확인하는 부분을 올려줘봐 주실 수 있는지요?

말씀하신대로 mmap, open을 동시에 하고, 에러코드 확인하는 부분 올렸습니다

file_name은 동일한 이름.

open(file_name,O_RDWR|O_CREAT,0777); 이 이미 되있는 상황(성공으로 열림)

프로세스 도중 아래의 function을 호출합니다.

function(char * file_name, time_t * ptime, struct file_info *pfile_info)
{
    int file_fd; int count,i;
    void * buf; void * dest;

    const int field_width = pfile_info->field_width; // 104
    int temp_data_size = 5;
    char * sensor_data = (char *)malloc(temp_data_size+1); // 임의 숫자로 할당

    file_fd = open(file_name,O_RDWR); // 말씀하신대로, 한번만 열었습니다.(open성공 : file_fd == 81)
    count = lseek(file_fd,0,SEEK_END); // count = 208

    if(mmap(0,count,PROT_READ|PROT_WRITE,MAP_SHARED,file_fd,0) == -1)
            fprintf(stderr,"mmap with error %d(%s)\n",errno,strerror(errno)); // EINVAL에러 납니다.
    else    fprintf(stdout,"mmap success! \n");

    ....
    ...
    memcpy..
    ..
}

실제 프로그램 도중에 다음과 같이 에러 메시지가 뜹니다.
mmap with error 22(Invalid argument)
하지만, 여기서도 MAP_SHARED를 MAP_PRIVATE으로 하면
mmap success!
메시지가 뜹니다.
하지만 역시나, MAP_PRIVATE의 경우에는 파일에 변경되지 않습니다..

답글 달아주세요~ :wink:

항상 감사하는 마음으로...

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.