abstract the real world is concurrent. several things may happen at the same time. computer systems...
TRANSCRIPT
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; } …}