abstract the real world is concurrent. several things may happen at the same time. computer systems...

1
ABSTRACT The real world is concurrent. Several things may happen at the same time. Computer systems must increasingly contend with concurrent applications. SCOOP is a concurrent programming language with a new semantics for contracts that applies equally well in concurrent and sequential contexts. SCOOP eliminates race conditions and atomicity violations by construction. In this work we describe JSCOOP an equivalent solution in Java. This solution introduces new annotations modeled after SCOOP keywords as well as several core library classes which provide the backend support necessary to mirror SCOOP semantics. JAC (Java with Annotated Concurrency via JML) is a prior attempt to port SCOOP notions to Java. OBJECTIVE JSCOOP extends Java’s concurrent behaviour by hiding the notion of threads, semaphores and synchronization. This is achieved by adding two annotated keywords ( @separate and @await). These keywords have the same meaning as separate and require in SCOOP. The goal in creating the JSCOOP library was to provide a base set of classes similar to SCOOPLI for SCOOP. These classes are intended to provide support for major SCOOP concepts, including a fair scheduling algorithm that eliminates race conditions, separate processor functionality, and mechanisms to mirror Eiffel’s agents for wrapping calls. Consider an excerpt of JSCOOP code using the new keywords for the classic Dining Philosophers example: Advantages • No explicit thread declarations • No synchronized blocks • No semaphores or explicit waits Support developed for JSCOOP includes: (a) An Eclipse JSCOOP plug-in that supports the two new keywords as annotations and does automated syntax type checking for “traitors” (that prevent atomicity or race violations). See sister poster. (b) Prototype runtime translation to translate JSCOOP to multithreaded Java as presented in this poster. A core library for the translation has been developed that provides support for the translation, with proof of concept on some examples. Jenna Lau With Kevin Doyle, Jonathan Ostroff and Faraz Ahmadi Torshizi. Department of Computer Science and Engineering, York University, 4700 Keele Street, Toronto, Canada M3J 1P3 WHAT IS JSCOOP? Java Simple Concurrent Object Oriented Programming Extends Java with two new annotations: @separate and @await These annotations allow for simple development of concurrent solutions without concern for low-level details JSCOOP code must be translated to Java prior to execution JSCOOP is supported by a group of library classes which take care of concurrency issues such as: data races atomicity violations Still, no guarantee of freedom of deadlocks @AWAIT ANNOTATION Preconditions are treated as “wait conditions” when declared using the @await annotation @await takes a String argument pre specifying boolean condition(s) Valid pre Strings must correspond to valid assert expressions Preconditions are checked by a global scheduler prior to granting locks Best Practice: Preconditions specified using the @await annotation should involve separate objects. Using @await to declare preconditions on non-separate objects may result in infinite waits and deadlocks @SEPARATE ANNOTATION An object handled by a different processor is called separate with respect to the current object Objects handled by the same processor as the current processor are called non-separate JObject x = new JObject(); is non-separate @separate JObject x = new JObject(); is separate @separate can be used to decorate fields, local variables and method parameters Each variable declaration which uses the @separate annotation corresponds to the following Java actions: Create a processor different from the processor handling the current object Create an instance of the translated object Associate the processor with the object @separate annotations decorating method parameters indicate that arguments passed may be separate with respect to the method’s object JSCOOP LIBRARY JSCOOP_Scheduler The JSCOOP_Scheduler maintains a list of all processors, and a list of locked processors, as well as a queue of JSCOOP_Calls (each of which contain a lock request). A fair scheduling algorithm is used to prevent race conditions. Locks are only granted when: All requested processors are available All @await preconditions hold JSCOOP_Processor The JSCOOP_Processor object is in change of maintaining a local call queue, a remote call queue, and a thread pool managed by an ExecutorService. Processors act as an intermediary between objects and the global scheduler. Calls are submitted to the processor, which must wait for locks to be granted by the scheduler before the calls are invoked. JSCOOP_Runnable (interface) The JSCOOP_Runnable interface provides a standard set of methods that must be implemented by all translated objects ADDITIONAL JSCOOP LIBRARY CLASSES JSCOOP_Call Acts as a wrapper for all method calls JSCOOP_LockRequest Acts as a wrapper for all lock requests Lock requests are made on the processor handling the object on which locks are required JSCOOP_Array Acts as a wrapper for standard Java arrays Required to provide support for arrays in the separate context JSCOOP_Print Provides an alternative to System.out.print to capture proper printing behaviour in a concurrent environment. CALL WRAPPING In order to facilitate communication between objects, processors and the scheduler, an equivalent to Eiffel’s agent functionality is necessary. When a JSCOOP application is translated into Java, each method invocation is analyzed as follows: Objects submit wrapped calls to processors to maintain correct execution ordering Processors submit wrapped calls to the scheduler for locks and precondition validation Wait-by-necessity is employed for remote query calls JSCOOP_Processor o_proc = scheduler.createProcessor(); JSCOOP_SomeObject o = new JSCOOP_SomeObject(); o.setProcessor(o_proc); @separate SomeObject o = new SomeObject(); @await(pre=“list.isEmpty() && arg1 != null) public void aMethod(@separate Jlist list, @separate JObject arg1) { } implements Runnable void addRequest JSCOOP_Scheduler (JSCOOP_Call call) JSCOOP_Processor createProcessor(String n) void releaseLocks (JSCOOP_Call call) boolean removeProcessor (JSCOOP_Processor p) implements Runnable void addLocalCall JSCOOP_Processor (JSCOOP_Call call) void addRemoteCall (JSCOOP_Call call) JSCOOP_Processor getLockedBy() Semaphore getLockSemaphore() JSCOOP_Scheduler getScheduler() boolean lockProcessor (JSCOOP_Processor p) boolean unlockProcessor() INTERFACE implements Runnable boolean checkPreconditions() JSCOOP_Call getCall() void setCall(JSCOOP_Call c) void setProcessor JSCOOP_Runnable (JSCOOP_Processor p) JSCOOP_Processor getProcessor() Get JSCOOP_Call from the call queue Check availability of all requested processors Evaluate @await precondition of call Signal processor requesting locks Lock requested processors Method Call Local Call Remote Call No Precondition No Locks Needed Has Precondition Or Needs Locks No Return Value Has Return Value Wrap call Run as normal Send call to processor Wait on semaphore Run as normal when signaled Wrap call Send call to processor Continue execution Wrap call Send call to processor Wait on semaphore Get returned value from call when signaled JSCOOP_SCHEDULER - Process JSCOOP_LockRequest stored in call - Check preconditions for the call - Lock processors requested - Release the lock semaphore JSCOOP_RUNNABLE - Create JSCOOP_LockRequest - Create JSCOOP_Call - Add call to the remote queue of JSCOOP Processor - Wait on the call semaphore - Extract return value from call JSCOOP_PROCESSOR - Add call to the request queue in JSCOOP_Scheduler - Wait on the lock semaphore - Execute call through the ExecutorService - Release call semaphore at end of call execution public class Philosopher { private @separate Fork left, right; @await(pre="!l.isInUse() && !r.isInUse()") public void eat(@separate Fork l, @separate Fork r) { l.pickUp(); r.pickUp(); if(l.isInUse() && r.isInUse()) status = EATING; l.putDown(); r.putDown(); if(!l.isInUse() && !r.isInUse()) status = IDLE; } }

