8 Replies Latest reply: Apr 16, 2009 6:16 AM by 807557 RSS

    NoHeapRealtimeThread.setReleaseParameters()

    807557
      Hi,

      I've got the following problem with a nhrt (placed in ScopedMemory or ImmortalMemory - the error remains the same).
      class SomeClass extends NoHeapRealtimeThread{
      
        // Constructor.
        public SomeClass {
          ...    
          setReleaseParameters(new PeriodicParameters(new RelativeTime(0, 100000))); // no error - works fine
          ..
        }
      
        public void run() {
          ...    
          setReleaseParameters(new PeriodicParameters(new RelativeTime(0, 222222))); // MemoryAccessError
          ...
        }
      
      }
      Why does this MemoryAccessError occur? Is there any other way to change the release period of a nhrt during runtime from inside the nhrt?

      Thanks,
      Gordon
        • 1. Re: NoHeapRealtimeThread.setReleaseParameters()
          807557
          Gordon_Realtime wrote:
          Why does this MemoryAccessError occur?
          No idea! Can you show the stacktrace from the exception please.
          Is there any other way to change the release period of a nhrt during runtime from inside the nhrt?
          Sure - use getReleaseParameters() and set the new period into it. Note however that the new period won't take affect immediately - the next release is determined by the previous release and the period at that time, so:

          // let last release time be T
          myparams.setPeriod(newPeriod);
          waitForNextPeriod(); // returns at T+oldPeriod
          waitForNextPeriod(); // returns at T+OldPeriod+newPeriod

          if you need immediate affect then you can use waitForNextPeriodInterruptible and interrupt the thread before calling it - but be aware that this also resets the phasing of the thread ie the interrupt time acts like a new initial release time.

          HTH

          David Holmes
          • 2. Re: NoHeapRealtimeThread.setReleaseParameters()
            807557
            Thanks David.

            This ist the stacktrace:
            Exception in thread "NoHeapRealtimeThread-0" javax.realtime.MemoryAccessError
                    at javax.realtime.MemoryArea.getMemoryAreaForObject0(Native Method)
                    at javax.realtime.MemoryArea.getMemoryArea(MemoryArea.java:207)
                    at javax.realtime.RealtimeThread.checkBidirectionalReferencing(RealtimeThread.java:1314)
                    at javax.realtime.RealtimeThread.setReleaseParameters(RealtimeThread.java:941)
                    at WriterThread.run(WriterThread.java:59)
            In line 59 of the WriterThread class, the .setReleaseParameters... is called from inside the run() method - as explained before.

            // let last release time be T
            myparams.setPeriod(newPeriod);
            waitForNextPeriod(); // returns at T+oldPeriod
            waitForNextPeriod(); // returns at T+OldPeriod+newPeriod
            But for the next releases, only the newPeriod would be guilty? Like this:

            // let last release time be T
            myparams.setPeriod(newPeriod);
            waitForNextPeriod(); // returns at T+oldPeriod
            waitForNextPeriod(); // returns at T+OldPeriod+newPeriod
            waitForNextPeriod(); // returns at T+newPeriod
            waitForNextPeriod(); // returns at T+newPeriod
            ...

            Because if not, it wouldn't be possible to reduce the period via myparams.setPeriod(...). The new period would be added to the current instead of replaced.

            Gordon.
            • 3. Re: NoHeapRealtimeThread.setReleaseParameters()
              807557
              Gordon_Realtime wrote:
              This ist the stacktrace:
              Exception in thread "NoHeapRealtimeThread-0" javax.realtime.MemoryAccessError
              at javax.realtime.MemoryArea.getMemoryAreaForObject0(Native Method)
              at javax.realtime.MemoryArea.getMemoryArea(MemoryArea.java:207)
              at javax.realtime.RealtimeThread.checkBidirectionalReferencing(RealtimeThread.java:1314)
              at javax.realtime.RealtimeThread.setReleaseParameters(RealtimeThread.java:941)
              at WriterThread.run(WriterThread.java:59)
              In line 59 of the WriterThread class, the .setReleaseParameters... is called from inside the run() method - as explained before.
              There's something not right here - this indicates a heap-reference was encountered, which should not be possible. I'll look into this.
              // let last release time be T
              myparams.setPeriod(newPeriod);
              waitForNextPeriod(); // returns at T+oldPeriod
              waitForNextPeriod(); // returns at T+OldPeriod+newPeriod
              But for the next releases, only the newPeriod would be guilty? Like this:

              // let last release time be T
              myparams.setPeriod(newPeriod);
              waitForNextPeriod(); // returns at T+oldPeriod
              waitForNextPeriod(); // returns at T+OldPeriod+newPeriod
              waitForNextPeriod(); // returns at T+newPeriod
              waitForNextPeriod(); // returns at T+newPeriod
              ...
              No it would be:

              // let last release time be T
              myparams.setPeriod(newPeriod);
              waitForNextPeriod(); // returns at T+oldPeriod
              waitForNextPeriod(); // returns at T+oldPeriod+newPeriod
              waitForNextPeriod(); // returns at T+oldPeriod+2*newPeriod
              waitForNextPeriod(); // returns at T+oldPeriod+3*newPeriod

              in other words the time T+oldPeriod becomes the new effective start time for newPeriod. Each of the releases is newPeriod apart.

              Hope this clarifies things.

              David
              • 4. Re: NoHeapRealtimeThread.setReleaseParameters()
                807557
                Gordon,

                I need to see exactly how the NHRT is being constructed - in particular which memory area it is in, and which memory area it is passed to execute in.

                Edited to add: I have been unable to duplicate this failure mode. So I really need to see all the code involved.

                There is potentially a problem with the way you are trying to do this because of the bi-directional-reference rule for parameter objects: the PeriodicParameters must be able to store a reference to the thread and vice-versa. If this is violated then you will get an IllegalAssignmentError. For example, if your NHRT is constructed in ImmortalMemory but passed a ScopedMemory in which to execute then:
                setReleaseParameters(new PeriodicParameters(...));
                will fail because the current thread can not hold a reference to the scope-allocated PeriodicParameters object.

                For a similar reason the way I indicated you could change the period actually requires greater care - because the existing PeriodicParameters object may not be able to store a reference to a newly allocated (possibly scope-allocated) RelativeTime object. There are a number of ways to deal with this (eg. get the MemoryArea of the object and use newInstance to do reflective allocation) but the simplest approach is:
                PeriodicParameters pp = (PeriodicParameters) getReleaseParameters();
                RelativeTime period = pp.getPeriod();
                period.set(newMillis, newNanos);
                pp.setPeriod(period);
                David

                Edited by: davidholmes on Apr 16, 2009 10:05 AM
                • 5. Re: NoHeapRealtimeThread.setReleaseParameters()
                  807557
                  Hi David,

                  here is the complete implementation which is relevant to the error:
                  public class Main {
                  
                      public static void main(String[] args) {
                         
                         ...
                  
                          // Start controller thread.
                          ScopedMemory scoped = new LTMemory(
                                  ControllerThread.SCOPED_SIZE_CONTROLLER);
                          RealtimeThread controllerThread = new ControllerThread(
                                  new PriorityParameters(ControllerThread.CONTROLLER_PRIORITY),
                                  scoped, reader);
                          controllerThread.start();
                      }
                  
                  }
                  
                  class ControllerThread extends RealtimeThread{
                      ...
                  
                      public ControllerThread(SchedulingParameters priority, 
                              MemoryArea memoryArea, ReaderThread reader) {
                          super(priority, null, null, memoryArea, null, null);
                          ...
                      }
                      
                  
                      @Override
                      public void run() {
                          ...
                  
                          // Declare writer thread.
                          ScopedMemory scoped = new LTMemory(ControllerThread.SCOPED_SIZE_WRITER);
                          WriterThread writer = new WriterThread(
                                  new PriorityParameters(ControllerThread.WRITER_PRIORITY),
                                  scoped, ControllerThread.queue);
                          ...
                          // Start writer thread.
                          writer.start();
                  
                          // Start reader thread.
                          reader.start();
                  
                          // Create queue.
                          reader.setQueue(queue);
                          writer.setQueue(queue);
                      }
                  }
                  
                  class WriterThread extends NoHeapRealtimeThread{
                  
                  
                      public WriterThread(PriorityParameters priorityParameters,
                              MemoryArea area, WaitFreeWriteQueue queue) {
                          super(priorityParameters, area);
                          ...
                          // Set the initial period.
                          this.currentPeriod = PERIOD_START;
                          this.setReleaseParameters(
                                  new PeriodicParameters(new RelativeTime(0, PERIOD_START))); // works fine
                      }
                  
                      @Override
                      public void run() {
                          byte b = 111;
                          ...
                  
                          this.setReleaseParameters(
                                  new PeriodicParameters(new RelativeTime(0, 4)));  // here the error occurs
                  
                          while(currentPeriod > 0) {
                              ...
                              for (int i=0; i<PERIOD_TIMES; i++) {
                                  queue.write(b);
                                  waitForNextPeriod();
                              }
                  
                              // change period.
                              currentPeriod = currentPeriod - PERIOD_DELTA;
                              this.setReleaseParameters(
                                  new PeriodicParameters(new RelativeTime(0, currentPeriod)));
                          }
                      }
                  }
                  • 6. Re: NoHeapRealtimeThread.setReleaseParameters()
                    807557
                    This solution:
                    PeriodicParameters pp = (PeriodicParameters) getReleaseParameters();
                    RelativeTime period = pp.getPeriod();
                    period.set(newMillis, newNanos);
                    pp.setPeriod(period);
                    seems to work if newMillis is some long value > 1. But it doesn't work, if newMillis = 0. In this case it doesn't matter which value newNanos has - an exception is thrown. For example:
                    PeriodicParameters pp = (PeriodicParameters) getReleaseParameters();
                    RelativeTime period = pp.getPeriod();
                    period.set(0, 800000);
                    pp.setPeriod(period);
                    leads to the exception:
                    Exception in thread "NoHeapRealtimeThread-0" java.lang.IllegalArgumentException
                      at javax.realtime.PriorityScheduler.acceptPeriodicParameters(PriorityScheduler.java:595)
                      at javax.realtime.PeriodicParameters.setPeriod(PeriodicParameters.java:539)
                      at WriterThread.run(WriterThread.java:74)
                    With this problem setting some period below 1 ms is impossible.

                    Thanks,
                    Gordon

                    Edited by: Gordon_Realtime on Apr 16, 2009 1:41 AM
                    • 7. Re: NoHeapRealtimeThread.setReleaseParameters()
                      807557
                      Gordon_Realtime wrote:
                      This solution:
                      PeriodicParameters pp = (PeriodicParameters) getReleaseParameters();
                      RelativeTime period = pp.getPeriod();
                      period.set(newMillis, newNanos);
                      pp.setPeriod(period);
                      seems to work if newMillis is some long value > 1. But it doesn't work, if newMillis = 0. In this case it doesn't matter which value newNanos has - an exception is thrown.
                      Sorry I overlooked one aspect. When you set the period explicitly you have to maintain the invariant that deadline <= period. So if you shrink the period you have to first shrink the deadline. When you create a PeriodicParameters object the default is to set deadline == period.

                      It would be useful to have the IllegalArgumentException include a message to that effect.

                      David
                      • 8. Re: NoHeapRealtimeThread.setReleaseParameters()
                        807557
                        Ah! Now I see the problem.

                        The first scoped area, used by the ControllerThread is itself allocated in the heap - lets call this ScopeA.

                        The NHRT is allocated in ScopeA and is passed ScopeB to execute in.

                        The "new PeriodicParameters()" is created in Scope B.

                        The code has to check that the NHRT can hold a reference to the parameter object and vice-versa, so it calls getMemoryArea passing in the parameter object - which gives ScopeB - and passing in 'this' which would return ScopeA. But ScopeA is a reference to a heap-allocated object and this is a NHRT so the MemoryAccessError is thrown.

                        This sort of problem could be caught at the time the NHRT is constructed, but the RTSJ doesn't quite go far enough in the checks that have to be made at NHRT construction.

                        But note that, as I said previously, in this case even if you didn't get the MemoryAccessError you would get an IllegalAssignmentError because the NHRT can not hold a reference to the new parameter object. (The assignment rules for scopes are stronger than strictly needed and this is one case where it would be safe to allow the reference to be stored.)

                        David