
1. 개요
이 문서는 시리얼 모듈을 루아에서 동작 시키기 위한 기능 중에서
시리얼 통신의 이벤트 방식 프로그램 지원을 위한 poll 객체 구현 내용을 기록한 문서이다.
이 문서에 대한 시험은 EZ-S3C2440 으로 하였다.
이번에도 루아의 사용법 소개와 소스 내용까지만 다룬다.
실제 C 에서 어떻게 구현했는가에 대한 소스 설명은 다음에
다룬다.
2. poll 객체
poll 객체는 다음과 같은 기능을 제공한다.
- poll 이벤트 등록
- poll 함수
- poll 이벤트 체크
2.1 poll 객체 생성
이벤트 처리를 지원하기 위해서는 poll 객체를 생성해야 한다.
생성은 다음과 같다.
p = require "poll"; -- 폴 모듈 생성 poll = p.create(4); -- poll 객체 생성 : p = nil; -- 실제 소멸
2.2 poll 이벤트 초기화 및 등록
원래 C 의 poll 함수의 이벤트 종류가 다양하지만 poll 객체에서는
가장 많이 쓰인느 다음과 같은 이벤트만 지원한다.
- 시간초과 이벤트
- 에러이벤트
- 읽기이벤트
- 쓰기이벤트
현재 설계된 이벤트는 수행 중간에 이벤트의 삭제나 추가는 되지 않는다.
즉 TCP 포트 연결과 같은 이벤트 추가는 지원되지 않고 있다.
이후에 추가될 예정이다.
이벤트의 초기화 및 등록은 다음과 같은 형식으로 사용되어야 한다.
poll.clear(); poll.add_event( com.fd,true);
clear() 는 이벤트의 목록을 초기화 하는 과정이다.
즉 이 함수가 호출되면 이전에 등록된 모든 이벤트가 제거된다.
add_event() 함수는 새로운 이벤트를 등록하게 된다. 이 함수의 파라메터는 다음과 같다.
add_event( 파일디스크립터 , 읽기 이벤트 조건, 에러 이벤트 조건, 쓰기 이벤트 조건 );
만약에 파라메터를 생략하면 false 즉 해당 이벤트는 체크 하지 않게 된다.
2.3 poll 동작
C 라이브러리의 poll() 함수를 호출하는 것은 poll 객체의 wait() 함수 이다.
이 함수는 파라메터 인자로 시간 초과 값(밀리초) 을 지정해야 한다.
poll.wait( 1000 )
이 함수의 반환은 내부적으로 poll() 함수에 실패한 것인데 이 때는
대부분 종료 처리 하는 것이 많다. (파일 디스크립터를 잘못 지정하는 것과 같은 프로그램 버그이거나
시스템에 치명적 문제로 인한 종료 이기 때문이다.
2.4 시간 초과 이벤트 체크
wait() 함수를 빠져 나오는 경우는 이벤트가 발생하거나 아무 이벤트가 발생하지 않아서 시간초과가 발생한 경우이다.
이때 시간 초과 검사를 가장 먼저 해야 하는데 이때 사용하는 함수가 check_event_read() 이다.
if poll.check_event_timeout() then // 아무런 이벤트 없이 시간 초과 발생 else : end;
2.5 이벤트 체크 및 처리 예
시간 초과가 아니라면 이벤트가 발생한 경우인데 이때는 각 이벤트별로 다음 함수들을 사용하여 체크해야 한다.
poll.check_event_read(fd); // fd 에 읽기 이벤트가 발생했는가? poll.check_event_error(fd); // fd 에 에러 이벤트가 발생했는가? poll.check_event_write(fd); // fd 에 쓰기 이벤트가 발생했는가?
만약 읽기 이벤트가 발생했다면 다음과 같이 해당 이벤트에 따라서 읽기 처리를 해 주어야 한다.
if poll.check_event_read( com.fd ) then print( "serial read event" ); rxsize, rxdata = com.read(); if rxsize > 0 then printf( " read size = %d", rxsize, rxdata ); printf( ">> [%s]",rxdata ); printf( "\n" ); end; end;
2.6 시험용 루아 데모 소스
#!/bin/lua -- #!/mnt/nfs/lua/lua printf = function(s,...) return io.write(s:format(...)) end; printf( ">> poll test\n" ); m = require "serial"; p = require "poll"; printf( ">> serial port list\n" ); spl = m.port_list(); printf( " total = %d\n", spl.count ); printf( " list = " ); print( spl ); spl.make_device_file(); poll = p.create(4); printf( ">> com create\n" ); com = m.create(); com.port = "/dev/ttyS1"; com.baud = 115200; com.data = 8; com.parity = "none"; printf( " port = %s\n", com.port ); printf( " baud = %d\n", com.baud ); printf( " data = %d\n", com.data ); printf( " parity = %s\n", com.parity ); com.open(); while true do poll.clear(); poll.add_event( com.fd,true); if poll.wait( 1000 ) == false then break; end; if poll.check_event_timeout() then print( "poll time out" ); com.write("serial write\r\n" ); else print( "poll event" ); if poll.check_event_read( com.fd ) then print( "serial read event" ); rxsize, rxdata = com.read(); if rxsize > 0 then printf( " read size = %d", rxsize, rxdata ); printf( ">> [%s]",rxdata ); printf( "\n" ); end; end; end; end; com.close(); p = nil; m = nil;
3. 구현 소스 목록
2 항에서 설명한 내용을 구현하기 위한 소스 구성은 다음과 같다.
Makefile : 컴파일을 위한 메이크 파일
run.lua : 시험을 위한 루아 스크립트
poll.c : poll 모듈를 위한 기본 구성 소스
4. poll.c 소스
#include <stdarg.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/poll.h> #define LUA_LIB #include <lua.h> #include <lauxlib.h> #define POLL_MODULE "POLL_MODULE" #define POLL "POLL" typedef struct { int max_count; struct pollfd *ufds; int count; int wait_time; int poll_result; } poll_t; static poll_t *call_func_pol = NULL; static poll_t *poll_new_userdata(lua_State *L) { poll_t *pol = (poll_t *) lua_newuserdata(L, sizeof(poll_t)); luaL_getmetatable(L, POLL); lua_setmetatable(L, -2); return pol; } static poll_t * poll_get_data(lua_State *L, int index) { poll_t *pol = (poll_t *) lua_touserdata(L, index); if (pol == NULL) luaL_typerror(L, index, POLL); return pol; } int poll_create( lua_State *L ) { poll_t *pol; pol = poll_new_userdata(L); pol->max_count = lua_tointeger( L, 1 ); if( pol->max_count < 0 ) pol->max_count = 0; if( pol->max_count == 0 ) pol->ufds = NULL; else pol->ufds = malloc( pol->max_count * sizeof( struct pollfd ) ); pol->count = 0; pol->wait_time = 0; return 1; } static int poll_index( lua_State *L ) { poll_t *pol; char *var_str; if( lua_type(L, 2) == LUA_TSTRING ) { pol = poll_get_data( L, 1 ); var_str = (char *) lua_tostring( L, 2 ); if ( !strcmp( var_str, "wait" ) ) { call_func_pol = pol; } else if( !strcmp( var_str, "clear" ) ) { call_func_pol = pol; } else if( !strcmp( var_str, "check_event_timeout" ) ) { call_func_pol = pol; } else if( !strcmp( var_str, "add_event" ) ) { call_func_pol = pol; } else if( !strcmp( var_str, "check_event_read" ) ) { call_func_pol = pol; } else if( !strcmp( var_str, "check_event_error" ) ) { call_func_pol = pol; } else if( !strcmp( var_str, "check_event_write" ) ) { call_func_pol = pol; } lua_getmetatable(L, 1); lua_replace(L, 1); lua_rawget(L, 1); return 1; } return 0; } static int poll_tostring (lua_State *L) { poll_t *pol; pol = poll_get_data( L, 1 ); lua_pushstring ( L, "poll_object" ); return 1; } static int poll_gc(lua_State *L) { poll_t *pol; pol = poll_get_data( L, 1 ); return 0; } static int poll_wait(lua_State *L) { poll_t *pol; int ret; pol = call_func_pol; pol->poll_result = -1; ret = -1; pol->wait_time = lua_tointeger( L, 1 ); pol->poll_result = poll( pol->ufds, pol->count, pol->wait_time ); if( pol->poll_result >= 0 ) lua_pushboolean(L, 1); else lua_pushboolean(L, 0); call_func_pol = NULL; return 1; } static int poll_clear(lua_State *L) { poll_t *pol; struct pollfd *poll_item; int lp; pol = call_func_pol; pol->count = 0; call_func_pol = NULL; if( pol->max_count == 0 ) return 0; if( pol->ufds == NULL ) return 0; memset( pol->ufds, 0, sizeof( struct pollfd ) * pol->max_count ); poll_item = pol->ufds; for( lp = 0; lp < pol->max_count; lp++ ) { poll_item->fd = -1; poll_item++; } return 0; } static int poll_add_event(lua_State *L) { poll_t *pol; struct pollfd *poll_item; int lp; int append_fd; int append_read; int append_error; int append_write; pol = call_func_pol; append_fd = lua_tointeger( L, 1 ); append_read = lua_toboolean( L, 2 ); append_error = lua_toboolean( L, 3 ); append_write = lua_toboolean( L, 4 ); if( pol->max_count == 0 ) return 0; if( pol->ufds == NULL ) return 0; if( pol->max_count <= pol->count ) return 0; poll_item = pol->ufds; for( lp = 0; lp < pol->max_count; lp++ ) { if( poll_item->fd == append_fd ) { printf( "error - same fd %d\n", append_fd ); break; } if( poll_item->fd == -1 ) { poll_item->fd = append_fd; poll_item->events = 0; poll_item->revents = 0; if( append_read ) poll_item->events |= POLLIN ; if( append_error ) poll_item->events |= POLLERR ; if( append_write ) poll_item->events |= POLLOUT ; if( poll_item->events == 0 ) { poll_item->fd = -1; printf( "error - append without event\n" ); } else { pol->count = pol->count + 1; } break; } poll_item++; } call_func_pol = NULL; return 0; } static int poll_check_event_timeout(lua_State *L) { poll_t *pol; pol = call_func_pol; if( pol->poll_result == 0 ) lua_pushboolean(L, 1); else lua_pushboolean(L, 0); call_func_pol = NULL; return 1; } static int poll_check_event_read(lua_State *L) { poll_t *pol; int check_fd; struct pollfd *poll_item; int lp; pol = call_func_pol; check_fd = lua_tointeger( L, 1 ); poll_item = pol->ufds; for( lp = 0; lp < pol->count; lp++ ) { if( poll_item->fd == check_fd ) { if( poll_item->revents & POLLIN ) { lua_pushboolean(L, 1); return 1; } } poll_item++; } lua_pushboolean(L, 0); return 1; } static int poll_check_event_error(lua_State *L) { poll_t *pol; int check_fd; struct pollfd *poll_item; int lp; pol = call_func_pol; check_fd = lua_tointeger( L, 1 ); poll_item = pol->ufds; for( lp = 0; lp < pol->count; lp++ ) { if( poll_item->fd == check_fd ) { if( poll_item->revents & POLLERR ) { lua_pushboolean(L, 1); return 1; } } poll_item++; } lua_pushboolean(L, 0); return 1; } static int poll_check_event_write(lua_State *L) { poll_t *pol; int check_fd; struct pollfd *poll_item; int lp; pol = call_func_pol; check_fd = lua_tointeger( L, 1 ); poll_item = pol->ufds; for( lp = 0; lp < pol->count; lp++ ) { if( poll_item->fd == check_fd ) { if( poll_item->revents & POLLOUT ) { lua_pushboolean(L, 1); return 1; } } poll_item++; } lua_pushboolean(L, 0); return 1; } static const luaL_reg poll_meta[] = { {"__index" , poll_index }, {"__tostring" , poll_tostring }, {"__gc" , poll_gc }, {"clear" , poll_clear }, {"wait" , poll_wait }, {"check_event_timeout" , poll_check_event_timeout }, {"add_event" , poll_add_event }, {"check_event_read" , poll_check_event_read }, {"check_event_error" , poll_check_event_error }, {"check_event_write" , poll_check_event_write }, {0, 0} }; static const struct luaL_Reg pm[] = { { "create" , poll_create }, { NULL, NULL } }; int poll_new_metatable(lua_State *L ) { int top; top = lua_gettop(L); luaL_newmetatable(L, POLL ); lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); luaL_register(L, NULL, poll_meta ); lua_settop(L, top); return 1; } LUALIB_API int luaopen_poll( lua_State *L ) { luaL_register(L, POLL_MODULE, pm ); poll_new_metatable(L); return 1; }
5. Makefile
모듈을 컴파일을 위한 메이크 파일이다.
CROSS_PREFIX = arm-linux CROSS_PREFIX_CC = $(CROSS_PREFIX)- LUA_MODULE = poll.so TARGET = $(LUA_MODULE) TARGET_NFS = /nfs/lua LIB_LUA_A = liblua.a C_SRCS = LUA_SRCS = LUA_LIBS_SRCS = C_SRCS += poll.c LUA_SRCS += run.lua # LUA Support -- CORE LUA_LIBS_SRCS = LUA_LIBS_SRCS += ../../lua_lib/lapi.c LUA_LIBS_SRCS += ../../lua_lib/lcode.c LUA_LIBS_SRCS += ../../lua_lib/ldebug.c LUA_LIBS_SRCS += ../../lua_lib/ldo.c LUA_LIBS_SRCS += ../../lua_lib/ldump.c LUA_LIBS_SRCS += ../../lua_lib/lfunc.c LUA_LIBS_SRCS += ../../lua_lib/lgc.c LUA_LIBS_SRCS += ../../lua_lib/llex.c LUA_LIBS_SRCS += ../../lua_lib/lmem.c LUA_LIBS_SRCS += ../../lua_lib/lobject.c LUA_LIBS_SRCS += ../../lua_lib/lopcodes.c LUA_LIBS_SRCS += ../../lua_lib/lparser.c LUA_LIBS_SRCS += ../../lua_lib/lstate.c LUA_LIBS_SRCS += ../../lua_lib/lstring.c LUA_LIBS_SRCS += ../../lua_lib/ltable.c LUA_LIBS_SRCS += ../../lua_lib/ltm.c LUA_LIBS_SRCS += ../../lua_lib/lundump.c LUA_LIBS_SRCS += ../../lua_lib/lvm.c LUA_LIBS_SRCS += ../../lua_lib/lzio.c # LUA Support -- LIB LUA_LIBS_SRCS += ../../lua_lib/lauxlib.c LUA_LIBS_SRCS += ../../lua_lib/lbaselib.c LUA_LIBS_SRCS += ../../lua_lib/ldblib.c LUA_LIBS_SRCS += ../../lua_lib/liolib.c LUA_LIBS_SRCS += ../../lua_lib/lmathlib.c LUA_LIBS_SRCS += ../../lua_lib/loslib.c LUA_LIBS_SRCS += ../../lua_lib/ltablib.c LUA_LIBS_SRCS += ../../lua_lib/lstrlib.c LUA_LIBS_SRCS += ../../lua_lib/loadlib.c LUA_LIBS_SRCS += ../../lua_lib/linit.c INCLUDES += -I. INCLUDES += -I/usr/local/include INCLUDES += -I/usr/$(CROSS_PREFIX)/include INCLUDES += -I../include INCLUDES += -I../../lua_include LDFLAGS += -L./ LDFLAGS += -L../../lua_lib/ LDFLAGS += -L/usr/$(CROSS_PREFIX)/lib LIBS = -lm -ldl -llua CFLAGS += $(INCLUDES) CFLAGS += -Wall -O2 -g -DLUA_USE_LINUX CPPFLAGS += $(DEFINES) ARFLAGS = rs #--------------------------------------------------------------------- CC = $(CROSS_PREFIX_CC)gcc CXX = $(CROSS_PREFIX_CC)g++ AR = $(CROSS_PREFIX_CC)ar rcu AR2 = $(CROSS_PREFIX_CC)ranlib RANLIB = $(CROSS_PREFIX_CC)ranlib LD = $(CROSS_PREFIX_CC)ld NM = $(CROSS_PREFIX_CC)nm STRIP = $(CROSS_PREFIX_CC)strip OBJCOPY = $(CROSS_PREFIX_CC)objcopy CP = cp MV = mv #-------------------------------------------------------------------- C_OBJS = $(C_SRCS:%.c=%.o) LUA_LIBS_OBJS = $(LUA_LIBS_SRCS:%.c=%.o) # # Compilation target for C files # %.o:%.c @echo "Compiling $< ..." $(CC) -c $(CFLAGS) -o $@ $< %.o:%.cc @echo "Compiling $< ..." $(CXX) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< # # Compilation target for C++ files # %.o:%.cc @echo "C++ compiling $< ..." $(CXX) -c $(CFLAGS) $(CXXFLAGS) -o $@ $< all : $(LIB_LUA_A) $(LIB_GXLIB_A) $(TARGET) cp -a $(LUA_MODULE) $(TARGET_NFS) cp $(LUA_SRCS) $(TARGET_NFS) $(LIB_LUA_A) : $(LUA_LIBS_OBJS) $(AR) $@ $? $(RANLIB) $@ $(TARGET) : $(C_OBJS) $(CC) $(LDFLAGS) -shared -Wl,-soname,$(TARGET) $(C_OBJS) -o $@ $(LIBS) dep : $(CC) -M $(INCLUDES) $(C_SRCS) > .depend clean: rm -f *.bak rm -f *.map rm -f *.o rm -f *.so rm -f $(C_OBJS) rm -f $(LUA_LIBS_OBJS) rm -f $(LIB_LUA_A) rm -f $(TARGET) core distclean: clean rm -rf .depend ifeq (.depend,$(wildcard .depend)) include .depend endif
6. 실행예
다음은 EZ-S3C2440 에서 실행한 예 이다.
[root@falinux lua]$ ./run.lua
>> poll test
>> serial port list
total = 3
list = /dev/ttyS0 /dev/ttyS1 /dev/ttyS2
>> com create
port = /dev/ttyS1
baud = 115200
data = 8
parity = none
poll time out
poll time out
poll event
serial read event
read size = 1>> [d]
poll event
serial read event
read size = 1>> [f]
poll event
serial read event
read size = 1>> [s]
poll time out
poll event
serial read event
read size = 1>> [f]
poll event
serial read event
read size = 1>> [d]
poll time out