Upload: patricia-glenn

Post on 20-Jan-2016

213 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: ABSTRACT The real world is concurrent. Several things may happen at the same time. Computer systems must increasingly contend with concurrent applications

ABSTRACT

The real world is concurrent. Several things may happen at the same time. Computer systems must increasingly contend with concurrent applications.

SCOOP is a concurrent programming language with a new semantics for contracts that applies equally well in concurrent and sequential contexts. SCOOP eliminates race conditions and atomicity violations by construction.

In this work we describe JSCOOP – an equivalent solution in Java. This solution introduces new annotations modeled after SCOOP keywords as well as several core library classes which provide the backend support necessary to mirror SCOOP semantics.

JAC (Java with Annotated Concurrency via JML) is a prior attempt to port SCOOP notions to Java.

OBJECTIVE

JSCOOP extends Java’s concurrent behaviour by hiding the notion of threads, semaphores and synchronization. This is achieved by adding two annotated keywords (@separate and @await). These keywords have the same meaning as separate and require in SCOOP.

The goal in creating the JSCOOP library was to provide a base set of classes similar to SCOOPLI for SCOOP. These classes are intended to provide support for major SCOOP concepts, including a fair scheduling algorithm that eliminates race conditions, separate processor functionality, and mechanisms to mirror Eiffel’s agents for wrapping calls.

Consider an excerpt of JSCOOP code using the new keywords for the classic Dining Philosophers example:

Advantages

• No explicit thread declarations• No synchronized blocks• No semaphores or explicit waits

Support developed for JSCOOP includes:

(a) An Eclipse JSCOOP plug-in that supports the two new keywords as annotations and does automated syntax type checking for “traitors” (that prevent atomicity or race violations). See sister poster.

(b) Prototype runtime translation to translate JSCOOP to multithreaded Java as presented in this poster. A core library for the translation has been developed that provides support for the translation, with proof of concept on some examples.

Jenna Lau

With Kevin Doyle, Jonathan Ostroff and Faraz Ahmadi Torshizi.Department of Computer Science and Engineering, York University, 4700 Keele Street, Toronto, Canada M3J 1P3

WHAT IS JSCOOP?

Java Simple Concurrent Object Oriented Programming

Extends Java with two new annotations: @separate and @await

These annotations allow for simple development of concurrent solutions without concern for low-level details

JSCOOP code must be translated to Java prior to execution

JSCOOP is supported by a group of library classes which take care of concurrency issues such as: data races atomicity violations

Still, no guarantee of freedom of deadlocks

@AWAIT ANNOTATION

Preconditions are treated as “wait conditions” when declared using the @await annotation

@await takes a String argument pre specifying boolean condition(s) Valid pre Strings must correspond to valid assert

expressions Preconditions are checked by a global scheduler prior to

granting locks

