www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - volatile variables in D....

reply Forest Ray <disto flying-guillotine.com> writes:
What is the correct way to impliment a volatile variable ala C++ in D?  For
example an ISR which triggers
every 1 ms does some work and increments a heartbeat variable.  How does one
define this?  In C++ you
would define it as "volatile unsigned int timer_1ms;" and all referance would
aways read from/write to the
memory location.  In D do you have to use the volatile key word on every
statement that access this
variable?  That would be rather klunky and error prone, not to mention gdc does
not always do the correct
thing.  Now that D is getting proper 'const', maybe it should get proper
'volatile'.

Mark
Apr 11 2007
next sibling parent reply "David B. Held" <dheld codelogicconsulting.com> writes:
Forest Ray wrote:
 What is the correct way to impliment a volatile variable ala C++ in D?  For
example an ISR which triggers
 every 1 ms does some work and increments a heartbeat variable.  How does one
define this?  In C++ you
 would define it as "volatile unsigned int timer_1ms;" and all referance would
aways read from/write to the
 memory location.  In D do you have to use the volatile key word on every
statement that access this
 variable?  That would be rather klunky and error prone, not to mention gdc
does not always do the correct
 thing.  Now that D is getting proper 'const', maybe it should get proper
'volatile'.

In fact, C++'s 'volatile' isn't guaranteed to do the right thing because C++ doesn't define a memory model which would be necessary to define what The Right Thing even is. Java made the same mistake at first, but later fixed the standard to properly define 'volatile'. While setting up memory barriers etc. to make volatile work properly might seem like a quick and easy solution, I think we need to think carefully about what multithreading primitives really give the most benefit. In this case, you basically want volatile to give you a cheap form of atomic increment. However, I would suggest that if you really need the accuracy of atomic increment, then you should consider a primitive like CAS instead: int count = 0; asm { MOV EBX, &count; MOV EAX, [EBX]; Retry: MOV EDX, EAX; INC EDX; CMPXCHG [EBX], EDX; JNZ Retry; } My x86 asm is pretty rusty, so this might be completely bogus code, but it should give you an idea of what I mean. Dave
Apr 11 2007
parent reply Forest Ray <disto flying-guillotine.com> writes:
I am NOT asking for an atomic increment or access.  What volatile guarantees is
that the variable is always read from memory or written to memory for each
access.  The ISR routine increments the timer variable
every 1 ms.  The user space application (which will be getting interrupted
every 1 ms) checks the variable to schedule events...this is not relying on
atomic access.

== Quote from David B. Held (dheld codelogicconsulting.com)'s article
 In fact, C++'s 'volatile' isn't guaranteed to do the right thing because
 C++ doesn't define a memory model which would be necessary to define
 what The Right Thing even is.  Java made the same mistake at first, but
 later fixed the standard to properly define 'volatile'.  While setting
 up memory barriers etc. to make volatile work properly might seem like a
 quick and easy solution, I think we need to think carefully about what
 multithreading primitives really give the most benefit.
 In this case, you basically want volatile to give you a cheap form of
 atomic increment.  However, I would suggest that if you really need the
 accuracy of atomic increment, then you should consider a primitive like
 CAS instead:
 int count = 0;
 asm
 {
      MOV EBX, &count;
      MOV EAX, [EBX];
 Retry:
      MOV EDX, EAX;
      INC EDX;
      CMPXCHG [EBX], EDX;
      JNZ Retry;
 }
 My x86 asm is pretty rusty, so this might be completely bogus code, but
 it should give you an idea of what I mean.
 Dave

Apr 12 2007
parent reply "Frank Benoit (keinfarbton)" <benoit tionex.removethispart.de> writes:
is it this you are looking for?
http://www.digitalmars.com/d/statement.html#VolatileStatement
Apr 12 2007
parent reply Sean Kelly <sean f4.ca> writes:
Frank Benoit (keinfarbton) wrote:
 is it this you are looking for?
 http://www.digitalmars.com/d/statement.html#VolatileStatement

Technically no, but it should achieve the same thing. Given the functionality of the volatile statement in D: int* io = 0x1234; int x; volatile x = *io; implicitly guarantees that the load from *io will always occur from memory rather than from a cached register value. I know it's not as convenient as labeling a variable as volatile as per C/C++, but it should do. Sean
Apr 12 2007
parent reply Sean Kelly <sean f4.ca> writes:
Sean Kelly wrote:
 Frank Benoit (keinfarbton) wrote:
 is it this you are looking for?
 http://www.digitalmars.com/d/statement.html#VolatileStatement

Technically no, but it should achieve the same thing. Given the functionality of the volatile statement in D: int* io = 0x1234; int x; volatile x = *io; implicitly guarantees that the load from *io will always occur from memory rather than from a cached register value. I know it's not as convenient as labeling a variable as volatile as per C/C++, but it should do.

Oh, if you're so inclined, tango.core.Atomic in Tango should achieve the same result, even though it's intended for multithreading as well. Use "atomicLoad!(msync.raw)(val)" and it will always load 'val' from memory. This module currently only supports x86 however. If you (or anyone else) needs support for other platforms, please let me know. And if you're really inclined, perhaps supply a .c or .S file with the stuff I'd need to call for that platform. Sean
Apr 12 2007
parent reply Derek Parnell <derek psych.ward> writes:
On Thu, 12 Apr 2007 08:18:48 -0700, Sean Kelly wrote:

 Oh, if you're so inclined, tango.core.Atomic in Tango should achieve the 
 same result ...

