Hatena::ブログ(Diary)

ばけらぼ このページをアンテナに追加 RSSフィード

2010-01-26

[]

リハビリ(?)に、SysV系の共有メモリ操作のサンプル作成。

共有メモリ ( shmget/shmat/shmdt )

シグナル周りが面倒だったので、SIGTERMを同期ハンドリングする方法で作成しました。

個人的には非同期ハンドリングよりも、デバッグしやすいので、こういう実装を好みます。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string>

int main( int argc, char** argv)
{
    key_t  ipc_key = 0x00000500;
    size_t memsize = 4096;
    int    shmid = -1;
    bool delete_mode = false;
    bool writer = false;
    bool reader = false;
    bool view_mode = false;

    int state = 0;
    for ( int i = 1; i < argc; i++ ) {
        std::string arg( argv[i] );
        if ( state == 0 ) {
            if ( arg == std::string("-k") ) {
                state = 1;
            } else if ( arg == std::string("-s") ) {
                state = 2;
            } else if ( arg == std::string("-d") ) {
                delete_mode = true;
            } else if ( arg == std::string("-v") ) {
                view_mode = true;
            } else if ( arg == std::string("-w") ) {
                writer = true;
            } else if ( arg == std::string("-r") ) {
                reader = true;
            }
        } else if ( state == 1 ) {
            ipc_key = (key_t) strtol( argv[i], NULL, 0 );
            state = 0;
        } else if ( state == 2 ) {
            memsize = (size_t) strtol( argv[i], NULL, 0 );
            state = 0;
        }
    }

    shmid = shmget ( ipc_key, memsize, IPC_CREAT | 0666 );
    if ( shmid == -1 ) {
        perror("shmget");
        printf(" key=%x size=%ld mode=%x\n", ipc_key, (long)memsize, IPC_CREAT | 0666 );
        return -1;
    }
    printf("[create] shmid=%d key=%x size=%ld\n", shmid, ipc_key, (long)memsize );

    if ( view_mode ) {
        struct shmid_ds data_seg;
        if ( shmctl( shmid, IPC_STAT, &data_seg ) == -1 ) {
            perror("shmctl");
            printf(" shmid=%d cmd=IPC_STAT\n", shmid );
            return -1;
        }
        printf("[view] shmid=%d\n", shmid );
        printf(" shm_segsz=%ld\n", (long)data_seg.shm_segsz );
        printf(" shm_atime=%ld\n", (long)data_seg.shm_atime );
        printf(" shm_dtime=%ld\n", (long)data_seg.shm_dtime );
        printf(" shm_ctime=%ld\n", (long)data_seg.shm_ctime );
        printf(" shm_cpid=%d\n", data_seg.shm_cpid );
        printf(" shm_lpid=%d\n", data_seg.shm_lpid );
        printf(" shm_nattach=%ld\n", (long)data_seg.shm_nattch );
    }

    if ( writer || reader ) {

        void * shmaddr = NULL;
        shmaddr = shmat( shmid, NULL, 0 );
        if ( shmaddr == (void*)-1 ) {
            perror("shmat");
            printf(" shmid=%d\n", shmid );
            return -1;
        }
        printf("[attach] shmaddr=%p\n", shmaddr );

        sigset_t block_set;
        sigemptyset( &block_set );
        sigaddset  ( &block_set, SIGTERM );
        sigprocmask( SIG_BLOCK, &block_set, NULL );
        srandom( (unsigned int)time(NULL) );
        while(true) {
            sigset_t pend;
            sigpending(&pend);
            if ( sigismember( &pend, SIGTERM ) == 1 ) {
                printf ("[receive] SIGTERM\n");
                break;
            }
            sleep (1);
            int* p = (int*)shmaddr;
            if ( writer ) {
                int w = random();
                printf ("[write] *p = %d\n", w );
                *p = w;
            }
            if ( reader ) {
                int r = *p;
                printf ("[read]  *p = %d\n", r );
            }
        }

        if ( shmdt( shmaddr ) == -1 ) {
            perror("shmdt");
            printf(" shmaddr=%p\n", shmaddr );
        }
         printf("[detach] shmaddr=%p\n", shmaddr );
    }

    if ( delete_mode ) {
        if ( shmctl( shmid, IPC_RMID, NULL ) == -1 ) {
            perror("shmctl");
            printf(" shmid=%d cmd=IPC_RMID buf=NULL\n", shmid );
        }
        printf("[delete] shmid=%d\n", shmid );
    }

    return 0;
}