/* This file is part of JOP, the Java Optimized Processor see <http://www.jopdesign.com/> Copyright (C) 2008, Martin Schoeberl (martin@jopdesign.com) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ /** * */ package rttm.jsim; import rttm.jsim.IncrementTest.Incrementer; import rttm.jsim.SingleLinkedListSynchronized.SynchronizedLinkedList; import com.jopdesign.io.IOFactory; import com.jopdesign.io.SysDevice; import com.jopdesign.sys.Const; import com.jopdesign.sys.Native; import com.jopdesign.sys.Startup; /** * Test program for RTTM with a single double linked list (producer/consumer). * * like in Herlihy & Moss, Transactional Memory: Architectural Support for Lock-Free Data Structures 1993 * * @author Michael Muck */ public class SingleLinkedList { private static final int MAGIC = -10000; private static SysDevice sys = IOFactory.getFactory().getSysDevice(); private static int SIZE = sys.nrCpu+1; private static int MAX_ITERATIONS = 1000; private static TransactionalLinkedList l = new TransactionalLinkedList(); /** * @param args */ public static void main(String[] args) { ListMover mov[] = new ListMover[sys.nrCpu]; for (int i=0; i<sys.nrCpu; ++i) { mov[i] = new ListMover(l); if(i > 0) { Startup.setRunnable(mov[i], i-1); } } // PreFill List with sys.nrCpu elements for(int i=0; i<SIZE; ++i) { l.insertAtHead(Integer.toString(i)); // for testing ... object is everytime the same } System.out.println("\nprefilled list:\n"); /* l.reset(); for(int i=0; i<SIZE; ++i) { System.out.print(l.next()); System.out.print(" "); } System.out.println("start"); */ int startTime, endTime; startTime = Native.rd(Const.IO_US_CNT); // start the other CPUs sys.signal = 1; // run one Runnable on this CPU mov[0].run(); // wait for other CPUs to finish boolean finished = false; while (!finished) { finished = true; for(int i=0; i<sys.nrCpu; ++i) { if(mov[i].finished != true) { finished = false; break; } } } endTime = Native.rd(Const.IO_US_CNT); System.out.print("Time: "); System.out.print(endTime-startTime); System.out.println("\n"); /* System.out.println("\nlist check:\n"); l.reset(); for(int i=0; i<SIZE; ++i) { System.out.print(l.next()); System.out.print(" "); } */ System.out.println("Finished!"); // write the magic string to stop the simulation System.out.println("\r\nJVM exit!\r\n"); } static class ListMover implements Runnable { public boolean finished = false; private TransactionalLinkedList myWorkingList; private int cnt = 0; public ListMover(TransactionalLinkedList ll) { myWorkingList = ll; } public void run() { Object o = null; //LinkedObject lo = null; while (cnt < MAX_ITERATIONS) { o = myWorkingList.removeFromTail(); /* Native.wrMem(1, MAGIC); // start transaction if(l.tail != null) { o = l.tail.thisObject; // get object if( l.tail.previous == null ) { l.tail = null; l.head = null; } else { l.tail = l.tail.previous; // tail.previous should never be emtpy l.tail.next = null; } } Native.wrMem(0, MAGIC); // end transaction */ if(o != null) { myWorkingList.insertAtHead(o); /* lo = new LinkedObject(o, null, null); Native.wrMem(1, MAGIC); // start transaction if(l.head == null) { // list is empty l.head = lo; l.tail = l.head; } else { lo.next = l.head; // save old head as new_head.next l.head.previous = lo; // set previous in old head to new head l.head = lo; // finally set new head as head } Native.wrMem(0, MAGIC); // end transaction */ ++cnt; } /* else { System.out.print("null"); } */ } finished = true; } } static class TransactionalLinkedList { public LinkedObject head; public LinkedObject tail; public LinkedObject current; // for iterations public TransactionalLinkedList() { head = null; tail = null; } public void insertAtHead(Object newObject) { LinkedObject lo = new LinkedObject(newObject, null, null); Native.wrMem(1, MAGIC); // start transaction if(head == null) { // list is empty head = lo; tail = head; } else { lo.next = head; // save old head as new_head.next head.previous = lo; // set previous in old head to new head head = lo; // finally set new head as head } Native.wrMem(0, MAGIC); // end transaction } public Object removeFromTail() { Object o = null; Native.wrMem(1, MAGIC); // start transaction if(tail != null) { o = tail.thisObject; // get object if( tail.previous == null ) { tail = null; head = null; } else { tail = tail.previous; // tail.previous should never be emtpy tail.next = null; } } Native.wrMem(0, MAGIC); // end transaction return o; } public void reset() { Native.wrMem(1, MAGIC); // start transaction current = head; Native.wrMem(0, MAGIC); // end transaction } public Object next() { Object o = null; Native.wrMem(1, MAGIC); // start transaction if(current != null) { o = current.thisObject; current = current.next; } Native.wrMem(0, MAGIC); // end transaction return o; } static class LinkedObject { public Object thisObject; public LinkedObject next; public LinkedObject previous; public LinkedObject(Object o, LinkedObject prev, LinkedObject nex) { thisObject = o; previous = prev; next = nex; } } } }