RexxLA / NetRexx

Other
6 stars 0 forks source link

Interpreter fails in synchronised section #49

Closed rvjansen closed 6 months ago

rvjansen commented 1 year ago

The following program only fails with the "loop protect Race.lock" included; without it, or compiled, it works OK. (Without the protect it obviously gives incorrect output, but that was the point of this educational program, which was made to simplify and illustrate a real race condition at work).

options binary
class Race

properties static
sharedVariable = 0
lock=Object()

  method main(args=String[]) static
    thread1 = Thread(Increment())
    thread2 = Thread(Increment())

    thread1.start()
    thread2.start()

    do
      thread1.join()
      thread2.join()
    catch e=InterruptedException
      e.printStackTrace()
    end

    say "shared variable = "sharedVariable

class Increment implements Runnable
  method run()
    loop protect Race.lock for 100000
      Race.sharedVariable = Race.sharedVariable + 1
    end

fails when executed interpreted; with AOT compiler everything is fine and working as expected. These messages are issued:

NetRexx portable processor 4.05-beta build 34-20230404-2054
Copyright (c) RexxLA, 2011,2023.   All rights reserved.
Parts Copyright (c) IBM Corporation, 1995,2008.
Program Race.nrx
  === class Race ===
    function main(String[])

  === class Increment ===
    method run
      implements Runnable.run
===== Exec: Race =====
Exception in thread "Thread-0" java.lang.StackOverflowError
    at netrexx.lang.RexxWords.changestr(RexxWords.java:126)
    at netrexx.lang.Rexx.changestr(Rexx.java:1011)
    at org.netrexx.process.RxType.getClassName(RxType.java:465)
    at org.netrexx.process.RxClasser.findclass(RxClasser.java:1953)
    at org.netrexx.process.RxClasser.issubclass(RxClasser.java:2150)
    at org.netrexx.process.RxClasser.issubclass(RxClasser.java:2141)
    at org.netrexx.process.RxConverter.assigncost(RxConverter.java:260)
    at org.netrexx.process.RxExprParser.twoopdo(RxExprParser.java:1434)
    at org.netrexx.process.RxExprParser.opdo(RxExprParser.java:675)
    at org.netrexx.process.RxExprParser.parseexpr(RxExprParser.java:484)
    at org.netrexx.process.RxExprParser.parseexpr(RxExprParser.java:266)
    at org.netrexx.process.RxExprParser.evalexpr(RxExprParser.java:197)
    at org.netrexx.process.NrAssign.interpret(NrAssign.java:496)
    at org.netrexx.process.RxInterpreter.runfree(RxInterpreter.java:1319)
    at org.netrexx.process.RxInterpreter.runprotected(RxInterpreter.java:1225)
    at org.netrexx.process.RxInterpreter.runfree(RxInterpreter.java:1305)
    at org.netrexx.process.RxInterpreter.runprotected(RxInterpreter.java:1225)
    at org.netrexx.process.RxInterpreter.runfree(RxInterpreter.java:1305)
    at org.netrexx.process.RxInterpreter.runprotected(RxInterpreter.java:1225)
[...]
    at org.netrexx.process.RxInterpreter.runfree(RxInterpreter.java:1305)
shared variable = 5541
Processing of 'Race.nrx' complete [2 classes]
remesm commented 1 year ago

Hi René,

for 'protecting' blocks RxInterpreter.nrx calls runprotected, which calls runfree, which then calls runprotected etc. This obviously overflows the stack when called too much. Changing the Java stack size will make it to 100000 loops;

But there's a different issue with smaller loops : loop protect Race.lock for 4

Still trying to understand the code, but it seems something needs to be fixed..

Marc

rvjansen commented 1 year ago

In the original Java example the class is static; could not do that in NetRexx. In NetRexx you can only make classes static by having every method static, but in the case or f run() it loses the right signature for the runnable interface that way. I wonder what we need to do with that.

remesm commented 6 months ago

fixed with commit 2e9ae103caa7dd24bf7505e655e0b32dd44c0c26 Defuse the lock at tne END statement of the protected block

rvjansen commented 6 months ago

works; all testing succeeds.