Project Home
Project Home
Documents
Documents
Wiki
Wiki
Discussion Forums
Discussions
Project Information
Project Info
Forum Topic - InterruptAttach and InterruptWait source: (11 Items)
   
InterruptAttach and InterruptWait source  
Hello,
I cannot find source code of InterruptAttach and InterruptWait functions. Is it available?

Regards,
Mike
Re: InterruptAttach and InterruptWait source  
Hi,

InterruptAttach and InterruptWait are kernel calls. The definition for these two can be found in  /lib/c/kercalls/
mkkercalls  , lines 141 and 144, respectively. The 'source' code (or rather, the code-generation code) is mainly to be 
found in the file 
   $(CPU)/template 

Regards,
- Thomas
Re: InterruptAttach and InterruptWait source  
Thank you Thomas!

Regards,
Mike
Re: InterruptAttach and InterruptWait source  
On Fri, 2009-12-25 at 16:57 -0500, Thomas Haupt wrote:
> InterruptAttach and InterruptWait are kernel calls. The definition for
> these two can be found in  /lib/c/kercalls/mkkercalls  , lines 141 and
> 144, respectively. The 'source' code (or rather, the code-generation
> code) is mainly to be found in the file 
>    $(CPU)/template 

As you may already have worked out from Thomas' good advice, the "real"
implementation for these kernel calls is found in
services/system/ker/ker_interrupt.c (ker_interrupt_attach() and
ker_interrupt_wait() respectively).

Regards,
Neil
Re: InterruptAttach and InterruptWait source  
Thanks, Neil.
I've asked because I prefer to do "printf" (or step by gdb) in ISR of driver code. Tracing is not so convenient for me. 
Today I use simple emulation of InterruptAttach call via code with InterruptWait and InterruptAttachEvent in separate 
thread. But I need to include this implementation of "my InterruptAttach" every time in my driver while debugging. So I 
thought to include it in my own "isr_debug_enabled" version of libc to have no changes in original code of a driver.
Now I see it is not so easy as I thought :).. Another way I see to put lib with my code before libc.so during build 
process.. I had not check if it could work..

Regards,
Mike
Re: InterruptAttach and InterruptWait source  
You may be able to use LD_PRELOAD to arrange to load your debugging
version first, but it may depend on exactly what your code needs to do.
Re: InterruptAttach and InterruptWait source  
I was tempted to suggest LD_PRELOAD as well, it would work well for overloading selected libc functions.

Problem is that your own implementation of InterruptAttach() would want to do an InterruptAttachEvent() - and that in 
turn uses InterruptAttach() with a NULL handler function and a sigevent for the data.

So to not end up in an infinite recursion, you'd need to call the 'real' InterruptAttach() when the <handler> argument 
is NULL -- but how could you do that? 

Of course, you could integrate appropriate kernel calls for all platforms into your lib - then you could use it by mere 
dynamic preloading.

If don't want to go that way, you could still 'wrap' the InterruptAttach() function at link time; look at ld's '--wrap' 
option.

You'd call your own function __wrap_InterruptAttach() and could (from within that) still call __real_InterruptAttach() 
to do the work. At build time, you'd have to feed '-Wl,--wrap InterruptAttach' to qcc. Of course, that would at least 
require a relink.

- Thomas
Re: InterruptAttach and InterruptWait source  
Thomas makes some really excellent points, all of which are viable.
Depending on exactly what you're doing, you may be able to get away with
an LD_PRELOAD coupled with a dlopen()/dlsym() redirect to the real
InterruptAttach() - but as Thomas points out, it is probably simpler to
just code the kernel call directly :-)

Since you have access to the object code, the -Wl,--wrap= option would
probably be simplest.  And, with a little sleight-of-hand, it could be
made to work both without needing to relink: put __real_foo() in a
shared library and either manually swap libraries or use LD_PRELOAD to
switch them.  (Depending on exactly what else you're wrapping, if
anything, you may need to statically link some bits of libc, though, so
that they also redirect through the wrapped function.)

Regards,
Neil
Re: InterruptAttach and InterruptWait source  
Oh.. I have not thought about infinite loop.. It could be a bug :) Thanks.
Direct kernel call rewriting sounds good but I am not sure how to design it in my case.. at this moment..
'--wrap' option is interesting too. I will try both.

Since "debug" part of driver code is my own research and it's not in release code I don't think any license could be 
disturb if I publish "debug" one.

//--------------------------------------------------------------------------------------------------

// To init interrupt I use following code:

	pub.isr_handler = can_intr;
	pub.isr_area = devinfo;
	ccan_isr_wrapper();

// ..instead of

	devinfo->iidsys = InterruptAttach( pub.irq, can_intr, devinfo, 0, 0);
	if(devinfo->iidsys == -1)
	{
		perror("InterruptAttach irqsys");
		exit(EXIT_FAILURE);
	}

// "pub" and "spec" are just shared global structures

// Below you could see how wrapper works

/*
* Service InterruptAttach ISR in InterrruptAttachEvent wrapper
* This is for debugging purpose. You can debug your ISR step by step
* and after that put it to InterruptAttach for speed or let it stands
* as is. You must set following settings before:
* pub.irq
* pub.isr_handler
* pub.isr_area
*/
int ccan_isr_wrapper( void )
{
	pthread_attr_t attr;
	int rez = 0;

	// Create thread for ISR
	pthread_attr_init( &attr );
	pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );
	rez = pthread_create( &spec.isr_tid, &attr, &ccan_isr_thread, NULL );
	return rez; // see errno for detail
}

