posix proactor library
++++++++++++++++++++++++++
+ Header File
++++++++++++++++++++++++++
// posix_proactor.h, v 0.1 2005/05/19
// ============================================================================
/**
*
*
*
* @file posix_proactor.h
*
* @brief posix_proactor which use RT Signal.
*
* struct aiocb
* int aio_fildes; //file descriptor
* volatile void *aio_buf; //buffer allocation
* size_t aio_nbytes; //length of transfer
* off_t aio_offet; //file offset. starting position
* int aio_reqprio; //request priority offset(_POSIX_PRIORITIZED_IO and _POSIX_PRORITY_SCHEDULING
* struct sigevent aio_sigevent; //signal number and offset
* int aio_lio_opcode; //listio operation
*
* @author sunsson <sunsson@varovision.com>
*/
// ============================================================================
#ifndef __POSIX_PROACTOR__
#define __POSIX_PROACTOR__
#include <signal.h>
#include <time.h>
#include <aio.h>
#define AIOCB_MAX_SIZE 2048 //서버가 지원하는 최대 클라이언트 수(1024) * 클라이언트 당 요청한 파일의 미디어 수(평균 2)
#define PROACTOR_DEBUG 1
#ifdef __cplusplus
extern "C" {
#endif//__cplusplus
//typedef void (*SIGNAL_C_FUNC)(int, siginfo_t *, void *);
/**
* posix asynchronous result
* <BR>
* asynchronous reqeust를 요청한 곳 ( handler, data ) 에 요청된 결과가 처리되었을 때
* 알리기 위한 구조
*/
typedef struct posix_asynch_result{
/// allocated aiocb
struct aiocb *aiocb;
/// file description
int fd;
/// Bytes transferred by this operation.
size_t size;
/**
* This really make sense only when doing file I/O.
*
* @@ On POSIX4-Unix, offset_high should be supported using
* aiocb64.
*
*/
unsigned long offset;
unsigned long offset_high;
/// Priority of the operation.
int priority;
/**
* POSIX4 realtime signal number to be used for the
* operation. <signal_number> ranges from SIGRTMIN to SIGRTMAX. By
* default, SIGRTMIN is used to issue <aio_> calls.
*/
int signal_number;
/// Success indicator.
int success;
/// Error if operation failed.
unsigned long error;
/// on receiving signal in signal_hander, to call media's handler function
void * (*hndlr)(void *);
/// on receiving signal in signal_hander, to give a parameter to media's handler function
void * data;
}posix_asynch_result;
/**
* aiocb에 대한 요청이 READ인지, WRITE인지를 나타내는 값
*/
typedef enum{
READ = 1,
WRITE = 2
}Opcode;
/// number of aiocb
struct aiocb **aiocb_list; //AIOCB_MAX_SIZE만큼
posix_asynch_result **result_list;
/// signal set
static sigset_t RT_completion_signal;
/// To maintain the maximum size of the array (list).
size_t aiocb_list_max_size;
/// To maintain the current size of the array (list).
size_t aiocb_list_cur_size;
/// Number of posix_asynch_result's waiting for start
/// i.e. deferred AIOs
size_t num_deferred_aiocb;
/// Number active,i.e. running requests
size_t num_started_aio;
/////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////PROACTOR INIT////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/**
* @author 박학선
* @param max_aio_operations System Interface에서 사용할 aiocb_list의 최대 갯수
* @retval -1 proactor init error
* @retval 0 proactor init ok
* @brief System Interface이 초기화될 때 posix_proactor를 초기화
* 하면서 시그널 세팅!!
*/
int
posix_proactor_init(size_t max_aio_operations);
/**
* @author 박학선
* @param
* @retval
* @brief System의 max aio size를 체크!!
*/
void
check_max_aio_num();
/**
* @author 박학선
* @param
* @retval 0 result create ok
* @brief System이 관리할 aiocb_list, result_list를 만듬
*/
int
create_result_aiocb_list();
/**
* @author 박학선
* @param
* @retval -1 setup signal init or setup signal_hanlder fail
* @retval 0 setup signal init(handler) success
* @brief System이 사용할 signal(RTSIG_MIN) set up!!
*/
int
signal_init();
/**
* @author 박학선
* @param signal_number signal handler를 띄울 RTSIG
* @retval -1 setup signal handler fail
* @retval 0 setup signal handler success
* @brief System Interface이 초기화될 때 시그널 핸들러 세팅!!
*/
int
setup_signal_handler(int signal_number);
/////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////CALLBACK/////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/**
* @author 박학선
* @param signal_number signal handler를 깨운 signal
* @param info signal과 연관된 정보들(aiocb_list의 index)
* @param context 사용한 바 없음.
* @retval
* @brief 요청된 read를 수행한 후에 호출되는 signal_handler
*/
void
rtsig_handler (int signal_number, siginfo_t* info, void* context);
/**
* @author 박학선
* @param
* @retval -1 handler event error
* @retval 0 run_event_loop complete
* @brief loop을 돌면서 완료된 aiocb_list가 있는지 검사
*/
int
run_event_loop();
/**
* @author 박학선
* @param
* @retval -1 sigtimedwait error
* @retval 0 handler_event complete
* @brief 요청된 read를 수행한 후에 호출되는 signal_handler
* ====> signal_handler에서 signal을 감지했을 때완료된 요청이 있는지 검사
*/
int
handle_event(void);
//posix_asynch_result *
//find_completed_aio(int *error_status, size_t *transfer_count, size_t index, size_t count);
/**
* @author 박학선
* @param aiocb
* @param error_status
* @param transfer_count
* @retval 1 AIO completed
* @retval 0 not completed yet
* @brief AIO가 completed되었는지를 체크
*/
int
get_result_status (struct aiocb *aiocb, int *error_status, size_t *transfer_count);
/**
* @author 박학선
* @param idx
* @param transfer_count
* @param error_status
* @brief completed된 aiocb_list의 callback handler를 호출
*/
void
application_specific_code(size_t idx, int transfer_count, int error_status);
/////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////REQEUEST////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/**
* @author 박학선
* @param file_fd
* @param size
* @param offset
* @param buf
* @param data
* @param hndlr_ftn
* @param priority
* @param op
* @brief media에서 asynchronous read를 요청하기 위해 호출하는 함수.
* 실제로는 이 파일안에 정의되어 있지는 않음. 단지 테스트를 위해서...
*/
int
si_read_req(int file_fd, int size, int offset, void *buf, void *data, void *hndlr_ftn, int priority, Opcode op);
/**
* @author 박학선
* @param result
* @param op
* @retval 0 started OK
* @retval 1 OS AIO queue overflow
* @retval -1 do not started
* @brief System Interface(si_read_req())에서 Proactor에
* read를 요청하기 위해 사용!!
*/
int
issue_aio_calls (posix_asynch_result *result, Opcode op);
/**
* @author 박학선
* @param aiocb
* @retval 0 AIO was started successfully
* @retval 1 AIO was not started, OS AIO queue overflow
* @retval -1 AIO was not started, other errors
* @brief 파일의 미디어 트랙에서 aio_read, aio_write를 실행!!
*/
int
execute_aio_calls (struct aiocb * aiocb);
/**
* @author 박학선
* @param aiocb
* @retval retval > 0 allocated aiocb_list's slot
* @retval -1 no free slot
* @brief 이 시스템에서 관리하는 aiocb_list의 free slot을 반환한다.
*/
ssize_t
allocate_aio_slot(struct aiocb * aiocb);
#ifdef __cplusplus
}
#endif//__cplusplus
#endif //__POSIX_PROACTOR__
++++++++++++++++++++++++++
+ Source File
++++++++++++++++++++++++++
// posix_proactor.c, v 0.1 2005/05/19
// ============================================================================
/**
*
*
*
* @file posix_proactor.c
*
* posix_proactor which use RT Signal.
*
* struct aiocb
* int aio_fildes; //file descriptor
* volatile void *aio_buf; //buffer allocation
* size_t aio_nbytes; //length of transfer
* off_t aio_offet; //file offset. starting position
* int aio_reqprio; //request priority offset(_POSIX_PRIORITIZED_IO and _POSIX_PRORITY_SCHEDULING
* struct sigevent aio_sigevent; //signal number and offset
* int aio_lio_opcode; //listio operation
*
* @author sunsson <sunsson@varovision.com>
*/
// ============================================================================
#include "posix_proactor.h"
#include "test/test_posix_proactor.h"
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h> //getrlimit, strlimit : control maximum resource consumption
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <limits.h>
#include <aio.h>
#include <time.h>
#include <assert.h>
/////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////PROACTOR INIT////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/**
* @author 박학선
* @param max_aio_operations System Interface에서 사용할 aiocb_list의 최대 갯수
* @retval -1 proactor init error
* @retval 0 proactor init ok
* @brief System Interface이 초기화될 때 posix_proactor를 초기화
* 하면서 시그널 세팅!!
*/
int
posix_proactor_init(size_t max_aio_operations)
{
aiocb_list = 0;
result_list = 0;
aiocb_list_max_size = max_aio_operations;
aiocb_list_cur_size = 0;
num_deferred_aiocb = 0;
num_started_aio = 0;
check_max_aio_num();
if(create_result_aiocb_list() != 0){
fprintf(stderr, "aiocb list make error\n");
return -1;
}
if(signal_init() != 0){
fprintf(stderr, "signal init error\n");
return -1;
}
///run_event_loop에서 완료된 sigset이 있는지 체크..
//run_event_loop();
return 0;
}
/**
* @author 박학선
* @param
* @retval
* @brief System의 max aio size를 체크!!
*/
void
check_max_aio_num()
{
long max_aio_num;
int max_num_files, r;
struct rlimit rl;
max_aio_num = sysconf (_SC_AIO_MAX);
if (max_aio_num > 0 && aiocb_list_max_size > (unsigned long) max_aio_num)
aiocb_list_max_size = max_aio_num;
if (aiocb_list_max_size <= 0 || aiocb_list_max_size > AIOCB_MAX_SIZE)
aiocb_list_max_size = AIOCB_MAX_SIZE;
#if defined (RLIM_INFINITY)
r = getrlimit (RLIMIT_NOFILE, &rl);
if (r == 0 && rl.rlim_cur != RLIM_INFINITY)
max_num_files = rl.rlim_cur;
#endif //RLIM_INFINITY
if (max_num_files > 0 && aiocb_list_max_size > (unsigned long) max_num_files){
#if defined (RLIM_INFINITY)
rl.rlim_cur = max_num_files;
r = setrlimit (RLIMIT_NOFILE, &rl);
if (r == 0 && rl.rlim_cur != RLIM_INFINITY)
#endif //RLIM_INFINITY
aiocb_list_max_size = max_num_files;
}
}
/**
* @author 박학선
* @param
* @retval 0 result create ok
* @brief System이 관리할 aiocb_list, result_list를 만듬
*/
int create_result_aiocb_list()
{
size_t ai;
if (aiocb_list != 0)
return 0;
aiocb_list = (struct aiocb**)malloc(sizeof(struct aiocb *[aiocb_list_max_size]));
result_list = (posix_asynch_result **)malloc(sizeof(posix_asynch_result * [aiocb_list_max_size]));
for (ai = 0; ai < aiocb_list_max_size; ai++){
aiocb_list[ai] = 0;
result_list[ai] = 0;
}
return 0;
}
/**
* @author 박학선
* @param
* @retval -1 setup signal init or setup signal_hanlder fail
* @retval 0 setup signal init(handler) success
* @brief System이 사용할 signal(RTSIG_MIN) set up!!
*/
int signal_init()
{
int ret_val;
/// Get full set
if(sigemptyset(&RT_completion_signal) == -1)
fprintf(stderr, "[Error] Couldnt empty signal set\n");
if(sigaddset(&RT_completion_signal, SIGRTMIN) == -1)
fprintf(stderr, "[Error] Couldnt init the RT completion signal set\n");
///block the signal
if(sigprocmask(SIG_BLOCK, &RT_completion_signal, 0) == -1) {
fprintf(stderr, "Could not block SIGRTMAX or SIGRTMAX-1");
return -1;
}
ret_val = setup_signal_handler(SIGRTMIN);
///unblock the signal
//if(sigprocmask(SIG_UNBLOCK, &newact.sa_mask, NULL) == -1){
if(sigprocmask(SIG_UNBLOCK, &RT_completion_signal, 0) == -1) {
fprintf(stderr, "Could not unblock SIGRTMAX or SIGRTMAX-1");
return -1;
}
return ret_val;
}
/**
* @author 박학선
* @param signal_number signal handler를 띄울 RTSIG
* @retval -1 setup signal handler fail
* @retval 0 setup signal handler success
* @brief System Interface이 초기화될 때 시그널 핸들러 세팅!!
*/
int
setup_signal_handler(int signal_number)
{
struct sigaction newact;
int sigaction_return;
sigemptyset(&newact.sa_mask); //Nothing else to mask
newact.sa_flags = SA_SIGINFO; // Realtime flag.
newact.sa_sigaction = rtsig_handler ; //set up "null_handler"
sigaction_return = sigaction (signal_number, &newact, 0); //specify the action to be associated with a specific signal
if(sigaction_return == -1){
fprintf(stderr, "[Error]couldnt do sigaction for the RT SIGNAL\n");
return -1;
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////CALLBACK/////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/**
* @author 박학선
* @param signal_number signal handler를 깨운 signal
* @param info signal과 연관된 정보들(aiocb_list의 index)
* @param context 사용한 바 없음.
* @retval
* @brief 요청된 read를 수행한 후에 호출되는 signal_handler
*/
void
rtsig_handler (int signal_number, siginfo_t* info, void* context)
{
int result = 0;
// struct timespec timeout;
#if 0
fprintf(stderr, "[info]Signal number %d\n", signal_number);
if(query_aio_completions() < 0)
fprintf(stderr, "null handler error\n");
else
fprintf(stdout, "rtsig_handler\n");
#else//0
#ifdef PROACTOR_DEBUG
fprintf(stdout, "\n\nrtsig_handler\n");
#endif//PROACTOR_DEBUG
result = handle_event ();
if (result != 0 || errno == ETIME)
perror("handle_event \n");
#endif//0
exit(1);
}
/**
* @author 박학선
* @param
* @retval -1 handler event error
* @retval 0 run_event_loop complete
* @brief loop을 돌면서 완료된 aiocb_list가 있는지 검사
*/
int run_event_loop()
{
int ret_val;
// Run the event loop.
for (;;){
ret_val = handle_event();
if(ret_val == -1)
break;
}
return 0;
}
/**
* @author 박학선
* @param
* @retval -1 sigtimedwait error
* @retval 0 handler_event complete
* @brief 요청된 read를 수행한 후에 호출되는 signal_handler
* ====> signal_handler에서 signal을 감지했을 때완료된 요청이 있는지 검사
*/
int
handle_event (void)
{
int sig_return = 0, error_status = 0;
int ret_aio, ret_val;
size_t aiocb_index = 0, transfer_count = 0, count = 1, idx;;
posix_asynch_result* asynch_result;
///To get back the signal info.
siginfo_t sig_info;
struct