Re: Volatile?

Discussion in 'Java' started by Knute Johnson, Jul 1, 2003.

  1. Roedy Green wrote:
    > On Mon, 30 Jun 2003 15:05:27 -0700, Knute Johnson
    > <> wrote or quoted :
    >
    >
    >>I've got a class that has a public int variable. I've declared it
    >>public volatile int. I have to change this variable and read this
    >>variable from both the EDT and the run() of another thread. Is the
    >>volatile declaration adequate to ensure that I won't get it mid-update
    >>or do I need to synchronize it too?

    >
    >
    > See http://mindprod.com/jgloss/thread.html
    > and http://mindprod.com/jgloss/threadsafe.html
    >
    > That question takes a whole book to answer properly.
    >


    Well, let me define my problem a little more closely. This int gets
    changed in a MouseListener on the mousePressed() and changed again in
    the mouseReleased(). Is it possible that the mouseReleased() happens
    before the mousePressed()? The int is used as an index for an array and
    once in a blue moon it ends up negative and blows up my app. My code
    relies on the fact that mousePressed() is going to occur before
    mouseReleased() and that both methods are working on the same value for
    the int. I thought the volatile would assure the latter.

    Thanks,

    --

    Knute Johnson
    email s/nospam/knute/
    Molon labe...
    Knute Johnson, Jul 1, 2003
    #1
    1. Advertising

  2. Knute Johnson

    Adam Maass Guest

    "Knute Johnson" <> wrote:
    > Roedy Green wrote:
    > > On Mon, 30 Jun 2003 15:05:27 -0700, Knute Johnson
    > > <> wrote or quoted :
    > >
    > >
    > >>I've got a class that has a public int variable. I've declared it
    > >>public volatile int. I have to change this variable and read this
    > >>variable from both the EDT and the run() of another thread. Is the
    > >>volatile declaration adequate to ensure that I won't get it mid-update
    > >>or do I need to synchronize it too?

    > >
    > >
    > > See http://mindprod.com/jgloss/thread.html
    > > and http://mindprod.com/jgloss/threadsafe.html
    > >
    > > That question takes a whole book to answer properly.
    > >

    >
    > Well, let me define my problem a little more closely. This int gets
    > changed in a MouseListener on the mousePressed() and changed again in
    > the mouseReleased(). Is it possible that the mouseReleased() happens
    > before the mousePressed()? The int is used as an index for an array and
    > once in a blue moon it ends up negative and blows up my app. My code
    > relies on the fact that mousePressed() is going to occur before
    > mouseReleased() and that both methods are working on the same value for
    > the int. I thought the volatile would assure the latter.
    >


    VMs (indeed processors in general) are free to re-order variable fetch and
    set sequences with respect to other operations -- as long as ANY ONE THREAD
    sees fetches and sets of that variable in the correct order. Volatile merely
    requires the VM to fetch the variable from main memory each time (rather
    than read from some thread-specific cache). It is conceivable that the EDT
    thread could make an update to the variable, but not flush it to main
    memory; the run() method of your other thread would never see the update
    despite the variable being declared volatile.

    The short answer: access to the variable must be synchronized;
    synchronization forces updates to be flushed to main memory, among other
    things.


    You also need to assure yourself that mousePressed() will absolutely always
    occur before, and also will absolutely always have a corresponding,
    mouseReleased(). It's been a long time since I've done any AWT or Swing
    programming, so I can't help answer that question.


    -- Adam Maass
    Adam Maass, Jul 1, 2003
    #2
    1. Advertising

  3. Knute Johnson

    Brian Kildea Guest

    Knute,

    There's a couple of parts to the answer:

    1) Is it possible that the mouseReleased() happens before the
    mousePressed()?

    No, assuming that you only let Swing call the mouse methods, Swing will
    guarantee the order in which it calls these two methods for a single act of
    clicking the mouse. All bets are off if you start calling these methods
    yourself.

    2) Is the volatile declaration adequate to ensure that I won't get it
    mid-update or do I need to synchronize it too?

    The volatile keyword is not sufficient. This keyword is simply a directive
    to Java to not attempt to optimize the loading of this value. Otherwise,
    Java optimization may employ a caching technique. Without the volatile
    keyword, thread 1 could set the integer value and retain its value in a
    register. Thread 2 could preempt thread one and also set its value. When
    thread one resumed, if it used the integer again, Java may pull its value
    from the register, rather than loading in the changed value from memory. The
    volatile keyword forces the value to be obtained from memory, thus using the
    value for the integer as modified by thread 2.

    I never heard that thing about all 32 bit types being updated atomically.
    Even if it does, I am sure that it would refer to just a simple operation,
    and would be meaningless if your assignment was anything other than the
    simplest form of assignment. For example,

    someInt = (someInt ^ 2) / ( PI * (someInt - 1 ) );

    would definitely not be atomic.

    Regardless, 'volatile' doesn't deal with the atomic issue. In fact, using
    my thread 1 / thread 2 example, volatile guarantees that thread 1 will use
    the value for the integer that was assigned to it by thread 2. So, yes, you
    must synchronize.

    -Brian

    "Knute Johnson" <> wrote in message
    news:...
    > Roedy Green wrote:
    > > On Mon, 30 Jun 2003 15:05:27 -0700, Knute Johnson
    > > <> wrote or quoted :
    > >
    > >
    > >>I've got a class that has a public int variable. I've declared it
    > >>public volatile int. I have to change this variable and read this
    > >>variable from both the EDT and the run() of another thread. Is the
    > >>volatile declaration adequate to ensure that I won't get it mid-update
    > >>or do I need to synchronize it too?

    > >
    > >
    > > See http://mindprod.com/jgloss/thread.html
    > > and http://mindprod.com/jgloss/threadsafe.html
    > >
    > > That question takes a whole book to answer properly.
    > >

    >
    > Well, let me define my problem a little more closely. This int gets
    > changed in a MouseListener on the mousePressed() and changed again in
    > the mouseReleased(). Is it possible that the mouseReleased() happens
    > before the mousePressed()? The int is used as an index for an array and
    > once in a blue moon it ends up negative and blows up my app. My code
    > relies on the fact that mousePressed() is going to occur before
    > mouseReleased() and that both methods are working on the same value for
    > the int. I thought the volatile would assure the latter.
    >
    > Thanks,
    >
    > --
    >
    > Knute Johnson
    > email s/nospam/knute/
    > Molon labe...
    >
    Brian Kildea, Jul 1, 2003
    #3
  4. Knute Johnson

    Roedy Green Guest

    On Mon, 30 Jun 2003 21:26:07 -0700, "Adam Maass"
    <> wrote or quoted :

    > It is conceivable that the EDT
    >thread could make an update to the variable, but not flush it to main
    >memory; the run() method of your other thread would never see the update
    >despite the variable being declared volatile.



    Does not volatile also force frequent flushing?

    --
    Canadian Mind Products, Roedy Green.
    Coaching, problem solving, economical contract programming.
    See http://mindprod.com/jgloss/jgloss.html for The Java Glossary.
    Roedy Green, Jul 1, 2003
    #4
  5. Knute Johnson

    Jon Skeet Guest

    Adam Maass <> wrote:

    > It is conceivable that the EDT
    > thread could make an update to the variable, but not flush it to main
    > memory; the run() method of your other thread would never see the update
    > despite the variable being declared volatile.


    Not according to the spec:

    <quote>
    The rules for volatile variables effectively require that main memory
    be touched exactly once for each use or assign of a volatile variable
    by a thread, and that main memory be touched in exactly the order
    dictated by the thread execution semantics.
    </quote>

    --
    Jon Skeet - <>
    http://www.pobox.com/~skeet/
    If replying to the group, please do not mail me too
    Jon Skeet, Jul 1, 2003
    #5
  6. Knute Johnson

    Jon Skeet Guest

    Brian Kildea <> wrote:
    > I never heard that thing about all 32 bit types being updated atomically.


    From section 17.1 of the JLS:

    <quote>
    For the purposes of this chapter, the verbs use, assign, load, store,
    lock, and unlock name actions that a thread can perform. The verbs
    read, write, lock, and unlock name actions that the main memory
    subsystem can perform. Each of these actions is atomic (indivisible).
    </quote>

    and about double/long:

    <quote>
    If a double or long variable is not declared volatile, then for the
    purposes of load, store, read, and write actions they are treated as if
    they were two variables of 32 bits each: wherever the rules require one
    of these actions, two such actions are performed, one for each 32-bit
    half. The manner in which the 64 bits of a double or long variable are
    encoded into two 32-bit quantities is implementation-dependent. The
    load, store, read, and write actions on volatile variables are atomic,
    even if the type of the variable is double or long.
    </quote>

    In other words, any value other than a long or a double is atomically
    assigned/fetched. That also includes references, even if the native
    length of the reference is more than 32 bits.

    > Even if it does, I am sure that it would refer to just a simple operation,
    > and would be meaningless if your assignment was anything other than the
    > simplest form of assignment. For example,
    >
    > someInt = (someInt ^ 2) / ( PI * (someInt - 1 ) );
    >
    > would definitely not be atomic.


    The assignment would be atomic, and each of the fetches would be
    atomic, but yes, it's possible that the two "someInt" values fetched
    would be different.

    --
    Jon Skeet - <>
    http://www.pobox.com/~skeet/
    If replying to the group, please do not mail me too
    Jon Skeet, Jul 1, 2003
    #6
  7. Thanks everybody for the replies. I think I'm going to synchronize my
    int variable. The problem I'm having that is caused by this is very
    intermittent but I think that is do to luck.

    --

    Knute Johnson
    email s/nospam/knute/
    Molon labe...
    Knute Johnson, Jul 1, 2003
    #7
  8. synchronized? was:Re: Volatile?

    Knute Johnson wrote:
    > Thanks everybody for the replies. I think I'm going to synchronize my
    > int variable. The problem I'm having that is caused by this is very
    > intermittent but I think that is do to luck.
    >


    So now I've come up on some architecture issues. My public volatile int
    is in one class and I access it from another class. Both classes modify
    the int. If I synchronize on "this" in its class and on the reference
    variable from the other class, is it synchronized? Thanks very much.

    class a {
    public volatile int x;

    public void run() {
    synchronized (this) {
    x = 1234;
    }
    }
    }

    class b {
    a aa = new a();

    public void run() {
    synchronized (aa) {
    aa.x = 4321;
    }
    }
    }

    --

    Knute Johnson
    email s/nospam/knute/
    Molon labe...
    Knute Johnson, Jul 1, 2003
    #8
  9. Knute Johnson

    Roedy Green Guest

    On Tue, 1 Jul 2003 09:41:27 +0100, Jon Skeet <> wrote
    or quoted :

    >The rules for volatile variables effectively require that main memory
    >be touched exactly once for each use or assign of a volatile variable
    >by a thread, and that main memory be touched in exactly the order
    >dictated by the thread execution semantics.


    In English, I think that means:


    The compiler/JVM does not cache volatile values in registers. On
    every use, it fetches the value from main shared RAM. On every
    assignment it saves the value to main shared RAM.

    In a multi cpu machine with cache coherency, the value may not
    actually be stored all the way back to RAM, but logically it is.

    --
    Canadian Mind Products, Roedy Green.
    Coaching, problem solving, economical contract programming.
    See http://mindprod.com/jgloss/jgloss.html for The Java Glossary.
    Roedy Green, Jul 1, 2003
    #9
  10. Knute Johnson

    Roedy Green Guest

    Re: synchronized? was:Re: Volatile?

    On Tue, 01 Jul 2003 09:56:56 -0700, Knute Johnson
    <> wrote or quoted :

    > Both classes modify
    >the int. If I synchronize on "this" in its class and on the reference
    >variable from the other class, is it synchronized?


    think of synchronised as like temporarily locking an object to have
    exclusive access to it for modifications or study.

    Your threads then lock the object containing the shared info.

    For a quick overview of how all this works, see
    http://mindprod.com/jgloss/threadsafe.html
    and http://mindprod.com/jgloss/thread.html

    For a deeper explanation buy Doug Lea's book mentioned there.

    --
    Canadian Mind Products, Roedy Green.
    Coaching, problem solving, economical contract programming.
    See http://mindprod.com/jgloss/jgloss.html for The Java Glossary.
    Roedy Green, Jul 1, 2003
    #10
  11. Knute Johnson

    hh Guest

    Re: synchronized? was:Re: Volatile?

    Knute Johnson wrote:
    > Knute Johnson wrote:
    >
    >> Thanks everybody for the replies. I think I'm going to synchronize my
    >> int variable. The problem I'm having that is caused by this is very
    >> intermittent but I think that is do to luck.
    >>

    >
    > So now I've come up on some architecture issues. My public volatile int
    > is in one class and I access it from another class. Both classes modify
    > the int. If I synchronize on "this" in its class and on the reference
    > variable from the other class, is it synchronized? Thanks very much.
    >
    > class a {
    > public volatile int x;
    >
    > public void run() {
    > synchronized (this) {
    > x = 1234;
    > }
    > }
    > }
    >
    > class b {
    > a aa = new a();
    >
    > public void run() {
    > synchronized (aa) {
    > aa.x = 4321;
    > }
    > }
    > }
    >



    class a
    {
    private int x;

    public synchronized void setX(int value)
    {
    x = value;
    }

    public void run()
    {
    setX(1234);

    ..
    ..
    hh, Jul 1, 2003
    #11
  12. Re: synchronized? was:Re: Volatile?

    hh wrote:
    > Knute Johnson wrote:
    >
    >> Knute Johnson wrote:
    >>
    >>> Thanks everybody for the replies. I think I'm going to synchronize
    >>> my int variable. The problem I'm having that is caused by this is
    >>> very intermittent but I think that is do to luck.
    >>>

    >>
    >> So now I've come up on some architecture issues. My public volatile
    >> int is in one class and I access it from another class. Both classes
    >> modify the int. If I synchronize on "this" in its class and on the
    >> reference variable from the other class, is it synchronized? Thanks
    >> very much.
    >>
    >> class a {
    >> public volatile int x;
    >>
    >> public void run() {
    >> synchronized (this) {
    >> x = 1234;
    >> }
    >> }
    >> }
    >>
    >> class b {
    >> a aa = new a();
    >>
    >> public void run() {
    >> synchronized (aa) {
    >> aa.x = 4321;
    >> }
    >> }
    >> }
    >>

    >
    >
    > class a
    > {
    > private int x;
    >
    > public synchronized void setX(int value)
    > {
    > x = value;
    > }
    >
    > public void run()
    > {
    > setX(1234);
    >
    > ..
    > ..
    >


    I appreciate the response but this doesn't address my question. I want
    to know if something in class a synchronized on "this" will be
    synchronized with an instance of class a that is referenced from class b.

    --

    Knute Johnson
    email s/nospam/knute/
    Molon labe...
    Knute Johnson, Jul 2, 2003
    #12
  13. Knute Johnson

    Brian Kildea Guest

    Re: synchronized? was:Re: Volatile?

    "Knute Johnson" <> wrote in message
    news:...
    > hh wrote:
    > > Knute Johnson wrote:
    > >
    > >> Knute Johnson wrote:
    > >>
    > >>> Thanks everybody for the replies. I think I'm going to synchronize
    > >>> my int variable. The problem I'm having that is caused by this is
    > >>> very intermittent but I think that is do to luck.
    > >>>
    > >>
    > >> So now I've come up on some architecture issues. My public volatile
    > >> int is in one class and I access it from another class. Both classes
    > >> modify the int. If I synchronize on "this" in its class and on the
    > >> reference variable from the other class, is it synchronized? Thanks
    > >> very much.
    > >>
    > >> class a {
    > >> public volatile int x;
    > >>
    > >> public void run() {
    > >> synchronized (this) {
    > >> x = 1234;
    > >> }
    > >> }
    > >> }
    > >>
    > >> class b {
    > >> a aa = new a();
    > >>
    > >> public void run() {
    > >> synchronized (aa) {
    > >> aa.x = 4321;
    > >> }
    > >> }
    > >> }
    > >>

    > >
    > >
    > > class a
    > > {
    > > private int x;
    > >
    > > public synchronized void setX(int value)
    > > {
    > > x = value;
    > > }
    > >
    > > public void run()
    > > {
    > > setX(1234);
    > >
    > > ..
    > > ..
    > >

    >
    > I appreciate the response but this doesn't address my question. I want
    > to know if something in class a synchronized on "this" will be
    > synchronized with an instance of class a that is referenced from class b.
    >
    > --
    >
    > Knute Johnson
    > email s/nospam/knute/
    > Molon labe...
    >


    As long as you synchronize the setX method on this, all should be well. You
    do not need to synchronize on aa in class b before calling setX from class
    b, although this should work, and have no ill effect.

    Brian
    Brian Kildea, Jul 2, 2003
    #13
  14. Re: synchronized? was:Re: Volatile?

    I dont know but anyway, it seems to be a bad practice to lock an object fron
    outside.

    class a {
    public volatile int x;

    public void run() {
    synchronized (this) {
    x = 1234;
    }
    }
    public synchronized void setX( x_) {
    x = x_;
    }
    }

    class b {
    a aa = new a();

    public void run() {
    aa.setX(4321);
    }
    }
    }



    "Knute Johnson" <> a écrit dans le message news:
    ...
    > Knute Johnson wrote:
    > > Thanks everybody for the replies. I think I'm going to synchronize my
    > > int variable. The problem I'm having that is caused by this is very
    > > intermittent but I think that is do to luck.
    > >

    >
    > So now I've come up on some architecture issues. My public volatile int
    > is in one class and I access it from another class. Both classes modify
    > the int. If I synchronize on "this" in its class and on the reference
    > variable from the other class, is it synchronized? Thanks very much.
    >
    > class a {
    > public volatile int x;
    >
    > public void run() {
    > synchronized (this) {
    > x = 1234;
    > }
    > }
    > }
    >
    > class b {
    > a aa = new a();
    >
    > public void run() {
    > synchronized (aa) {
    > aa.x = 4321;
    > }
    > }
    > }
    >
    > --
    >
    > Knute Johnson
    > email s/nospam/knute/
    > Molon labe...
    >
    Xavier Tarrago, Jul 2, 2003
    #14
  15. Re: synchronized? was:Re: Volatile?

    On Tue, 01 Jul 2003 16:34:36 -0700, Knute Johnson wrote:
    > I appreciate the response but this doesn't address my question. I
    > want to know if something in class a synchronized on "this" will be
    > synchronized with an instance of class a that is referenced from
    > class b.


    It doesn't matter how you refer to it. If "this" and the instance of a
    referenced from b are in fact the same object, then yes, they will be
    mutually synchronized.

    That said, the better solution is to use accessor methods inside a,
    and provide the necessary synchronization there instead of requiring
    that users of the class know about its synchronization needs.

    /gordon

    --
    [ do not send me private copies of your followups ]
    g o r d o n . b e a t o n @ e r i c s s o n . c o m
    Gordon Beaton, Jul 2, 2003
    #15
  16. Re: synchronized? was:Re: Volatile?

    Steve Horsley wrote:
    > On Tue, 01 Jul 2003 09:56:56 -0700, Knute Johnson wrote:
    >
    >
    >>Knute Johnson wrote:
    >>
    >>>Thanks everybody for the replies. I think I'm going to synchronize my
    >>>int variable. The problem I'm having that is caused by this is very
    >>>intermittent but I think that is do to luck.
    >>>
    >>>

    >>
    >>So now I've come up on some architecture issues. My public volatile int
    >>is in one class and I access it from another class. Both classes modify
    >>the int. If I synchronize on "this" in its class and on the reference
    >>variable from the other class, is it synchronized? Thanks very much.
    >>
    >>class a {
    >> public volatile int x;
    >>
    >> public void run() {
    >> synchronized (this) {
    >> x = 1234;
    >> }
    >> }
    >> }
    >>}
    >>class b {
    >> a aa = new a();
    >>
    >> public void run() {
    >> synchronized (aa) {
    >> aa.x = 4321;
    >> }
    >> }
    >> }
    >>}

    >
    >
    > Sometimes you have to synchronize on a foreign Object, for instance if you
    > are performing a series of operations on it and don't want it accessed in
    > mid-sequence by another thread. In this simple case though, I would be
    > inclined to make a.x private and fit class a with public synchronized
    > accessor methods getX() and setX(int). Always use those synchronized
    > methods even from inside class a's code and you're bomb-proof.
    >
    > Steve


    Thanks Steve and everybody for the replies. I've sort of gotten myself
    into a pickle with this app. I need to be able to increment and
    decrement my int as well as use it as a limit in a for loop from outside
    of its class. The accessor methods won't really work for that. Maybe
    it would make more sense to take it out of its class and put it in a
    globals class and synchronize on that class for access. This is
    starting to sound like one of those bizarre situations that are in the
    Multi-Threading book.

    Thanks,


    --

    Knute Johnson
    email s/nospam/knute/
    Molon labe...
    Knute Johnson, Jul 2, 2003
    #16
  17. Knute Johnson

    Keeger Guest

    Re: synchronized? was:Re: Volatile?

    Knute Johnson <> wrote in message news:<>...
    > Steve Horsley wrote:
    > > On Tue, 01 Jul 2003 09:56:56 -0700, Knute Johnson wrote:
    > >
    > >
    > >>Knute Johnson wrote:
    > >>
    > >>>Thanks everybody for the replies. I think I'm going to synchronize my
    > >>>int variable. The problem I'm having that is caused by this is very
    > >>>intermittent but I think that is do to luck.
    > >>>
    > >>>
    > >>
    > >>So now I've come up on some architecture issues. My public volatile int
    > >>is in one class and I access it from another class. Both classes modify
    > >>the int. If I synchronize on "this" in its class and on the reference
    > >>variable from the other class, is it synchronized? Thanks very much.
    > >>
    > >>class a {
    > >> public volatile int x;
    > >>
    > >> public void run() {
    > >> synchronized (this) {
    > >> x = 1234;
    > >> }
    > >> }
    > >> }
    > >>}
    > >>class b {
    > >> a aa = new a();
    > >>
    > >> public void run() {
    > >> synchronized (aa) {
    > >> aa.x = 4321;
    > >> }
    > >> }
    > >> }
    > >>}

    > >
    > >
    > > Sometimes you have to synchronize on a foreign Object, for instance if you
    > > are performing a series of operations on it and don't want it accessed in
    > > mid-sequence by another thread. In this simple case though, I would be
    > > inclined to make a.x private and fit class a with public synchronized
    > > accessor methods getX() and setX(int). Always use those synchronized
    > > methods even from inside class a's code and you're bomb-proof.
    > >
    > > Steve

    >
    > Thanks Steve and everybody for the replies. I've sort of gotten myself
    > into a pickle with this app. I need to be able to increment and
    > decrement my int as well as use it as a limit in a for loop from outside
    > of its class. The accessor methods won't really work for that. Maybe
    > it would make more sense to take it out of its class and put it in a
    > globals class and synchronize on that class for access. This is
    > starting to sound like one of those bizarre situations that are in the
    > Multi-Threading book.
    >
    > Thanks,


    maybe you should provide us with the exact problem you are trying to
    solve. It seems to me you're running into more of a design issue than
    implementation.
    Keeger, Jul 2, 2003
    #17
  18. Re: synchronized? was:Re: Volatile?

    Keeger wrote:
    >
    > maybe you should provide us with the exact problem you are trying to
    > solve. It seems to me you're running into more of a design issue than
    > implementation.


    You are right I wouldn't have these problems if the architecture wasn't
    totally fubared. This job was 7/8ths done and the client wanted it to
    work completely differently and didn't want to pay more for it. I was
    stuck having to make do with a lot of existing code and stuff scattered
    all over in the silly thing. The really hard part is trying to get it
    to not work correctly. I've been chasing around this synchronization
    bug for weeks and have had it crop up about 4 times. The app is in use
    ten or twelve hours a day and once in a while somebody can make it go south.

    I have however learned a lot about volatile and synchronization that I
    didn't before I started this.

    --

    Knute Johnson
    email s/nospam/knute/
    Molon labe...
    Knute Johnson, Jul 3, 2003
    #18
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Doug Pardee

    Re: Volatile?

    Doug Pardee, Jul 1, 2003, in forum: Java
    Replies:
    0
    Views:
    882
    Doug Pardee
    Jul 1, 2003
  2. Replies:
    1
    Views:
    902
    Knute Johnson
    Aug 29, 2003
  3. Daniel

    Can volatile be trusted?

    Daniel, Sep 11, 2003, in forum: Java
    Replies:
    7
    Views:
    465
    Chris Uppal
    Sep 12, 2003
  4. Harald Kirsch

    Is volatile keyword necessary?

    Harald Kirsch, Mar 4, 2004, in forum: Java
    Replies:
    2
    Views:
    343
    Chris Uppal
    Mar 4, 2004
  5. ben
    Replies:
    5
    Views:
    579
    Ulrich Eckhardt
    Jan 11, 2005
Loading...

Share This Page