2006-03-27 01:14:30 -08:00
/*
2017-11-20 21:17:58 +00:00
* Copyright ( C ) 2017 - Cambridge Greys Ltd
* Copyright ( C ) 2011 - 2014 Cisco Systems Inc
2008-02-04 22:31:02 -08:00
* Copyright ( C ) 2000 - 2007 Jeff Dike ( jdike @ { addtoit , linux . intel } . com )
2006-03-27 01:14:30 -08:00
* Licensed under the GPL
*/
# include <stdlib.h>
# include <errno.h>
2017-11-20 21:17:58 +00:00
# include <sys/epoll.h>
2006-03-27 01:14:30 -08:00
# include <signal.h>
# include <string.h>
2012-10-08 03:27:32 +01:00
# include <irq_user.h>
# include <os.h>
# include <um_malloc.h>
2006-03-27 01:14:30 -08:00
2017-11-20 21:17:58 +00:00
/* Epoll support */
static int epollfd = - 1 ;
# define MAX_EPOLL_EVENTS 64
static struct epoll_event epoll_events [ MAX_EPOLL_EVENTS ] ;
/* Helper to return an Epoll data pointer from an epoll event structure.
* We need to keep this one on the userspace side to keep includes separate
*/
void * os_epoll_get_data_pointer ( int index )
{
return epoll_events [ index ] . data . ptr ;
}
/* Helper to compare events versus the events in the epoll structure.
* Same as above - needs to be on the userspace side
*/
int os_epoll_triggered ( int index , int events )
{
return epoll_events [ index ] . events & events ;
}
/* Helper to set the event mask.
* The event mask is opaque to the kernel side , because it does not have
* access to the right includes / defines for EPOLL constants .
*/
int os_event_mask ( int irq_type )
{
if ( irq_type = = IRQ_READ )
return EPOLLIN | EPOLLPRI ;
if ( irq_type = = IRQ_WRITE )
return EPOLLOUT ;
return 0 ;
}
2007-02-10 01:44:23 -08:00
/*
2017-11-20 21:17:58 +00:00
* Initial Epoll Setup
2007-02-10 01:44:23 -08:00
*/
2017-11-20 21:17:58 +00:00
int os_setup_epoll ( void )
{
epollfd = epoll_create ( MAX_EPOLL_EVENTS ) ;
return epollfd ;
}
2006-03-27 01:14:30 -08:00
2017-11-20 21:17:58 +00:00
/*
* Helper to run the actual epoll_wait
*/
int os_waiting_for_events_epoll ( void )
2006-03-27 01:14:30 -08:00
{
2017-11-20 21:17:58 +00:00
int n , err ;
2006-03-27 01:14:30 -08:00
2017-11-20 21:17:58 +00:00
n = epoll_wait ( epollfd ,
( struct epoll_event * ) & epoll_events , MAX_EPOLL_EVENTS , 0 ) ;
2006-05-01 12:15:57 -07:00
if ( n < 0 ) {
2006-03-27 01:14:30 -08:00
err = - errno ;
2006-05-01 12:15:57 -07:00
if ( errno ! = EINTR )
2017-11-20 21:17:58 +00:00
printk (
UM_KERN_ERR " os_waiting_for_events: "
" epoll returned %d, error = %s \n " , n ,
strerror ( errno )
) ;
2006-03-27 01:14:30 -08:00
return err ;
}
return n ;
}
2017-11-20 21:17:58 +00:00
/*
* Helper to add a fd to epoll
*/
int os_add_epoll_fd ( int events , int fd , void * data )
2006-03-27 01:14:30 -08:00
{
2017-11-20 21:17:58 +00:00
struct epoll_event event ;
int result ;
event . data . ptr = data ;
event . events = events | EPOLLET ;
result = epoll_ctl ( epollfd , EPOLL_CTL_ADD , fd , & event ) ;
if ( ( result ) & & ( errno = = EEXIST ) )
result = os_mod_epoll_fd ( events , fd , data ) ;
if ( result )
printk ( " epollctl add err fd %d, %s \n " , fd , strerror ( errno ) ) ;
return result ;
2006-03-27 01:14:30 -08:00
}
2017-11-20 21:17:58 +00:00
/*
* Helper to mod the fd event mask and / or data backreference
*/
int os_mod_epoll_fd ( int events , int fd , void * data )
2006-03-27 01:14:30 -08:00
{
2017-11-20 21:17:58 +00:00
struct epoll_event event ;
int result ;
event . data . ptr = data ;
event . events = events ;
result = epoll_ctl ( epollfd , EPOLL_CTL_MOD , fd , & event ) ;
if ( result )
printk ( UM_KERN_ERR
" epollctl mod err fd %d, %s \n " , fd , strerror ( errno ) ) ;
return result ;
2006-03-27 01:14:30 -08:00
}
2017-11-20 21:17:58 +00:00
/*
* Helper to delete the epoll fd
*/
int os_del_epoll_fd ( int fd )
2006-03-27 01:14:30 -08:00
{
2017-11-20 21:17:58 +00:00
struct epoll_event event ;
int result ;
/* This is quiet as we use this as IO ON/OFF - so it is often
* invoked on a non - existent fd
*/
result = epoll_ctl ( epollfd , EPOLL_CTL_DEL , fd , & event ) ;
return result ;
2006-03-27 01:14:30 -08:00
}
void os_set_ioignore ( void )
{
2006-09-25 23:33:04 -07:00
signal ( SIGIO , SIG_IGN ) ;
2006-03-27 01:14:30 -08:00
}
2017-11-20 21:17:58 +00:00
void os_close_epoll_fd ( void )
{
/* Needed so we do not leak an fd when rebooting */
os_close_file ( epollfd ) ;
}