This is the mail archive of the crossgcc@cygnus.com mailing list for the crossgcc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Atomic Operations (continuing on from Masking Interrupts?)


>>>>> "David" == David Williams <davidwilliams@ozemail.com.au> writes:

    David> Hi all, Thanks for the helpful suggestions. I have now
    David> implemented some in line assembly with constraints etc. as
    David> suggested to ensure atomic operations.

    David> This started me thinking...(very dangerous!). Some
    David> responses indicated that others have experienced this
    David> 'problem' before. As GCC and support for M68K have been
    David> around for quite some time I assume that a 'fix' in the
    David> compiler is probably difficult.

The problem is that it is impossible for a compiler to infer what you
consider should be atomic.  The best fix (IMO) is to follow the
example of Lisp, and provide a routine such as the following:

	inline void without_pre_emption(void (*routine)()) {
	  assembler_routine_to_disable_interrupts();
	  routine();
	  assembler_routine_to_enable_interrupts();
	}

I also do not believe that the ANSI C or C++ [draft] standard requires 
any particular expressions, such as *foo++ to be atomic operations.
If it did, would then *(*foo++)++ also have to be atomic?  This can go 
on forever!  What if the program is being compiled for a multiuser
system, and the invoking user is not priveledged?  YOu need to guard
against pre-emption a different way that if you are root doing kernel
or driver programming, or that if you are writing on bare metal for an 
embedded target.

The above routine is not even perfect.  Consider that the "routine()"
being called also makes a call to without_pre_emption().  Then the
enable in the call at depth will prematurely enable interrupts and
leave a nasty hole this is not even visable unless you look deeply
into the routine you are calling.

The fix for this problem is to have a counter that increments on
disable, and decrements on enable.  The enable routine will only
actually enable interrupts if the value of the counter is zero.  We
must make sure that the increment and decrement operations are also
atomic; therefore, we must actually disable interrupts before the
counter is incremented in assembler_routine_to_disable_interrupts(),
and decrement before we disable interrupts in
assembler_routine_to_enable_interrupts() (we realize, of course, that
it is an error to call assembler_routine_to_enable_interrupts() when
interrupts are not disabled!), and only actually enable interrupts in
assembler_routine_to_enable_interrupts() is the counter goes to zero.
The counter must be global in C, but should probably be class static
in C++.

-- 
--------  "And there came a writing to him from Elijah"  [2Ch 21:12]  --------
R. J. Brown III  rj@elilabs.com http://www.elilabs.com/~rj  voice 847 543-4060
Elijah Laboratories Inc. 457 Signal Lane, Grayslake IL 60030  fax 847 543-4061
-----  M o d e l i n g   t h e   M e t h o d s   o f   t h e   M i n d  ------
_______________________________________________
New CrossGCC FAQ: http://www.objsw.com/CrossGCC
_______________________________________________
To remove yourself from the crossgcc list, send
mail to crossgcc-request@cygnus.com with the
text 'unsubscribe' (without the quotes) in the
body of the message.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]