sharemem.c 6.77 KB
/**    
    @file     sharemem.c
    @date     2006
    @author   유영창 frog@falinux.com  FALinux.Co.,Ltd.
    @author   오재경 freefrug@falinux.com  FALinux.Co.,Ltd.
    @brief    공유메모리를 생성하고 해제한다.

    @modify   
    @todo    
    @bug     
    @remark   
    
    
    @warning 
*/
//
//  저작권    에프에이리눅스(주)
//            외부공개 금지
//
//----------------------------------------------------------------------------
#define EMBEDDED_LINUX                                          // 이렇게 처리하지 않으면 EClipse에서 C 영역이 회색 바탕이 됨

#ifdef MS_WIN32
    #undef EMBEDDED_LINUX
#endif

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

#include <sys/types.h>
#include <sys/stat.h>

#ifdef EMBEDDED_LINUX

	#include <sys/shm.h>
	#include <sys/ipc.h>
	#include <sys/poll.h>
	#include <sys/ioctl.h>
	#include <sys/signal.h>

#endif




/// 공유메모리 관리를 위한 구조체
typedef struct
{
	int	key;            // 사용자가 바라보는 식별자
    int	id;             // 공유메모리 핸들
	char	data[0];    // 사용자가 엑세스하는 메모리
	
} share_t;


//------------------------------------------------------------------------------
/** @brief    공유메모리를 삭제한다.
    @param    key   공유메모리를 지정하는 유니크값
    @remark
*///----------------------------------------------------------------------------
void	share_delete( int key )
{
	FILE  *fp;
	char   line[128];
	int	   id = -1;
	int    size;
	
	// shm 정보파일을 연다.
	fp = fopen( "/proc/sysvipc/shm", "r" );
	if ( NULL == fp) 	return;
	
	if ( NULL != fgets( line, sizeof(line), fp )){              // 첫 번째 라인은 무시하기 위해 fgets() 실행
	    while(1){
	        int tmp_key, tmp_id, tmp_perm, tmp_size;

	        if ( fgets( line, sizeof(line), fp ) == NULL ) break;

	        // 키값과 크기를 읽어온다.
	        if ( 4 == sscanf( line, "%d %d %d %d", &tmp_key, &tmp_id, &tmp_perm, &tmp_size) ){
	            // printf( "SHM KEY = %d ID = %d SIZE=%d\n", tmp_key, tmp_id, tmp_size );
	            if ( tmp_key == key){
	                id = tmp_id;    // 해당하는 id 를 찾았다
	                size = tmp_size;
	                break;
	            }
	        }
	    }
	}

	// 파일을 닫는다.
	fclose( fp );

	// id 를 찾았다면 공유메모리를 삭제한다.
	if( 0 <= id){
		id = shmget( key, size, 0666 | IPC_CREAT);
		shmctl( id, IPC_RMID, NULL ); 
	}
}
//------------------------------------------------------------------------------
/** @brief    공유 메모리를 생성한다.
    @param    key   공유메모리를 지정하는 유니크값
    @param    size  생성할 공유메모리 크기
    @return   할당받은 공유메모리
    @remark
*///----------------------------------------------------------------------------
void	*share_create( int key, unsigned int size )
{
	int	id;
	void	*ptr;
	share_t *share; 
	
//	printf( "share_create key = %d\n" , key );
	
	// 공유 메모리를 생성하여 핸들을 얻거나 이미 있으면 해당 핸들을 가져 온다.
	id = shmget( key, sizeof(share_t) + size, 0666 | IPC_CREAT );
//	printf("shmget id = %d\n", id )

	if( id < 0 ) 
	{
		// 만약에 기존에 다른 크기로 생성되어 있다면
		// 이전것을 모두 삭제 처리 하고 재 생성을 요청한다.
//		printf("Exit Share Memory %08X\n", key );
		share_delete( key );
		
		// 다시 할당받는다.
		id = shmget( key, size + sizeof(share_t), 0666 | IPC_CREAT | IPC_EXCL );
		
		if( id < 0 ) return NULL;
	}

	// 공유메모리의 선두 주소를 얻어온다.
	ptr = shmat( id, NULL, 0 ); 
	if( ptr == NULL ) return NULL;
	
	// 공유메모리의 정보를 저장한다.
	share = (share_t *) ptr;
	share->key = key;
	share->id  = id;
	
	return share->data;
}
//------------------------------------------------------------------------------
/** @brief    공유 메모리를 해제한다.
    @param    data  share_create() 함수로 받은 메모리 포인터
    @remark
*///----------------------------------------------------------------------------
void	share_free( void *data )
{
	share_t	*share; 
	int	id;
	
	share = (share_t *)( data - sizeof(share_t) );
	id    = share->id;
	
	// 공유 메모리를 어드레스 공간에서 분리한다.
	shmdt( share ); 
	
	// 공유 메모리를 사용하는 프로세스가 없다면 삭제하도록 설정한다.
	shmctl( id, IPC_RMID, NULL ); 
}


/*

//-------------------------------------------------------------------------------
// 설명 :
// 주의 :
//-------------------------------------------------------------------------------
int	get_usrmsg( char *buf, int size )
{
	printf( "  type msg >> " );
	fgets( buf, size, stdin );

	if ( buf[strlen(buf)-1] == '\n' ) buf[strlen(buf)-1] = 0;

	if ( 0 == strcmp( buf, "exit" ) ) return -1;
	
	return 0;
}



//-------------------------------------------------------------------------------
// 설명 : help
// 주의 :
//-------------------------------------------------------------------------------
void	help( void )
{
	printf( " sap_shm [r|w] [key] [size]\n"	\
		"    r|w   : read or write\n"   \
		"    key   : shared mem key\n"  \
		"    size  : shared mem size\n"	\
		"    ex) ./sap_shm r 0x1234 256\n"\
	);
}

// 메세지를 보내고 받기위한 구조체
typedef struct 
{
	unsigned int	seq;
	char		data[0];
	
} msg_t;

//------------------------------------------------------------------------------
// 설명 : main
// 주의 :
//------------------------------------------------------------------------------
int     main( int argc, char **argv )
{
	msg_t	*pmsg;
	int	key, size;
	char	dir;
	
	
	if ( argc < 4 )
	{
		help();
		return -1;	
	}

	dir  = argv[1][0];
	key  = strtoul( argv[2], NULL, 0 );	
	size = strtoul( argv[3], NULL, 0 );	
	
	// 공유메모리를 생성한다.
	pmsg = (msg_t *)share_create( key, sizeof(msg_t) + size );
	
	if ( NULL == pmsg )
	{
		printf( " fail get shared mem\n" );
		return -1;
	}
	
	// 데이타를 공유메모리에 쓴다.
	if ( dir == 'w' )
	{
		pmsg->seq = 0;
		while( 0 == get_usrmsg( pmsg->data, size ) )
		{
			pmsg->seq ++;
		}	
		
		pmsg->seq ++;
	}
	// 데이타를 공유메모리에서 읽는다.
	else
	{
		unsigned int seq = 0;
		
		while(1)
		{
			if ( seq != pmsg->seq )
			{
				printf( " --> %s\n", pmsg->data );
				seq = pmsg->seq;

				if ( 0 == strcmp( pmsg->data, "exit" ) ) break;
			}
			
			sleep(1);
		}
	}
	
	// 공유메모리를 해제한다.
	share_free( pmsg );

	printf( " shm test end\n" );
	return 0;
}

*/