/*
*  Separate thread for ISR handling
*/
void* ccan_isr_thread( void * arg )
{
	struct sigevent si, *rsi;

	SIGEV_INTR_INIT( &si );
	InterruptAttachEvent( pub.irq, &si, 0 );
	spec.isr_run = 1;

	while( spec.isr_run )
	{
		InterruptWait( 0, NULL );
		rsi = (*pub.isr_handler)( pub.isr_area, spec.iid );
		if( rsi != NULL )
		{
			if( SIGEV_GET_TYPE( rsi ) == SIGEV_PULSE)
			{
				MsgSendPulse( rsi->sigev_coid, rsi->sigev_priority, rsi->sigev_code, rsi->sigev_value.sival_int );
			}

		}
		InterruptUnmask( pub.irq, spec.iid );
	}

	InterruptDetach( spec.iid );
	return NULL;
}

//--------------------------------------------------------------------------------------------------

Regards,
Mike
Re: InterruptAttach and InterruptWait source  
Oh.. I have not thought about infinite loop.. It could be a bug :)  
Thanks.
Direct kernel call rewriting sounds good but I am sure how to design  
it in my way.. at this moment..
Wrap option is interesting too. I will try to look at both.

Since "debug" part of driver code is my own research and it's not in  
release code I don't think any license could be disturb if I publish  
"debug" one.

//--------------------------------------------------------------------------------------------------

// To init interrupt I use following code:

	pub.isr_handler = can_intr;
	pub.isr_area = devinfo;
	ccan_isr_wrapper();

// ..instead of

	devinfo->iidsys = InterruptAttach( pub.irq, can_intr, devinfo, 0, 0);
	if(devinfo->iidsys == -1)
	{
		perror("InterruptAttach irqsys");
		exit(EXIT_FAILURE);
	}

// "pub" and "spec" are just shared global structures

// Below you could see how wrapper works

/*
  * Service InterruptAttach ISR in InterrruptAttachEvent wrapper
  * This for debugging purpose. You can debug your ISR step by step
  * and after that put it to InterruptAttach for speed or let it stands
  * as is. You must set following settings before:
  * pub.irq
  * pub.isr_handler
  * pub.isr_area
  */
int ccan_isr_wrapper( void )
{
	pthread_attr_t attr;
	int rez = 0;

	// Create thread for ISR
	pthread_attr_init( &attr );
	pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );
	rez = pthread_create( &spec.isr_tid, &attr, &ccan_isr_thread, NULL );
	return rez; // see errno for detail
}

/*
  *  Separate thread for ISR handling
  */
void* ccan_isr_thread( void * arg )
{
	struct sigevent si, *rsi;

	SIGEV_INTR_INIT( &si );
	InterruptAttachEvent( pub.irq, &si, 0 );
	spec.isr_run = 1;

	while( spec.isr_run )
	{
		InterruptWait( 0, NULL );
		rsi = (*pub.isr_handler)( pub.isr_area, spec.iid );
		if( rsi != NULL )
		{
			if( SIGEV_GET_TYPE( rsi ) == SIGEV_PULSE)
			{
				MsgSendPulse( rsi->sigev_coid, rsi->sigev_priority, rsi- 
 >sigev_code, rsi->sigev_value.sival_int );
			}

		}
		InterruptUnmask( pub.irq, spec.iid );
	}

	InterruptDetach( spec.iid );
	return NULL;
}

//--------------------------------------------------------------------------------------------------

Regards,
Mike
Re: InterruptAttach and InterruptWait source  
Hi Mike,

as Neil so nicely pointed out, you might be able to get the original address off InterruptAttach using  dlopen()  and  
dlsym() .  I tried that, and it seems to work fine -- see code snippet below. You'd have to add your own flesh to these 
bones; also, I'd consider using pulses instead of INTR events; that way, you could carry back information about which 
interrupt had fired. 

The solution shown below can be put into a shared lib and preloaded using LD_PRELOAD - this way, you wouldn't even have 
to relink your applications.

Regards,
- Thomas

-----------------------------------------------------------------------------------------
#include <stdio.h>
#include <errno.h>
#include <dlfcn.h>
#include <sys/neutrino.h>

int InterruptAttach( int intr, const struct sigevent *(* handler)(void *, int),
                     const void * area, int size, unsigned flags ) {
	static int  (*ia)( int intr, const struct sigevent *(* handler)(void *, int),
	                   const void * area, int size, unsigned flags );
	static void  *hdl;
	static int  inhere;
	int  res = 0;

	if ( NULL == ia ) {
		if ( NULL == ( hdl = dlopen( "libc.so.3", RTLD_NOW | RTLD_GLOBAL ) ) )
			return -1;

		if ( NULL == ( ia = dlsym( hdl, "InterruptAttach" ) ) )
			return -1;
	}

	/* ISR provided and not recursive? */
	if ( handler && ! inhere ) {
		inhere = 1;			/* Inhibit recursion */

		/* Do your stuff here */
		errno = ENOSYS;	/* This is while nothing's implemented */
		res = -1;

		inhere = 0;			/* All recursion avoided */

		return res;
	}

	return ia( intr, handler, area, size, flags );
}