I'm sure now that the people trying to help the OP just are not understanding the problem. The problem is that in D, one must code the 'volatile' keyword on *EVERY* access of the variable if one wants to force the compiler to do real memory fetch and store operations, otherwise the compiler /might/ cache a fetch or store value when it optimizes the machine code. The OP was asking for a shorthand way to do this ... namely apply the 'volatile' keyword to a variable so that the compiler will behave as if the coder had used 'volatile' on each and every access to that variable. -- Derek Parnell Melbourne, Australia "Justice for David Hicks!" skype: derek.j.parnell
Apr 12 2007
parent reply Sean Kelly <sean f4.ca> writes:
Derek Parnell wrote:
 On Thu, 12 Apr 2007 08:18:48 -0700, Sean Kelly wrote:
 
 Oh, if you're so inclined, tango.core.Atomic in Tango should achieve the 
 same result ...

I'm sure now that the people trying to help the OP just are not understanding the problem.

Perhaps in other cases, that's true.
 The problem is that in D, one must code the 'volatile' keyword on *EVERY*
 access of the variable if one wants to force the compiler to do real memory
 fetch and store operations, otherwise the compiler /might/ cache a fetch or
 store value when it optimizes the machine code. The OP was asking for a
 shorthand way to do this ... namely apply the 'volatile' keyword to a
 variable so that the compiler will behave as if the coder had used
 'volatile' on each and every access to that variable. 

Yup. But given that no such feature exists in D right now, I was suggesting alternatives. Sean
Apr 12 2007
parent Sean Kelly <sean f4.ca> writes:
Sean Kelly wrote:
 
 Yup.  But given that no such feature exists in D right now, I was 
 suggesting alternatives.

For what it's worth, I don't think the C++ implementation of 'volatile' is really ideal. Qualifying something as 'volatile' has a viral effect on code, and overloading and such can become fairly complicated. Also, the requirements for memory mapped io are a subset of the requirements for multithreaded programming, so by properly addressing multithreading I think memory mapped io will be supported "for free." The C++ 0x discussions seem pretty promising here, so perhaps something similar will be done in D once the dust settles a bit in the C++ arena. In short, I agree that something more than the 'volatile' statement we have in D now would be useful, and suspect we'll get something before too terribly long. In the interim, I would probably implement a value "proxy" struct to simplify things. Sean
Apr 12 2007
prev sibling parent reply Davidl <Davidl 126.com> writes:
worth consideration!!
And the volatile statement we have now is completely not usable compare to
C++'s volatile prefix vars

 What is the correct way to impliment a volatile variable ala C++ in D?   
 For example an ISR which triggers
 every 1 ms does some work and increments a heartbeat variable.  How does  
 one define this?  In C++ you
 would define it as "volatile unsigned int timer_1ms;" and all referance  
 would aways read from/write to the
 memory location.  In D do you have to use the volatile key word on every  
 statement that access this
 variable?  That would be rather klunky and error prone, not to mention  
 gdc does not always do the correct
 thing.  Now that D is getting proper 'const', maybe it should get proper  
 'volatile'.

 Mark

Apr 12 2007
next sibling parent Sean Kelly <sean f4.ca> writes:
Davidl wrote:
 worth consideration!!
 And the volatile statement we have now is completely not usable compare to
 C++'s volatile prefix vars

If you mean for the actual purpose of volatile in C++ (reading from IO memory and such) then that's debatable. But C++ volatile is currently useless for multithreading, though Microsoft has extended the guarantees so it will work in some circumstances. Sean
Apr 12 2007
prev sibling parent reply Forest Ray <disto flying-guillotine.com> writes:
Here is a more concrete example which should not get confused with atomic
access.  I am an embedded/OS programmer.  I have to use memory mapped devices
all of the time.  In C/C++ I must declare references to these address as
volatile pointers otherwise the compiler may NOT actually access that address. 
An optomizing compiler will cache the value from the first reference and not
read/write the other accesses.  For example, I have a serial port device mapped
into my address space:

volatile unsigned char* serial_base = 0x00000020;

then I need to read 3 character from the serial port:

x = *serial_base;
y = *serial_base;
z = *serial_base;

If serial_base is NOT volatile and I have a modern optimizing compiler x, y,
and z will all have the same value as serial_base was only accessed once.  The
first memory load from serial_base is stored in x then copied to y and z. 
volatile tells the compiler not to optimize the serial_base variable and always
read from/write to it.

If D is to be considered in the embedded enviroment this has to be addressed. 
D's volatile statement is error prone, I would have to declare each STATEMENT
that used serial_base as volatile, that is horrible.



Davidl Wrote:

 worth consideration!!
 And the volatile statement we have now is completely not usable compare to
 C++'s volatile prefix vars
 
 What is the correct way to impliment a volatile variable ala C++ in D?   
 For example an ISR which triggers
 every 1 ms does some work and increments a heartbeat variable.  How does  
 one define this?  In C++ you
 would define it as "volatile unsigned int timer_1ms;" and all referance  
 would aways read from/write to the
 memory location.  In D do you have to use the volatile key word on every  
 statement that access this
 variable?  That would be rather klunky and error prone, not to mention  
 gdc does not always do the correct
 thing.  Now that D is getting proper 'const', maybe it should get proper  
 'volatile'.

 Mark


Apr 12 2007
parent Rory McGuire <rjmcguire gmail.com> writes:
Wouldn't it be better to have an object which represents the actual device/port
that you are reading/writing?
This would also make the code's actions more obvious.

class Port { // (Could also be a struct)
    size_t port; // this is a pointer to the memory mapped io port

    this(size_t port) {
        this.port = port;
    }
    byte read() {
        volatile return *port;
    }
    void write(byte value) {
        volatile *port = value;
    }
}

Anyone still reading this thread?
Mar 19 2008