volkoff@home

Начало » Заметки

13 Декабря 2009

Драйвер канального уровня без сокетов. Часть 3

Опустив детали реализации[12], сразу покажу, что из этого получилось.

В интерфейс добавилась структура t_ivrChannelInfo, полностью описывающая канал:

typedef struct {
  ushort  link; /* (IN)  TDM link */
  ushort channel; /* (IN)  TDM channel 	*/
  uchar *txBuffer; /* (OUT) TX buffer  */
  ushort txBufferSize; /* allocated by driver and mapped to user space */ 
  uchar *rxBuffer; /* (OUT) RX buffer */
  ushort rxBufferSize; /* allocated by driver and mapped to user space */
  ulong channel_fd; /* (OUT) channel file descriptor */
} t_ivrChannelInfo;
Вот так выглядит инициализация каналов в приложении:
int fdAnnDrv; /* Driver handle */
int epfd; /* message queue */
/* channel descriptors table */
t_ivrChannelInfo chInfo[NUMBER_OF_CHANNELS];	

void ivrInit(void)
{
struct epoll_event ev;
fdAnnDrv=open("/dev/ivrDrv", 0);
/* Don't forget to check result here !!*/
....
/* Create epoll queue */
epfd = epoll_create(IVR_QUEUE_LEN);
/* Init all the channels */
for (i = 0; i < NUMBER_OF_CHANNELS; ++i)
{
 chInfo[i].link = IVR_TDM_LINK; /* TDM link for IVR*/
 chInfo[i].channel = i; /* channel number */
 /* Initialize the channel */
 retCode=ioctl(fdAnnDrv, IVR_INIT_CHANNEL, (unsigned int) &chInfo[i] );
 ev.events = EPOLLIN | EPOLLOUT | EPOLLERR;
 /* store channel info pointer in event structure */
 ev.data.ptr = chInfo[i]  
 /* add channel file descriptor to event queue */
 retCode=epoll_ctl(epfd, EPOLL_CTL_ADD, chInfo[i].channel_fd, &ev);
} /* for */
}
Вот так вызываются команды:
int ivrCmdExecute(int ch_num)
{
t_ivrChannelMsg chMsg;
t_ivrChannelInfo * chInfoPtr;
chInfoPtr = &chInfo[ch_num];
/* chInfoPtr->txBuff  should already contain the data we want to play */
chMsg.bufferOffset = 0;  /* offset from starting pointer of txBuff */
chMsg.bufferSize = 8000; 	/* chunk size */
chMsg.msgType = IVR_PLAY_BLOCK; / or whatever command
/* Send command to channel */
write(chInfoPtr->channel_fd, ( void *) &chMsg, sizeof(chMsg) );
}
Теперь самое интересное - системный процесс, который раньше разгребал очередь сообщений и вызывал callback-функцию приложения в контексте ядра, ушёл туда, где ему и следовало быть - в приложение:
void ivrMsgHandlingTask(void)
{
int retCode, nfds, i;
struct epoll_event *events;
struct epoll_event ivr_events[NUM_OF_EVENTS]; 
chInfoPtr * t_ivrChannelInfo;
t_ivrChannelMsg chMsg;
events = &ivr_events[0];
/* main message loop - forever */
for ( ; ; ){ 
 /* wait on queue - 2 second delay*/
 nfds = epoll_wait(epfd, events, NUM_OF_EVENTS, 2000); 
 /* For all events fired at a moment */
 for(i = 0; i < nfds; ++i) 
 {
  /* Get channel description pointer from event */
  chInfoPtr = (t_ivrChannelInfo *) events[i].data.ptr;
  /* Read the message from channel file descriptor */
  read(chInfoPtr->channel_fd, ( void *) &chMsg, sizeof(chMsg));
  /* Handle the messages */
  switch chMsg.msgType {
	case IVR_PLAY_GET_NEXT_BLOCK: ....
	case IVR_BLOCK_RECORDED:....
	case ....
  }
 } /* for */
}

Заключение
Думаю, детали реализации не так интересны, как сама идея. Она позволила без значительных изменений перенести на Linux достаточно сложную систему, казалось бы идеологически несовместимую, сохранив при этом логику взаимодействия, семантику вызовов, и не потеряв при этом в производительности.

Надеюсь, данный опыт окажется полезным для разработчиков, портирующих драйверы с закрытых коммерческих ОС на Linux.

Литература
[1] V5 interface, Wikipedia
[2] MPC8560 Reference Manual, Rev. 1, Freescale Semiconductors, 2004
[3] VoiceXML, Wikipedia
[4] Migrating legacy VxWorks applications to Linux, white paper by Bill Weinberg, Linux Pundit for MontaVista Software, October 22, 2008
[5] Linux Device Drivers, Third Edition, by Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman
[6] The need of Asynchronous, Zero-copy Network API, Ulrich Drepper, Red Hat
[7] The C10K problem, Dan Kegel, 2006
[8] Comparison of Performance of Different poll implementations
[9] Improving (network) I/O performance, Davide Libenzi, 2006
[10] Using epoll() for Asynchronous Network Programming, Alexey Kovyrin, 2006
[11] File descriptor for event notification, Davide Libenzi, 2007
[12] Embedded IVR solution for communication controllers, Alexey Volkov, master thesis, 2010

Комментарии