2006-03-27 01:14:30 -08:00
/*
* Copyright ( C ) 2000 , 2001 , 2002 Jeff Dike ( jdike @ karaya . com )
* Licensed under the GPL
*/
# include <stdlib.h>
# include <unistd.h>
# include <errno.h>
# include <signal.h>
# include <string.h>
# include <sys/poll.h>
# include <sys/types.h>
# include <sys/time.h>
# include "user.h"
# include "process.h"
# include "sigio.h"
# include "irq_user.h"
# include "os.h"
2006-10-19 23:28:20 -07:00
# include "um_malloc.h"
2006-03-27 01:14:30 -08:00
2007-02-10 01:44:23 -08:00
/*
* Locked by irq_lock in arch / um / kernel / irq . c . Changed by os_create_pollfd
* and os_free_irq_by_cb , which are called under irq_lock .
*/
2006-03-27 01:14:30 -08:00
static struct pollfd * pollfds = NULL ;
static int pollfds_num = 0 ;
static int pollfds_size = 0 ;
int os_waiting_for_events ( struct irq_fd * active_fds )
{
struct irq_fd * irq_fd ;
int i , n , err ;
n = poll ( pollfds , pollfds_num , 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 )
2006-03-27 01:14:30 -08:00
printk ( " sigio_handler: os_waiting_for_events: "
" poll returned %d, errno = %d \n " , n , errno ) ;
return err ;
}
2006-05-01 12:15:57 -07:00
if ( n = = 0 )
2006-03-27 01:14:30 -08:00
return 0 ;
irq_fd = active_fds ;
2006-05-01 12:15:57 -07:00
for ( i = 0 ; i < pollfds_num ; i + + ) {
if ( pollfds [ i ] . revents ! = 0 ) {
2006-03-27 01:14:30 -08:00
irq_fd - > current_events = pollfds [ i ] . revents ;
pollfds [ i ] . fd = - 1 ;
}
irq_fd = irq_fd - > next ;
}
return n ;
}
int os_create_pollfd ( int fd , int events , void * tmp_pfd , int size_tmpfds )
{
if ( pollfds_num = = pollfds_size ) {
if ( size_tmpfds < = pollfds_size * sizeof ( pollfds [ 0 ] ) ) {
/* return min size needed for new pollfds area */
2007-02-10 01:44:23 -08:00
return ( pollfds_size + 1 ) * sizeof ( pollfds [ 0 ] ) ;
2006-03-27 01:14:30 -08:00
}
2006-05-01 12:15:57 -07:00
if ( pollfds ! = NULL ) {
2006-03-27 01:14:30 -08:00
memcpy ( tmp_pfd , pollfds ,
sizeof ( pollfds [ 0 ] ) * pollfds_size ) ;
/* remove old pollfds */
kfree ( pollfds ) ;
}
pollfds = tmp_pfd ;
pollfds_size + + ;
2006-05-01 12:15:57 -07:00
} else
kfree ( tmp_pfd ) ; /* remove not used tmp_pfd */
2006-03-27 01:14:30 -08:00
2006-05-01 12:15:57 -07:00
pollfds [ pollfds_num ] = ( ( struct pollfd ) { . fd = fd ,
. events = events ,
. revents = 0 } ) ;
2006-03-27 01:14:30 -08:00
pollfds_num + + ;
2006-05-01 12:15:57 -07:00
return 0 ;
2006-03-27 01:14:30 -08:00
}
void os_free_irq_by_cb ( int ( * test ) ( struct irq_fd * , void * ) , void * arg ,
struct irq_fd * active_fds , struct irq_fd * * * last_irq_ptr2 )
{
struct irq_fd * * prev ;
int i = 0 ;
prev = & active_fds ;
2006-05-01 12:15:57 -07:00
while ( * prev ! = NULL ) {
if ( ( * test ) ( * prev , arg ) ) {
2006-03-27 01:14:30 -08:00
struct irq_fd * old_fd = * prev ;
2006-05-01 12:15:57 -07:00
if ( ( pollfds [ i ] . fd ! = - 1 ) & &
( pollfds [ i ] . fd ! = ( * prev ) - > fd ) ) {
2006-03-27 01:14:30 -08:00
printk ( " os_free_irq_by_cb - mismatch between "
" active_fds and pollfds, fd %d vs %d \n " ,
( * prev ) - > fd , pollfds [ i ] . fd ) ;
goto out ;
}
pollfds_num - - ;
/* This moves the *whole* array after pollfds[i]
* ( though it doesn ' t spot as such ) !
*/
memmove ( & pollfds [ i ] , & pollfds [ i + 1 ] ,
( pollfds_num - i ) * sizeof ( pollfds [ 0 ] ) ) ;
if ( * last_irq_ptr2 = = & old_fd - > next )
* last_irq_ptr2 = prev ;
* prev = ( * prev ) - > next ;
if ( old_fd - > type = = IRQ_WRITE )
ignore_sigio_fd ( old_fd - > fd ) ;
kfree ( old_fd ) ;
continue ;
}
prev = & ( * prev ) - > next ;
i + + ;
}
out :
return ;
}
int os_get_pollfd ( int i )
{
2006-05-01 12:15:57 -07:00
return pollfds [ i ] . fd ;
2006-03-27 01:14:30 -08:00
}
void os_set_pollfd ( int i , int fd )
{
pollfds [ i ] . fd = fd ;
}
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
}
void init_irq_signals ( int on_sigstack )
{
int flags ;
flags = on_sigstack ? SA_ONSTACK : 0 ;
set_handler ( SIGIO , ( __sighandler_t ) sig_handler , flags | SA_RESTART ,
2007-10-16 01:27:27 -07:00
SIGUSR1 , SIGIO , SIGWINCH , SIGVTALRM , - 1 ) ;
2006-03-27 01:14:30 -08:00
signal ( SIGWINCH , SIG_IGN ) ;
}