Best Practice: Preconditions specified using the @await annotation should involve separate objects. Using @await to declare preconditions on non-separate objects may result in infinite waits and deadlocks

@SEPARATE ANNOTATION

An object handled by a different processor is called separate with respect to the current object

Objects handled by the same processor as the current processor are called non-separate JObject x = new JObject(); is non-separate @separate JObject x = new JObject(); is separate

@separate can be used to decorate fields, local variables and method parameters

Each variable declaration which uses the @separate annotation corresponds to the following Java actions: Create a processor different from the processor

handling the current object Create an instance of the translated object Associate the processor with the object

@separate annotations decorating method parameters indicate that arguments passed may be separate with respect to the method’s object

JSCOOP LIBRARY

JSCOOP_Scheduler The JSCOOP_Scheduler maintains a list of all

processors, and a list of locked processors, as well as a queue of JSCOOP_Calls (each of which contain a lock request).

A fair scheduling algorithm is used to prevent race conditions. Locks are only granted when: All requested processors are available All @await preconditions hold

JSCOOP_Processor The JSCOOP_Processor object is in change of

maintaining a local call queue, a remote call queue, and a thread pool managed by an ExecutorService.

Processors act as an intermediary between objects and the global scheduler. Calls are submitted to the processor, which must wait for locks to be granted by the scheduler before the calls are invoked.

JSCOOP_Runnable (interface) The JSCOOP_Runnable interface provides a

standard set of methods that must be implemented by all translated objects

ADDITIONAL JSCOOP LIBRARY CLASSES

JSCOOP_Call Acts as a wrapper for all method calls

JSCOOP_LockRequest Acts as a wrapper for all lock requests Lock requests are made on the processor

handling the object on which locks are required JSCOOP_Array

Acts as a wrapper for standard Java arrays Required to provide support for arrays in the

separate context JSCOOP_Print

Provides an alternative to System.out.print to capture proper printing behaviour in a concurrent environment.

CALL WRAPPING

In order to facilitate communication between objects, processors and the scheduler, an equivalent to Eiffel’s agent functionality is necessary.

When a JSCOOP application is translated into Java, each method invocation is analyzed as follows:

Objects submit wrapped calls to processors to maintain correct execution ordering

Processors submit wrapped calls to the scheduler for locks and precondition validation

Wait-by-necessity is employed for remote query calls

JSCOOP_Processor o_proc = scheduler.createProcessor();JSCOOP_SomeObject o = new JSCOOP_SomeObject();o.setProcessor(o_proc);

@separate SomeObject o = new SomeObject();

@await(pre=“list.isEmpty() && arg1 != null)public void aMethod(@separate Jlist list,

@separate JObject arg1) {…

}

• implements Runnable

• void addRequest

JSCOOP_Scheduler

(JSCOOP_Call call)

• JSCOOP_Processor createProcessor(String n)

• void releaseLocks (JSCOOP_Call call)

• boolean removeProcessor (JSCOOP_Processor p)

• implements Runnable

• void addLocalCall

JSCOOP_Processor

(JSCOOP_Call call)

• void addRemoteCall (JSCOOP_Call call)

• JSCOOP_Processor getLockedBy()

• Semaphore getLockSemaphore()

• JSCOOP_Scheduler getScheduler()

• boolean lockProcessor (JSCOOP_Processor p)

• boolean unlockProcessor()

INTERFACE implements Runnable

• boolean checkPreconditions()

• JSCOOP_Call getCall()

• void setCall(JSCOOP_Call c)

• void setProcessor

JSCOOP_Runnable

(JSCOOP_Processor p)

• JSCOOP_Processor getProcessor()

Get JSCOOP_Call from the call queue

Check availability of allrequested processors

Evaluate @await precondition of call

Signal processorrequesting locks

Lock requested processors

Method Call

Local Call Remote Call

No PreconditionNo Locks Needed

Has PreconditionOr Needs Locks

No Return Value

Has Return Value

Wrap call Run as normal

Send call to processor

Wait on semaphore

Run as normalwhen signaled

Wrap call

Send call to processor

Continue execution

Wrap call

Send call to processor

Wait on semaphore

Get returned value from call when signaled

JSCOOP_SCHEDULER

- Process JSCOOP_LockRequest stored in call

- Check preconditions for the call

- Lock processors requested

- Release the lock semaphore

JSCOOP_RUNNABLE

- Create JSCOOP_LockRequest

- Create JSCOOP_Call

- Add call to the remote queue of JSCOOP Processor

- Wait on the call semaphore

- Extract return value from call

JSCOOP_PROCESSOR

- Add call to the request queue in JSCOOP_Scheduler

- Wait on the lock semaphore

- Execute call through the ExecutorService

- Release call semaphoreat end of call execution

public class Philosopher {

private @separate Fork left, right;

@await(pre="!l.isInUse() && !r.isInUse()") public void eat(@separate Fork l, @separate Fork r) { l.pickUp(); r.pickUp(); if(l.isInUse() && r.isInUse()) status = EATING; l.putDown(); r.putDown(); if(!l.isInUse() && !r.isInUse()) status = IDLE; } …}