├── .gitignore ├── CHANGES.txt ├── LICENSE.txt ├── MANIFEST.in ├── Makefile ├── README.md ├── build.sh ├── debian ├── changelog ├── compat ├── control ├── copyright ├── pycompat ├── pyversions ├── rules └── watch ├── examples ├── 1MillionProcesses.py ├── Commstime.py ├── Commstime_Io.py ├── Commstime_Multiprocesses.py ├── Dining-Phil.py ├── Fibonacci.py ├── MCPi.py ├── MCPiTrace.py ├── Mandelbrot │ ├── mandelbrot_ctypes.py │ ├── mandelbrot_kernel.c │ ├── mandelbrot_kernel.h │ └── pycsp_import.py ├── MultipleTokenRing.py ├── ParallelReturn_MCPi.py ├── Sieve.py ├── TerminationRacePoison.py ├── TerminationRaceRetire.py ├── TokenRing.py ├── WebServer.py ├── problems │ ├── deadlock_doing_alternation_on_input_and_output_pre_0.6.1.py │ ├── greenlets_differentiate_between_deadlocking_and_all_executed_processes_pre_0.7.0.py │ ├── greenlets_exception_propagation_from_io_functions_pre_0.7.1.py │ ├── greenlets_unable_to_communicate_on_channels_from_main_namespace_pre_0.7.1.py │ ├── parallel_leaking_mobile_channelend_garbage_collection_pre_0.9.2.py │ ├── parallel_nesting_multiprocess_in_process.py │ └── pycsp_import.py └── pycsp_import.py ├── pycsp ├── __init__.py ├── common │ ├── __init__.py │ ├── const.py │ ├── plugNplay.py │ ├── six.py │ ├── toolkit.py │ └── trace.py ├── current │ └── __init__.py ├── greenlets │ ├── __init__.py │ ├── alternation.py │ ├── altselect.py │ ├── buffer.py │ ├── channel.py │ ├── channelend.py │ ├── compat.py │ ├── exceptions.py │ ├── guard.py │ ├── process.py │ └── scheduling.py └── parallel │ ├── __init__.py │ ├── alternation.py │ ├── altselect.py │ ├── channel.py │ ├── clusterprocess.py │ ├── compat.py │ ├── configuration.py │ ├── const.py │ ├── dispatch.py │ ├── exceptions.py │ ├── guard.py │ ├── header.py │ ├── multiprocess.py │ ├── noderunner.py │ ├── ossocket.py │ ├── process.py │ ├── protocol.py │ ├── server.py │ └── sshprocess.py ├── setup.py ├── test ├── autotest.py ├── buffertest.py ├── check.py ├── commtest.py ├── guardtest.py ├── iotest.py ├── poisontest.py ├── pycsp_import.py ├── runtests.bat ├── runtests.sh ├── selecttest.py ├── unix │ ├── check.py │ ├── clusterprocesstest.py │ ├── multiprocesstest.py │ ├── nodefile │ ├── remotetest.py │ └── sshprocesstest.py └── windows │ └── remotetest.py └── tools ├── PlayTrace.png └── PlayTrace.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runefriborg/pycsp/6e5c2af90d1bebe4a4bf4de66a2af7a4e9c907be/LICENSE.txt -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.txt 2 | recursive-include test *.py *.sh *.bat 3 | recursive-include examples *.py *.c *.h 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | PYTHON=`which python` 3 | DESTDIR=/ 4 | BUILDIR=$(CURDIR)/debian/pycsp 5 | PROJECT=Pycsp 6 | VERSION=0.9.2 7 | 8 | all: 9 | @echo "make source - Create source package" 10 | @echo "make install - Install on local system" 11 | @echo "make buildrpm - Generate a rpm package" 12 | @echo "make builddeb - Generate a deb package" 13 | @echo "make clean - Get rid of scratch and byte files" 14 | 15 | source: 16 | $(PYTHON) setup.py sdist $(COMPILE) 17 | 18 | install: 19 | $(PYTHON) setup.py install --root $(DESTDIR) $(COMPILE) 20 | 21 | buildrpm: 22 | $(PYTHON) setup.py bdist_rpm --post-install=rpm/postinstall --pre-uninstall=rpm/preuninstall 23 | 24 | builddeb: 25 | # build the source package in the parent directory 26 | # then rename it to project_version.orig.tar.gz 27 | $(PYTHON) setup.py sdist $(COMPILE) --dist-dir=../ 28 | rename -f 's/$(PROJECT)-(.*)\.tar\.gz/$(PROJECT)_$$1\.orig\.tar\.gz/' ../* 29 | # build the package 30 | dpkg-buildpackage -i -I -rfakeroot 31 | 32 | buildsrc: 33 | debuild -S 34 | 35 | clean: 36 | $(PYTHON) setup.py clean 37 | fakeroot $(MAKE) -f $(CURDIR)/debian/rules clean 38 | rm -rf build/ MANIFEST 39 | find . -name '*.pyc' -delete 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | This PyCSP implementation has been discontinued. 3 | 4 | Go to https://pycsp.github.io/ for other more recent implementations. 5 | 6 |
7 | 8 | 9 | 10 | 11 | PyCSP was a CSP library for Python that implemented core CSP 12 | functionality with some extensions from pi-calculus. 13 | 14 | Provided: 15 | 16 | * Synchronous communication 17 | * Buffered channels 18 | * Multiple process types such as, greenlets, threads, processes and remote processes 19 | * Both input and output guards supported in external choice (Alts) 20 | * A single any-to-any channel type 21 | * Mobile channel-ends 22 | * Retire and poison signals for shutting down networks nicely 23 | * A channel which can communicate using inter-process communication as well as sockets. 24 | * A PyCSP providing local and distributed communication using only standard python modules bundled with CPython 25 | * NAT traversal 26 | * Tracing PyCSP executions to a log file, for later visualisation 27 | 28 | See https://github.com/runefriborg/pycsp/wiki for more information. 29 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | make builddeb && make clean && lintian -IviE --display-experimental --pedantic -L ">=wishlist" --color auto --show-overrides --checksums ../pycsp_0.7.0-0.1_amd64.changes 2 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | pycsp (0.7.0-0.1) unstable; urgency=low 2 | 3 | * Initial release. NMU (Closes: #205) 4 | 5 | -- Rune M. Friborg Thu, 19 Nov 2009 15:17:33 +0100 6 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 7 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: pycsp 2 | Section: devel 3 | Priority: optional 4 | Maintainer: Rune M. Friborg 5 | Standards-Version: 3.8.3 6 | Build-Depends: debhelper (>=7.0.0), cdbs (>= 0.4.49), python-dev, python-support(>=0.8) 7 | 8 | Package: pycsp 9 | Architecture: all 10 | Homepage: http://code.google.com/p/pycsp/ 11 | Depends: python-codespeak-lib, python (>=2.6), pyro (>=3.7) 12 | Description: Communicating Sequential Processes (CSP) for Python. 13 | PyCSP provides an API that can be used to write concurrent applications using CSP. 14 | The API is implemented in four versions: Threads, processes, greenlets and net. 15 | All implementations share an almost identical API making it trivial to switch 16 | from one implementation to another. 17 | 18 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 John Markus Bjørndalen , 2 | Brian Vinter , Rune M. Friborg 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. THE 14 | SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /debian/pycompat: -------------------------------------------------------------------------------- 1 | 2 2 | -------------------------------------------------------------------------------- /debian/pyversions: -------------------------------------------------------------------------------- 1 | 2.6- 2 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | 4 | DEB_PYTHON_SYSTEM := pysupport 5 | 6 | include /usr/share/cdbs/1/rules/debhelper.mk 7 | include /usr/share/cdbs/1/class/python-distutils.mk 8 | 9 | clean:: 10 | rm -rf build build-stamp configure-stamp build/ MANIFEST 11 | dh_clean 12 | -------------------------------------------------------------------------------- /debian/watch: -------------------------------------------------------------------------------- 1 | version=3 2 | http://code.google.com/p/pycsp/downloads/list http://pycsp.googlecode.com/files/pycsp-(.*)\.tar.gz 3 | -------------------------------------------------------------------------------- /examples/1MillionProcesses.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | import sys 8 | sys.path.append("..") 9 | 10 | import pycsp.greenlets as pycsp 11 | 12 | @pycsp.process 13 | def readP(cin): 14 | cin() 15 | 16 | A = pycsp.Channel("A") 17 | 18 | pycsp.Spawn(1000000 * readP(A.reader())) 19 | 20 | cout = A.writer() 21 | for i in range(1000000): 22 | cout(i) 23 | if (i%20000 == 0): 24 | sys.stdout.write(".") 25 | sys.stdout.flush() 26 | 27 | sys.stdout.write("done\n") 28 | 29 | pycsp.shutdown() 30 | -------------------------------------------------------------------------------- /examples/Commstime.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | from pycsp_import import * 8 | import time 9 | 10 | @process 11 | def Prefix(cin, cout, prefixItem=None): 12 | t = prefixItem 13 | while True: 14 | cout(t) 15 | t = cin() 16 | 17 | @process 18 | def Delta2(cin, cout1, cout2): 19 | while True: 20 | t = cin() 21 | cout1(t) 22 | cout2(t) 23 | 24 | @process 25 | def Successor(cin, cout): 26 | """Adds 1 to the value read on the input channel and outputs it on the output channel. 27 | Infinite loop. 28 | """ 29 | while True: 30 | cout(cin()+1) 31 | 32 | @process 33 | def Consumer(cin): 34 | "Commstime consumer process" 35 | N = 5000 36 | ts = time.time 37 | t1 = ts() 38 | cin() 39 | t1 = ts() 40 | for i in range(N): 41 | cin() 42 | t2 = ts() 43 | dt = t2-t1 44 | tchan = dt / (4 * N) 45 | print("DT = %f.\nTime per ch : %f/(4*%d) = %f s = %f us" % \ 46 | (dt, dt, N, tchan, tchan * 1000000)) 47 | print("consumer done, posioning channel") 48 | poison(cin) 49 | 50 | @process 51 | def CommsTimeBM(): 52 | # Create channels 53 | a = Channel("a") 54 | b = Channel("b") 55 | c = Channel("c") 56 | d = Channel("d") 57 | 58 | print("Running commstime test") 59 | Parallel(Prefix(+c, -a, prefixItem = 0), # initiator 60 | Delta2(+a, -b, -d), # forwarding to two 61 | Successor(+b, -c), # feeding back to prefix 62 | Consumer(+d)) # timing process 63 | 64 | N_BM = 3 65 | for i in range(N_BM): 66 | print("----------- run %d/%d -------------" % (i+1, N_BM)) 67 | Parallel(CommsTimeBM()) 68 | 69 | shutdown() 70 | -------------------------------------------------------------------------------- /examples/Commstime_Io.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | from pycsp_import import * 8 | import time 9 | 10 | @process 11 | def Prefix(cin, cout, prefixItem=None): 12 | t = prefixItem 13 | while True: 14 | cout(t) 15 | t = empty(cin()) 16 | 17 | @process 18 | def Delta2(cin, cout1, cout2): 19 | while True: 20 | t = empty(cin()) 21 | cout1(t) 22 | cout2(t) 23 | 24 | 25 | @process 26 | def Successor(cin, cout): 27 | """Adds 1 to the value read on the input channel and outputs it on the output channel. 28 | Infinite loop. 29 | """ 30 | while True: 31 | cout(empty(cin()+1)) 32 | 33 | @io 34 | def empty(i): 35 | return i 36 | 37 | @process 38 | def Consumer(cin): 39 | "Commstime consumer process" 40 | N = 1000 41 | ts = time.time 42 | t1 = ts() 43 | cin() 44 | t1 = ts() 45 | for i in range(N): 46 | empty(cin()) 47 | t2 = ts() 48 | dt = t2-t1 49 | tchan = dt / (4 * N) 50 | print("DT = %f.\nTime per ch : %f/(4*%d) = %f s = %f us" % \ 51 | (dt, dt, N, tchan, tchan * 1000000)) 52 | print("consumer done, posioning channel") 53 | retire(cin) 54 | 55 | @process 56 | def CommsTimeBM(): 57 | # Create channels 58 | a = Channel("a") 59 | b = Channel("b") 60 | c = Channel("c") 61 | d = Channel("d") 62 | 63 | print("Running commstime test") 64 | Parallel(Prefix(c.reader(), a.writer(), prefixItem = 0), # initiator 65 | Delta2(a.reader(), b.writer(), d.writer()), # forwarding to two 66 | Successor(b.reader(), c.writer()), # feeding back to prefix 67 | Consumer(d.reader())) # timing process 68 | 69 | N_BM = 10 70 | for i in range(N_BM): 71 | print("----------- run %d/%d -------------" % (i+1, N_BM)) 72 | Parallel(CommsTimeBM()) 73 | 74 | 75 | shutdown() 76 | -------------------------------------------------------------------------------- /examples/Commstime_Multiprocesses.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | from pycsp_import import * 8 | import time 9 | 10 | @multiprocess 11 | def Prefix(cin, cout, prefixItem=None): 12 | t = prefixItem 13 | while True: 14 | cout(t) 15 | t = cin() 16 | 17 | @multiprocess 18 | def Delta2(cin, cout1, cout2): 19 | while True: 20 | t = cin() 21 | cout1(t) 22 | cout2(t) 23 | 24 | @multiprocess 25 | def Successor(cin, cout): 26 | """Adds 1 to the value read on the input channel and outputs it on the output channel. 27 | Infinite loop. 28 | """ 29 | while True: 30 | cout(cin()+1) 31 | 32 | @multiprocess 33 | def Consumer(cin): 34 | "Commstime consumer process" 35 | N = 1000 36 | ts = time.time 37 | t1 = ts() 38 | cin() 39 | t1 = ts() 40 | for i in range(N): 41 | cin() 42 | t2 = ts() 43 | dt = t2-t1 44 | tchan = dt / (4 * N) 45 | print("DT = %f.\nTime per ch : %f/(4*%d) = %f s = %f us" % \ 46 | (dt, dt, N, tchan, tchan * 1000000)) 47 | print("consumer done, posioning channel") 48 | poison(cin) 49 | 50 | @multiprocess 51 | def CommsTimeBM(): 52 | # Create channels 53 | a = Channel("a") 54 | b = Channel("b") 55 | c = Channel("c") 56 | d = Channel("d") 57 | 58 | print("Running commstime test") 59 | Parallel(Prefix(+c, -a, prefixItem = 0), # initiator 60 | Delta2(+a, -b, -d), # forwarding to two 61 | Successor(+b, -c), # feeding back to prefix 62 | Consumer(+d)) # timing process 63 | 64 | N_BM = 10 65 | for i in range(N_BM): 66 | print("----------- run %d/%d -------------" % (i+1, N_BM)) 67 | Parallel(CommsTimeBM()) 68 | 69 | shutdown() 70 | -------------------------------------------------------------------------------- /examples/Dining-Phil.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | from pycsp_import import * 8 | 9 | # Based on the exercise q7.occ from the source distribution of kroc-1.4 10 | # 11 | # This is an example, showing how to do the equivalent in python using PyCSP 12 | # 13 | 14 | @process 15 | def philosopher(id, left, right, down, up): 16 | try: 17 | eat = 0 18 | while True: 19 | # think 20 | # Skip 21 | 22 | # get permission to sit down 23 | down(True) 24 | 25 | # pick up the forks (left and right) 26 | FairSelect( 27 | OutputGuard(left, msg=True, action="right(True)"), 28 | OutputGuard(right, msg=True, action="left(True)") 29 | ) 30 | 31 | # eat 32 | eat += 1 33 | 34 | # put down the forks (left and right) 35 | FairSelect( 36 | OutputGuard(left, msg=True, action="right(True)"), 37 | OutputGuard(right, msg=True, action="left(True)") 38 | ) 39 | 40 | # notify security you have finished 41 | up(True) 42 | 43 | except ChannelRetireException: 44 | print('philosopher '+str(id)+' has eaten '+str(eat)+' times') 45 | retire(left, right) 46 | 47 | @process 48 | def fork(left, right): 49 | while True: 50 | FairSelect( 51 | # philosopher left picks up fork 52 | # philosopher left puts down fork 53 | InputGuard(left, "left()"), 54 | 55 | # philosopher right picks up fork 56 | # philosopher right puts down fork 57 | InputGuard(right, "right()") 58 | ) 59 | 60 | @process 61 | def security(steps, down, up): 62 | max = 4 63 | n_sat_down = [0] # use call by reference 64 | for step in range(steps): 65 | guards = [] 66 | 67 | if n_sat_down[0] < max: # don't allow max at a time 68 | 69 | for i in range(5): 70 | # philosopher wanting to sit down 71 | guards.append(InputGuard(down[i], action="n_sat_down[0] += 1")) 72 | 73 | for i in range(5): 74 | # philosopher wanting to stand up 75 | # always allow this 76 | guards.append(InputGuard(up[i], action="n_sat_down[0] -= 1")) 77 | 78 | FairSelect(*guards) 79 | 80 | retire(*down) 81 | retire(*up) 82 | 83 | @process 84 | def secure_college(steps): 85 | left = Channel() * 5 86 | right = Channel() * 5 87 | up = Channel() * 5 88 | down = Channel() * 5 89 | 90 | Parallel( 91 | security(steps, [d.reader() for d in down] , [u.reader() for u in up]), 92 | [philosopher(i, left[i].writer(), right[i].writer(), down[i].writer(), up[i].writer()) for i in range(5)], 93 | [fork(left[i].reader(), right[(i+1) % 5].reader()) for i in range(5)] 94 | ) 95 | 96 | 97 | Sequence(secure_college(1000)) 98 | 99 | shutdown() 100 | -------------------------------------------------------------------------------- /examples/Fibonacci.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | from pycsp_import import * 8 | from pycsp.common.plugNplay import * 9 | 10 | # We are using plugNplay processes 11 | # Prefix 12 | # Pairs 13 | # Delta2 14 | 15 | @process 16 | def Printer(cin, limit): 17 | for i in range(limit): 18 | print(cin()) 19 | poison(cin) 20 | 21 | A = Channel('A') 22 | B = Channel('B') 23 | C = Channel('C') 24 | D = Channel('D') 25 | printC = Channel() 26 | 27 | Parallel( 28 | Prefix(+B, -A, prefix=0), 29 | Prefix(+C, -B, prefix=1), 30 | Pairs(+D, -C), 31 | Delta2(+A, -D, -printC), 32 | Printer(+printC, limit=20) 33 | ) 34 | 35 | shutdown() 36 | -------------------------------------------------------------------------------- /examples/MCPi.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | from pycsp_import import * 8 | from random import random 9 | from functools import reduce 10 | 11 | @process 12 | def producer(job_out, bagsize, bags): 13 | for i in range(bags): job_out(bagsize) 14 | retire(job_out) 15 | 16 | @process 17 | def worker(job_in, result_out): 18 | while True: 19 | cnt=job_in() #Get task 20 | sum = reduce(lambda x,y: x+(random()**2+random()**2<1.0), list(range(cnt))) 21 | result_out((4.0*sum)/cnt) #Forward result 22 | 23 | 24 | @process 25 | def consumer(result_in): 26 | cnt=0; sum=result_in() #Get first result 27 | try: 28 | while True: 29 | cnt+=1 30 | print(str(cnt) + ' ' + str(sum)) 31 | sum=(sum*cnt+result_in())/(cnt+1) #Get result 32 | except ChannelRetireException: 33 | print('Result:',sum) #We are done - print result 34 | 35 | jobs=Channel() 36 | results=Channel() 37 | 38 | 39 | Parallel( 40 | producer( jobs.writer() , 10000, 1000), 41 | 10 * worker( jobs.reader() ,results.writer()), 42 | consumer(results.reader())) 43 | 44 | shutdown() 45 | -------------------------------------------------------------------------------- /examples/MCPiTrace.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | from pycsp_import import * 8 | from pycsp.common.trace import * 9 | from random import random 10 | from functools import reduce 11 | 12 | TraceInit('MCPiTrace.ouput') 13 | 14 | @process 15 | def producer(job_out, bagsize, bags): 16 | for i in range(bags): job_out(bagsize) 17 | retire(job_out) 18 | 19 | @process 20 | def worker(job_in, result_out): 21 | while True: 22 | cnt=job_in() #Get task 23 | sum = reduce(lambda x,y: x+(random()**2+random()**2<1.0), list(range(cnt))) 24 | result_out((4.0*sum)/cnt) #Forward result 25 | 26 | 27 | @process 28 | def consumer(result_in): 29 | cnt=0; sum=result_in() #Get first result 30 | try: 31 | while True: 32 | cnt+=1 33 | print(str(cnt) + ' ' + str(sum)) 34 | sum=(sum*cnt+result_in())/(cnt+1) #Get result 35 | except ChannelRetireException: 36 | print('Result:',sum) #We are done - print result 37 | 38 | jobs=Channel() 39 | results=Channel() 40 | 41 | 42 | Parallel( 43 | producer( jobs.writer() , 10000, 1000), 44 | 10 * worker( jobs.reader() ,results.writer()), 45 | consumer(results.reader())) 46 | 47 | TraceQuit() 48 | 49 | print("Created trace file 'MCPiTrace.output'") 50 | 51 | shutdown() 52 | -------------------------------------------------------------------------------- /examples/Mandelbrot/mandelbrot_ctypes.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. THE 14 | SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | """ 22 | 23 | from pycsp_import import * 24 | from numpy import * 25 | import sys, os 26 | 27 | from ctypes import * 28 | 29 | if os.path.exists('mandelbrot_kernel.dylib'): 30 | mandelbrot=CDLL('mandelbrot_kernel.dylib') 31 | elif os.path.exists('mandelbrot_kernel.so'): 32 | mandelbrot=CDLL('mandelbrot_kernel.so') 33 | else: 34 | print('Compile mandelbrot_kernel!') 35 | print('See mandelbrot_kernel.c for instructions') 36 | sys.exit(0) 37 | 38 | args = sys.argv 39 | if (len(args) < 5): 40 | print('Usage:\n\tpython mandelbrot_ctypes.py ') 41 | sys.exit(0) 42 | 43 | workers = int(args[1]) 44 | jobcount = int(args[2]) 45 | width = int(args[3]) 46 | height = int(args[4]) 47 | 48 | import time 49 | def init_time_record(): 50 | return {'total':0,'diff':time.time(),'calls':0} 51 | 52 | def t1(record): 53 | record['diff'] = time.time() 54 | record['calls'] += 1 55 | 56 | def t2(record): 57 | record['total'] += time.time() - record['diff'] 58 | record['diff'] = -9999 59 | 60 | def compute(u, h_step, w_step, h_start, w_start, h, w, maxit): 61 | mandelbrot.compute(u.ctypes.data_as(c_void_p), 62 | c_double(h_step), 63 | c_double(w_step), 64 | c_double(h_start), 65 | c_double(w_start), 66 | c_int(h), 67 | c_int(w), 68 | c_int(maxit)) 69 | 70 | 71 | @process 72 | def worker(cin, cout, maxit = 5000): 73 | time_rec = init_time_record() 74 | try: 75 | while True: 76 | (id, w_start, w_step, w, h_start, h_step, h) = cin() 77 | t1(time_rec) 78 | 79 | u=zeros((h,w), dtype=uint16) 80 | compute(u, h_step, w_step, h_start, w_start, h, w, maxit) 81 | 82 | t2(time_rec) 83 | cout((id, u)) 84 | except ChannelPoisonException: 85 | sys.stdout.write(' Worker: %d calls, %fs\n' % (time_rec['calls'],time_rec['total'])) 86 | 87 | 88 | @process 89 | def manager(workerOut, workerIn, w, h, jobcount): 90 | time_rec = init_time_record() 91 | 92 | #xmin = -2.0 93 | #xmax = 0.8 94 | #ymin = -1.4 95 | #ymax = 1.4 96 | 97 | xmin = -1.6744096758873175 98 | xmax = -1.6744096714940624 99 | ymin = 0.00004716419197284976 100 | ymax = 0.000047167062611931696 101 | 102 | w_step = (xmax-xmin)/w 103 | h_step = (ymax-ymin)/h 104 | w_start = xmin 105 | h_start = ymin 106 | 107 | job_h = h/jobcount 108 | 109 | # Generate jobs 110 | # Tuple: (job_id, w_start, w_step, width, h_start(job), h_step, job_h) 111 | jobs = [] 112 | for job_id in range(jobcount): 113 | jobs.append( 114 | (job_id, 115 | w_start, w_step, w, 116 | h_start + h_step * (job_id * job_h), h_step, job_h) 117 | ) 118 | 119 | if job_h*jobcount < h: 120 | last_h = h - job_h*jobcount 121 | jobs.append( 122 | (jobcount, 123 | w_start, w_step, w, 124 | h_start + h_step*(jobcount*job_h), h_step, last_h)) 125 | 126 | jobcount = len(jobs) 127 | 128 | # Deliver and receive 129 | results = [None for i in range(jobcount)] 130 | received = 0 131 | while jobs or received < jobcount: 132 | t2(time_rec) 133 | if jobs: 134 | guard, msg = AltSelect( 135 | InputGuard(workerIn), 136 | OutputGuard(workerOut, jobs[-1], action="jobs.pop(-1)") 137 | ) 138 | else: 139 | guard = workerIn 140 | msg = guard() 141 | t1(time_rec) 142 | 143 | if guard == workerIn: 144 | job_id, result = msg 145 | received += 1 146 | results[job_id] = result 147 | 148 | # Produce result 149 | u = concatenate(results, axis=0) 150 | 151 | sys.stdout.write(' Manager: %fs\n' % (time_rec['total'])) 152 | #pylab.imshow(u) 153 | retire(workerOut, workerIn) 154 | 155 | 156 | 157 | if __name__ == '__main__': 158 | 159 | print('PyCSP mandelbrot') 160 | print(' workers :', workers) 161 | print(' jobcount :',jobcount) 162 | print(' size :', (width, height)) 163 | 164 | rec_time_t = init_time_record() 165 | 166 | jobChannel = Channel() 167 | resultChannel = Channel() 168 | 169 | Parallel(manager(jobChannel.writer(), resultChannel.reader(), width, height, jobcount), 170 | [worker(jobChannel.reader(), resultChannel.writer()) for i in range(workers)]) 171 | 172 | t2(rec_time_t) 173 | sys.stdout.write(' *** Total: %f\n' % (rec_time_t['total'])) 174 | sys.stdout.write(' NB: includes channel create, job create and process startup/exit times\n') 175 | sys.stdout.write(' @%s\n' % (repr((jobcount, width, height, workers, rec_time_t['total'], "PyCSP")))) 176 | #pylab.show() 177 | 178 | shutdown() 179 | -------------------------------------------------------------------------------- /examples/Mandelbrot/mandelbrot_kernel.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. THE 14 | SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | Compile on mac: 23 | gcc -dynamiclib mandelbrot_kernel.c -o mandelbrot_kernel.dylib 24 | 25 | Compile on linux: 26 | gcc -shared mandelbrot_kernel.c -o mandelbrot_kernel.so 27 | 28 | */ 29 | #include 30 | #include "mandelbrot_kernel.h" 31 | 32 | void compute(uint16 *u, double h_step, double w_step, double h_start, double w_start, int h, int w, int maxint) 33 | { 34 | int x,y; 35 | 36 | if (0) 37 | printf("h_step %e, w_step %e, h_start %e, w_start %e, h %d, w %d, maxint %d\n", 38 | h_step, w_step, h_start, w_start, h, w, maxint); 39 | 40 | for (y=0; y, 3 | Brian Vinter , Rune M. Friborg 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. THE 14 | SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef __MANDELBROT_KERNEL__H__ 24 | #define __MANDELBROT_KERNEL__H__ 25 | 26 | typedef unsigned short uint16; 27 | 28 | void compute(uint16 *u, double h_step, double w_step, double h_start, double w_start, int h, int w, int maxint); 29 | int iterate_point(double x0, double y0, int max_iterations); 30 | 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /examples/Mandelbrot/pycsp_import.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | import sys 7 | sys.path.insert(0,"../..") 8 | 9 | if len(sys.argv) > 1: 10 | mod = sys.argv[1] 11 | else: 12 | mod = '' 13 | 14 | if (mod == 'parallel'): 15 | from pycsp.parallel import * 16 | elif (mod == 'greenlets'): 17 | from pycsp.greenlets import * 18 | else: 19 | print("python",sys.argv[0],"[ parallel | greenlets ]") 20 | from pycsp.parallel import * 21 | 22 | print('Using version', version) 23 | 24 | -------------------------------------------------------------------------------- /examples/MultipleTokenRing.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | import sys 8 | from pycsp_import import * 9 | 10 | elements = 64 11 | 12 | @process 13 | def element(this_read, next_write): 14 | while True: 15 | token = this_read() 16 | next_write(token + 1) 17 | 18 | @process 19 | def root(cycles, tokens, this_read, next_write): 20 | next_write(1) 21 | token = this_read() 22 | 23 | sys.stdout.write("start\n") 24 | sys.stdout.flush() 25 | 26 | for i in range(tokens): 27 | next_write(i + 1) 28 | 29 | while cycles: 30 | for i in range(tokens): 31 | token = this_read() 32 | next_write(token + 1) 33 | cycles = cycles - 1 34 | 35 | sum = 0 36 | for i in range(tokens): 37 | sum += this_read() 38 | 39 | sys.stdout.write("end\n") 40 | sys.stdout.flush() 41 | 42 | sys.stdout.write(str(sum) + "\n") 43 | 44 | retire(next_write, this_read) 45 | 46 | def ring(args): 47 | global elements 48 | cycles = 0 49 | tokens = 1 50 | if len(args) > 0: 51 | cycles = int(args[0]) 52 | if len(args) > 1: 53 | tokens = int(args[1]) 54 | 55 | head = Channel() 56 | this = head 57 | 58 | #chanlist to avoid Channel() datastructures to be gb_collected, when used in element processes 59 | chanlist = [head] 60 | for i in range(elements - 1): 61 | next = Channel() 62 | chanlist.append(next) 63 | Spawn(element(this.reader(), next.writer())) 64 | this = next 65 | 66 | Parallel(root(cycles, tokens, this.reader(), head.writer())) 67 | 68 | if __name__ == "__main__": 69 | ring(sys.argv[2:]) 70 | 71 | shutdown() 72 | -------------------------------------------------------------------------------- /examples/ParallelReturn_MCPi.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 Rune M. Friborg . 3 | See LICENSE.txt for licensing details (MIT License). 4 | """ 5 | 6 | from pycsp_import import * 7 | from random import random 8 | from functools import reduce 9 | 10 | if version[3] == "greenlets": 11 | multiprocess = process 12 | 13 | @process 14 | def work1(cnt): 15 | sum = reduce(lambda x,y: x+(random()**2+random()**2<1.0), list(range(cnt))) 16 | return (4.0*sum)/cnt #Return result 17 | 18 | @multiprocess 19 | def work2(cnt): 20 | sum = reduce(lambda x,y: x+(random()**2+random()**2<1.0), list(range(cnt))) 21 | return (4.0*sum)/cnt #Return result 22 | 23 | cnt = 100000 24 | P = 20 25 | 26 | def sum(a,b): 27 | return a+b 28 | 29 | if __name__ == '__main__': 30 | L = Parallel((P/2) * work1(cnt), (P/2) * work2(cnt)) 31 | print("Processes return " + str(L)) 32 | all = reduce(sum, L) 33 | print(("Result: %f" % (all/P))) 34 | 35 | shutdown() 36 | -------------------------------------------------------------------------------- /examples/Sieve.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | from pycsp_import import * 8 | 9 | @process 10 | def producer(cout, cnt): 11 | for i in range(2,cnt): 12 | cout(i) 13 | poison(cout) 14 | 15 | @process 16 | def worker(cin, cout): 17 | try: 18 | ccout=None 19 | my_prime=cin() 20 | cout(my_prime) 21 | child_channel=Channel() 22 | ccout=child_channel.writer() 23 | Spawn(worker(child_channel.reader(), cout)) 24 | while True: 25 | new_prime=cin() 26 | if new_prime%my_prime: 27 | ccout(new_prime) 28 | except ChannelPoisonException: 29 | if ccout: 30 | poison(ccout) 31 | else: 32 | poison(cout) 33 | 34 | @process 35 | def printer(cin): 36 | while True: 37 | print(cin()) 38 | 39 | 40 | first=Channel() 41 | outc=Channel() 42 | 43 | Parallel(producer(first.writer(),2000), 44 | worker(first.reader(), outc.writer()), 45 | printer(outc.reader())) 46 | 47 | 48 | shutdown() 49 | -------------------------------------------------------------------------------- /examples/TerminationRacePoison.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | from pycsp_import import * 8 | import sys 9 | 10 | @process 11 | def source(chan_out): 12 | for i in range(10): 13 | chan_out("Hello world (%d)\n" % (i)) 14 | poison(chan_out) 15 | 16 | @process 17 | def sink(chan_in): 18 | while True: 19 | sys.stdout.write(chan_in()) 20 | 21 | chan = Channel() 22 | Parallel(source(chan.writer()) * 5, 23 | sink(chan.reader()) * 5) 24 | 25 | shutdown() 26 | -------------------------------------------------------------------------------- /examples/TerminationRaceRetire.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | from pycsp_import import * 8 | import sys 9 | 10 | @process 11 | def source(chan_out): 12 | for i in range(10): 13 | chan_out("Hello world (%d)\n" % (i)) 14 | retire(chan_out) 15 | 16 | @process 17 | def sink(chan_in): 18 | while True: 19 | sys.stdout.write(chan_in()) 20 | 21 | chan = Channel() 22 | Parallel(source(chan.writer()) * 5, 23 | sink(chan.reader()) * 5) 24 | 25 | shutdown() 26 | -------------------------------------------------------------------------------- /examples/TokenRing.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | import sys 8 | from pycsp_import import * 9 | 10 | elements = 64 11 | 12 | @process 13 | def element(this_read, next_write): 14 | while True: 15 | token = this_read() 16 | next_write(token + 1) 17 | 18 | @process 19 | def root(cycles, this_read, next_write): 20 | next_write(1) 21 | token = this_read() 22 | 23 | sys.stdout.write("start\n") 24 | sys.stdout.flush() 25 | while cycles: 26 | next_write(token + 1) 27 | token = this_read() 28 | cycles = cycles - 1 29 | sys.stdout.write("end\n") 30 | sys.stdout.flush() 31 | 32 | sys.stdout.write(str(token) + "\n") 33 | 34 | retire(next_write, this_read) 35 | 36 | def ring(args): 37 | global elements 38 | cycles = 0 39 | if len(args) > 0: 40 | cycles = int(args[0]) 41 | 42 | head = Channel() 43 | this = head 44 | 45 | #chanlist to avoid Channel() datastructures to be gb_collected, when used in element processes 46 | chanlist = [head] 47 | 48 | for i in range(elements - 1): 49 | next = Channel() 50 | chanlist.append(next) 51 | Spawn(element(this.reader(), next.writer())) 52 | this = next 53 | 54 | Parallel(root(cycles, this.reader(), head.writer())) 55 | 56 | if __name__ == "__main__": 57 | ring(sys.argv[2:]) 58 | 59 | shutdown() 60 | -------------------------------------------------------------------------------- /examples/WebServer.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | from pycsp_import import * 8 | import socket 9 | import time 10 | import sys 11 | 12 | PORT = 8081 13 | 14 | @process 15 | def HelloWorld(register): 16 | request_channel = Channel('HelloWorld'+str(id)) 17 | cin = +request_channel 18 | register((b'/hello.html', -request_channel)) 19 | while True: 20 | (request_string, cout) = cin() 21 | cout(b"Hello at " + time.strftime("%H:%M:%S", time.localtime()).encode()) 22 | 23 | @process 24 | def Time(register): 25 | request_chan = Channel('Time-'+str(id)) 26 | cin = +request_chan 27 | register((b'/time.html', -request_chan)) 28 | 29 | while True: 30 | (request_string, cout) = cin() 31 | cout(str(time.time()).encode()) 32 | 33 | @process 34 | def Index(id, register): 35 | request_chan = Channel('Index-'+str(id)) 36 | cin = +request_chan 37 | register((b'/index.html', -request_chan)) 38 | register((b'/', -request_chan)) 39 | 40 | while True: 41 | (request_string, cout) = cin() 42 | s = b"Hello World! :" + request_string 43 | s += b"
Visit time or sleep" 44 | s += b"

Served by process " + str(id).encode() 45 | cout(s) 46 | 47 | @io 48 | def time_sleep(s): 49 | import time 50 | time.sleep(s) 51 | 52 | @process 53 | def Sleep(id, register): 54 | request_chan = Channel('Sleep-'+str(id)) 55 | cin = +request_chan 56 | register((b'/sleep.html', -request_chan)) 57 | 58 | while True: 59 | (request_string, cout) = cin() 60 | seconds = 0 61 | if request_string.find(b'?') != -1: 62 | try: 63 | seconds = int(request_string[request_string.index(b'?')+1:]) 64 | except Exception as e: 65 | print(e) 66 | 67 | if type(seconds) == type(0): 68 | s = b"Process " + str(id).encode() + b" is going to sleep for " +str(seconds).encode() + b" seconds" 69 | cout(s) 70 | 71 | time_sleep(seconds) 72 | 73 | else: 74 | s = str(ms) + " is not a number!" 75 | cout(s) 76 | 77 | 78 | 79 | 80 | @process 81 | def Dispatcher(register, inc): 82 | services = {} 83 | 84 | def dispatch(channel_input): 85 | (GET, result) = channel_input 86 | 87 | print(b'Dispather got:',GET,result) 88 | 89 | if GET.find(b'?') != -1: 90 | service_id = GET[:GET.index(b'?')] 91 | else: 92 | service_id = GET 93 | 94 | # Dispatch to service by Alternating on output ends. 95 | if service_id in services: 96 | guards = [] 97 | for req in services[service_id]: 98 | guards.append( OutputGuard(req, msg=(GET, result)) ) 99 | AltSelect(*guards) 100 | else: 101 | result(b"Service '"+str(service_id).encode() + b"' not found!
") 102 | 103 | def add_service(channel_input): 104 | (id, request) = channel_input 105 | if id in services: 106 | services[id].append(request) 107 | else: 108 | services[id] = [request] 109 | 110 | try: 111 | while True: 112 | AltSelect( 113 | InputGuard(register, action=add_service), 114 | InputGuard(inc, action=dispatch) 115 | ) 116 | 117 | except ChannelPoisonException: 118 | poison(register, inc) 119 | for regs in list(services.values()): 120 | poison(*regs) 121 | 122 | @process 123 | def HTTPsocket(sock, dispatchChan): 124 | answer=b'HTTP/1.0 200 OK\nServer: BaseHTTP/0.2 Python/2.2\nDate: Tue, 18 Feb 2003 17:15:49 GMT\nContent-Type: text/html\nServer: myHandler\n\n' 125 | 126 | item = Channel() 127 | itemOut = -item 128 | itemIn = +item 129 | 130 | conn, addr=sock 131 | req=conn.recv(256) 132 | if not req: 133 | conn.close() 134 | return 135 | lines = req.split(b'\n') 136 | for line in lines: 137 | line=line.split(b' ') 138 | if line[0]==b'GET': 139 | conn.sendall(answer) 140 | dispatchChan((line[1], itemOut)) 141 | conn.sendall(itemIn()) 142 | 143 | conn.shutdown(socket.SHUT_RDWR) 144 | conn.close() 145 | 146 | 147 | @io 148 | def serversocket_accept(serversocket): 149 | return serversocket.accept() 150 | 151 | @process 152 | def entry(request): 153 | serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 154 | 155 | # Enable reuse of sockets in TIME_WAIT state. 156 | serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 157 | 158 | serversocket.bind(('', PORT)) 159 | 160 | print(("Listening on http://localhost:" + str(PORT))) 161 | 162 | serversocket.listen(1) 163 | 164 | while True: 165 | s = serversocket_accept(serversocket) 166 | Spawn(HTTPsocket(s, -request)) 167 | 168 | 169 | register=Channel('Register Service') 170 | request=Channel('Request Service') 171 | 172 | Parallel(entry(request), 173 | Dispatcher(+register, +request), 174 | [Time(-register) for i in range(2)], 175 | [Sleep(i, -register) for i in range(50)], 176 | [Index(i, -register) for i in range(2)], 177 | HelloWorld(-register)) 178 | 179 | shutdown() 180 | -------------------------------------------------------------------------------- /examples/problems/deadlock_doing_alternation_on_input_and_output_pre_0.6.1.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. THE 14 | SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | """ 22 | # Diamond setup, with 4 channels and 4 processes. 23 | 24 | # In versions of pycsp from 0.5.0 to 0.6.0 the locking mechanism will produce a deadlock, 25 | # when multiple processes are doing an alternation on an input and output guard. 26 | # 27 | # The locks is acquired in write-read order and produces a deadlock eventually. 28 | # 29 | # PyCSP 0.6.1 fixes this issue by introducing ordering of locks by memory address, before actual locking. 30 | 31 | from pycsp_import import * 32 | 33 | @process 34 | def P(id, c1, c2): 35 | for i in range(10000): 36 | Alternation([{(c1,True):None, c2:None}]).select() 37 | poison(c1,c2) 38 | 39 | if __name__=='__main__': 40 | c1 = Channel('c1') 41 | c2 = Channel('c2') 42 | c3 = Channel('c3') 43 | c4 = Channel('c4') 44 | 45 | Parallel(P(1,c1.writer(), c2.reader()), 46 | P(2,c2.writer(), c3.reader()), 47 | P(3,c3.writer(), c4.reader()), 48 | P(4,c4.writer(), c1.reader())) 49 | 50 | shutdown() 51 | -------------------------------------------------------------------------------- /examples/problems/greenlets_differentiate_between_deadlocking_and_all_executed_processes_pre_0.7.0.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. THE 14 | SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | """ 22 | # Creating a deadlock on purpose, by reading on a channel with no writers. 23 | 24 | # In pycsp.greenlets pre 0.7.0 this should be blocking, but instead it 25 | # releases the Parallel construct as if all processes had been executed. 26 | 27 | # In PyCSP 0.7.0 this issue is fixed, and since we can detect when all 28 | # existing processes are blocked on channels, we now raise an Exception with the 29 | # message Deadlock! 30 | 31 | from pycsp_import import * 32 | 33 | A = Channel() 34 | 35 | @process 36 | def P(cin): 37 | cin() 38 | 39 | Parallel(P(A.reader())) 40 | 41 | shutdown() 42 | -------------------------------------------------------------------------------- /examples/problems/greenlets_exception_propagation_from_io_functions_pre_0.7.1.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. THE 14 | SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | """ 22 | # No exception propagation from within @pycsp.greenlets.io-decorated functions. 23 | 24 | # In pycsp.greenlets pre 0.7.1 this does not propagate exceptions. 25 | 26 | from pycsp_import import * 27 | import time 28 | 29 | @io 30 | def blocking(): 31 | time.sleep(1) 32 | raise Exception('OMG!') 33 | 34 | @process 35 | def show(): 36 | try: 37 | blocking() 38 | except Exception as ex: 39 | print('Exception caught: %s' % str(ex)) 40 | else: 41 | print('No exception!') 42 | 43 | Parallel(show()) 44 | -------------------------------------------------------------------------------- /examples/problems/greenlets_unable_to_communicate_on_channels_from_main_namespace_pre_0.7.1.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. THE 14 | SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | """ 22 | # Communicating on channels from the main namespace 23 | 24 | # In pycsp.greenlets pre 0.7.1 this fails, because the main namespace 25 | # cannot be scheduled, by the greenlet scheduler. 26 | 27 | # In PyCSP 0.7.1 this issue is fixed. 28 | 29 | from pycsp_import import * 30 | 31 | @process 32 | def func(cout): 33 | while True: 34 | cout(42) 35 | 36 | 37 | ch = Channel() 38 | cin, cout = +ch, -ch 39 | Spawn(func(cout)) 40 | 41 | print(cin()) 42 | 43 | poison(cin) 44 | 45 | shutdown() 46 | -------------------------------------------------------------------------------- /examples/problems/parallel_leaking_mobile_channelend_garbage_collection_pre_0.9.2.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg 4 | """ 5 | 6 | import sys 7 | from pycsp_import import * 8 | from random import randint 9 | 10 | # Running this multiple times, eventually causes a deadlock with output looking like this: 11 | # python parallel_leaking_mobile_channelend_garbage_collection.py 12 | # 192.168.0.12 80 13 | # 192.168.0.12 80 14 | # 192.168.0.12 80 15 | # Simulated HTTP Server got: Hello?705 16 | # 192.168.0.12 80 17 | # ... 18 | # ... 19 | # Simulated HTTP Server got: Hello?910 20 | # Simulated HTTP Server got: Hello?480 21 | # Bye 22 | # Simulated HTTP Server got: Hello?43 23 | # Simulated HTTP Server got: Hello?910 24 | # Bye 25 | # Bye 26 | 27 | @process 28 | def do_service(outp): 29 | conn = Channel() 30 | outp(conn.writer()) 31 | inp = conn.reader() 32 | 33 | while True: 34 | msg = inp() 35 | outp('Simulated HTTP Server got: '+msg) 36 | #outp.disconnect() / explicit disconnect was necessary, before this was fixed. 37 | 38 | @process 39 | def server(IPin): 40 | for _ in range(10): #Only do 10 services then terminate 41 | addr, port, conn = IPin() 42 | print(addr,port) 43 | Spawn(do_service(conn)) 44 | 45 | print('Major bye') 46 | 47 | @process 48 | def client(IPout): 49 | id = randint(0,1000) 50 | conn = Channel() 51 | IPout(('192.168.0.12',80,conn.writer())) 52 | 53 | inp = conn.reader() 54 | # Receiving new channel end 55 | outp = inp() 56 | 57 | for _ in range(10): 58 | outp('Hello?%d'%id) 59 | msg = inp() 60 | print(msg) 61 | print('Bye') 62 | poison(outp) 63 | 64 | service = Channel() 65 | 66 | Parallel(server(service.reader()), 10*client(service.writer())) 67 | print('Parallel returned...') 68 | 69 | shutdown() 70 | -------------------------------------------------------------------------------- /examples/problems/parallel_nesting_multiprocess_in_process.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: latin-1 -*- 3 | """ 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. THE 16 | SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | """ 24 | from pycsp_import import * 25 | import time 26 | 27 | @multiprocess 28 | def Prefix(cin, cout, prefixItem=None): 29 | t = prefixItem 30 | while True: 31 | cout(t) 32 | t = cin() 33 | 34 | @multiprocess 35 | def Delta2(cin, cout1, cout2): 36 | while True: 37 | t = cin() 38 | cout1(t) 39 | cout2(t) 40 | 41 | @multiprocess 42 | def Successor(cin, cout): 43 | """Adds 1 to the value read on the input channel and outputs it on the output channel. 44 | Infinite loop. 45 | """ 46 | while True: 47 | cout(cin()+1) 48 | 49 | @multiprocess 50 | def Consumer(cin): 51 | "Commstime consumer process" 52 | N = 1000 53 | ts = time.time 54 | t1 = ts() 55 | cin() 56 | t1 = ts() 57 | for i in range(N): 58 | cin() 59 | t2 = ts() 60 | dt = t2-t1 61 | tchan = dt / (4 * N) 62 | print("DT = %f.\nTime per ch : %f/(4*%d) = %f s = %f us" % \ 63 | (dt, dt, N, tchan, tchan * 1000000)) 64 | print("consumer done, posioning channel") 65 | poison(cin) 66 | 67 | @process 68 | def CommsTimeBM(): 69 | # Create channels 70 | a = Channel("a") 71 | b = Channel("b") 72 | c = Channel("c") 73 | d = Channel("d") 74 | 75 | print("Running commstime test") 76 | Parallel(Prefix(+c, -a, prefixItem = 0), # initiator 77 | Delta2(+a, -b, -d), # forwarding to two 78 | Successor(+b, -c), # feeding back to prefix 79 | Consumer(+d)) # timing process 80 | 81 | N_BM = 10 82 | for i in range(N_BM): 83 | print("----------- run %d/%d -------------" % (i+1, N_BM)) 84 | Parallel(CommsTimeBM()) 85 | 86 | shutdown() 87 | -------------------------------------------------------------------------------- /examples/problems/pycsp_import.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | import sys 7 | sys.path.insert(0,"../..") 8 | 9 | if len(sys.argv) > 1: 10 | mod = sys.argv[1] 11 | else: 12 | mod = '' 13 | 14 | if (mod == 'parallel'): 15 | from pycsp.parallel import * 16 | elif (mod == 'greenlets'): 17 | from pycsp.greenlets import * 18 | else: 19 | print("python",sys.argv[0],"[ parallel | greenlets ]") 20 | from pycsp.parallel import * 21 | 22 | print('Using version', version) 23 | 24 | -------------------------------------------------------------------------------- /examples/pycsp_import.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | import sys 7 | sys.path.insert(0,"..") 8 | 9 | if len(sys.argv) > 1: 10 | mod = sys.argv[1] 11 | else: 12 | mod = '' 13 | 14 | if (mod == 'parallel'): 15 | from pycsp.parallel import * 16 | elif (mod == 'greenlets'): 17 | from pycsp.greenlets import * 18 | else: 19 | print("python",sys.argv[0],"[ parallel | greenlets ]") 20 | from pycsp.parallel import * 21 | 22 | print('Using version', version) 23 | 24 | -------------------------------------------------------------------------------- /pycsp/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | PyCSP implementation of the CSP Core functionality (Channels, Processes, PAR, ALT). 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | 8 | Versions available: parallel, greenlets 9 | Channels can not be used to communicate between versions. 10 | 11 | Modules available 12 | > import pycsp.parallel 13 | > import pycsp.greenlets 14 | 15 | > import pycsp.common.trace 16 | > import pycsp.common.plugNplay 17 | > import pycsp.common.toolkit 18 | """ 19 | 20 | # Import parallel by default to enable "import pycsp" 21 | if not __name__ == '__main__': 22 | from pycsp.parallel import * 23 | -------------------------------------------------------------------------------- /pycsp/common/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ['toolkit', 'plugNplay','trace','six'] 2 | -------------------------------------------------------------------------------- /pycsp/common/const.py: -------------------------------------------------------------------------------- 1 | """ 2 | Constants 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | """ 8 | 9 | # Operation type 10 | READ, WRITE = list(range(2)) 11 | 12 | # Result of a channel request (ChannelReq) 13 | FAIL, SUCCESS = list(range(2)) 14 | 15 | # State of a channel request status (ReqStatus) 16 | ACTIVE, DONE = list(range(2)) 17 | 18 | # Constants used for both ChannelReq results and ReqStatus states. 19 | POISON, RETIRE = list(range(2,4)) 20 | -------------------------------------------------------------------------------- /pycsp/common/plugNplay.py: -------------------------------------------------------------------------------- 1 | """ 2 | PlugNPlay module 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | """ 8 | import pycsp.current 9 | 10 | @pycsp.current.process 11 | def Identity(cin, cout): 12 | """Copies its input stream to its output stream, adding a one-place buffer 13 | to the stream.""" 14 | while True: 15 | t = cin() 16 | cout(t) 17 | 18 | @pycsp.current.process 19 | def Prefix(cin, cout, prefix=None): 20 | t = prefix 21 | while True: 22 | cout(t) 23 | t = cin() 24 | 25 | @pycsp.current.process 26 | def Successor(cin, cout): 27 | """Adds 1 to the value read on the input channel and outputs it on the output channel. 28 | Infinite loop. 29 | """ 30 | while True: 31 | cout(cin()+1) 32 | 33 | @pycsp.current.process 34 | def Delta2(cin, cout1, cout2): 35 | while True: 36 | msg = cin() 37 | pycsp.current.Alternation([{ 38 | (cout1,msg):'cout2(msg)', 39 | (cout2,msg):'cout1(msg)' 40 | }]).execute() 41 | 42 | @pycsp.current.process 43 | def Plus(cin1, cin2, cout): 44 | while True: 45 | cout(cin1() + cin2()) 46 | 47 | @pycsp.current.process 48 | def Tail(cin, cout): 49 | dispose = cin() 50 | while True: 51 | cout(cin()) 52 | 53 | @pycsp.current.process 54 | def Pairs(cin, cout): 55 | pA, pB, pC = pycsp.current.Channel('pA'), pycsp.current.Channel('pB'), pycsp.current.Channel('pC') 56 | pycsp.current.Parallel( 57 | Delta2(cin, -pA, -pB), 58 | Plus(+pA, +pC, cout), 59 | Tail(+pB, -pC) 60 | ) 61 | 62 | @pycsp.current.process 63 | def SkipProcess(): 64 | pass 65 | 66 | @pycsp.current.process 67 | def Mux2(cin1, cin2, cout): 68 | alt = pycsp.current.Alternation([{cin1:None, cin2:None}]) 69 | while True: 70 | guard, msg = alt.select() 71 | cout(msg) 72 | -------------------------------------------------------------------------------- /pycsp/common/toolkit.py: -------------------------------------------------------------------------------- 1 | """ 2 | Toolkit module 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | """ 8 | 9 | 10 | from pycsp.common.six import string_types 11 | import pycsp.current as pycsp 12 | 13 | if pycsp.trace: 14 | from pycsp.common import trace as pycsp 15 | 16 | import subprocess 17 | import types 18 | 19 | 20 | def which(cmd): 21 | P = subprocess.Popen(args=('which', cmd), stdin=None, stdout=subprocess.PIPE) 22 | (stdout, _) = P.communicate() 23 | return stdout.strip() 24 | 25 | 26 | @pycsp.process 27 | def file_r(cout, file, retire_on_eof=True, sep="\n"): 28 | 29 | if isinstance(file, string_types): 30 | file = open(file, 'r') 31 | 32 | try: 33 | buf = [] 34 | line = file.readline() 35 | while (line): 36 | buf.append(line) 37 | if buf[-1].find(sep) > -1: 38 | cout(buf) 39 | buf = [] 40 | line = file.readline() 41 | if buf: 42 | cout(buf) 43 | except: 44 | pass 45 | 46 | file.close() 47 | if retire_on_eof: 48 | pycsp.retire(cout) 49 | 50 | 51 | @pycsp.process 52 | def file_w(cin, file): 53 | 54 | if isinstance(file, string_types): 55 | file = open(file, 'w') 56 | 57 | try: 58 | while True: 59 | data = cin() 60 | if type(data) == list: 61 | file.write(''.join(data)) 62 | else: 63 | file.write(data) 64 | file.flush() 65 | except: 66 | file.close() 67 | 68 | 69 | @pycsp.process 70 | def runner(cin): 71 | while True: 72 | command, stdinChEnd, stdoutChEnd, stderrChEnd = cin() 73 | 74 | pycsp.Sequence( 75 | execute(command, stdinChEnd, stdoutChEnd, stderrChEnd) 76 | ) 77 | 78 | 79 | @pycsp.process 80 | def execute(command, stdinChEnd=None, stdoutChEnd=None, stderrChEnd=None, retire_on_eof=True): 81 | 82 | stdin, stdout, stderr = [None]*3 83 | if stdinChEnd: stdin = subprocess.PIPE 84 | if stdoutChEnd: stdout = subprocess.PIPE 85 | if stderrChEnd: stderr = subprocess.PIPE 86 | 87 | P = subprocess.Popen(args=command, 88 | stdin=stdin, 89 | stdout=stdout, 90 | stderr=stderr) 91 | 92 | @pycsp.choice 93 | def handle_stdin(channel_input, stdin): 94 | stdin.write(channel_input) 95 | stdin.flush() 96 | 97 | @pycsp.choice 98 | def forwarder(channel_input, cout): 99 | cout(channel_input) 100 | 101 | 102 | altList = [] 103 | if stdinChEnd: 104 | altList.append((stdinChEnd, handle_stdin(stdin=P.stdin))) 105 | 106 | if stdoutChEnd: 107 | C1 = pycsp.Channel() 108 | C1in = C1.reader() 109 | pycsp.Spawn(file_r(C1.writer(), P.stdout)) 110 | altList.append((C1in, forwarder(cout=stdoutChEnd))) 111 | 112 | if stderrChEnd: 113 | C2 = pycsp.Channel() 114 | C2in = C2.reader() 115 | pycsp.Spawn(file_r(C2.writer(), P.stderr)) 116 | altList.append((C2in, forwarder(cout=stderrChEnd))) 117 | 118 | if altList: 119 | alt = pycsp.Alternation(altList) 120 | 121 | try: 122 | while True: 123 | alt.execute() 124 | 125 | except pycsp.ChannelRetireException: 126 | # stdout has reached eof 127 | if stdoutChEnd: 128 | pycsp.retire(C1in) 129 | if stderrChEnd: 130 | pycsp.retire(C2in) 131 | 132 | if retire_on_eof: 133 | if stdoutChEnd: 134 | pycsp.retire(stdoutChEnd) 135 | if stderrChEnd: 136 | pycsp.retire(stderrChEnd) 137 | 138 | else: 139 | 140 | P.wait() 141 | 142 | -------------------------------------------------------------------------------- /pycsp/current/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | A container which is updated with the pycsp version in use. Making it possible to import pycsp.current from pycsp.common modules. 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | """ 8 | -------------------------------------------------------------------------------- /pycsp/greenlets/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | PyCSP.greenlets implementation of the CSP Core functionality (Channels, Processes, PAR, ALT). 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | """ 8 | 9 | # Test for Greenlets 10 | import sys 11 | try: from greenlet import greenlet 12 | except ImportError as e: 13 | try: from py.magic import greenlet 14 | except ImportError as e: 15 | sys.stderr.write("PyCSP.greenlets requires the greenlet module, recommended version is 0.2 or above and is\navailable from http://pypi.python.org/pypi/greenlet/.\n\n") 16 | raise ImportError(e) 17 | 18 | # Imports 19 | from pycsp.greenlets.scheduling import Io, io 20 | from pycsp.greenlets.guard import Skip, Timeout, SkipGuard, TimeoutGuard 21 | from pycsp.greenlets.alternation import choice, Alternation 22 | from pycsp.greenlets.altselect import FairSelect, AltSelect, PriSelect, InputGuard, OutputGuard 23 | from pycsp.greenlets.channel import Channel 24 | from pycsp.greenlets.channelend import retire, poison 25 | from pycsp.greenlets.process import Process, process, Sequence, Parallel, Spawn, current_process_id 26 | from pycsp.greenlets.exceptions import ChannelPoisonException, ChannelRetireException, FatalException, InfoException 27 | from pycsp.greenlets.compat import * 28 | 29 | __all__ = ['Skip', 'SkipGuard', 'Timeout', 'TimeoutGuard', 'InputGuard', 'OutputGuard', 'choice', 'Alternation', 'FairSelect', 'AltSelect', 'PriSelect', 'Channel', 'retire', 'poison', 'Process', 'process', 'MultiProcess', 'multiprocess', 'ClusterProcess', 'clusterprocess', 'SSHProcess', 'sshprocess', 'Sequence', 'Parallel', 'Spawn', 'current_process_id', 'shutdown', 'ChannelRetireException', 'ChannelPoisonException', 'ChannelSocketException', 'InfoException', 'FatalException', 'io', 'Io', 'Configuration', 'SOCKETS_CONNECT_TIMEOUT', 'SOCKETS_CONNECT_RETRY_DELAY', 'SOCKETS_BIND_TIMEOUT', 'SOCKETS_BIND_RETRY_DELAY', 'PYCSP_PORT', 'PYCSP_HOST', 'SOCKETS_STRICT_MODE', 'version'] 30 | 31 | version = (0,9,2, 'greenlets') 32 | 33 | # Set current implementation 34 | import pycsp.current 35 | pycsp.current.version = version 36 | pycsp.current.trace = False 37 | 38 | pycsp.current.Skip = Skip 39 | pycsp.current.Timeout = Timeout 40 | pycsp.current.SkipGuard = SkipGuard 41 | pycsp.current.TimeoutGuard = TimeoutGuard 42 | pycsp.current.choice = choice 43 | pycsp.current.Alternation = Alternation 44 | pycsp.current.Channel = Channel 45 | pycsp.current.ChannelPoisonException = ChannelPoisonException 46 | pycsp.current.ChannelRetireException = ChannelRetireException 47 | pycsp.current.ChannelSocketException = ChannelSocketException 48 | pycsp.current.FatalException = FatalException 49 | pycsp.current.InfoException = InfoException 50 | pycsp.current.retire = retire 51 | pycsp.current.poison = poison 52 | pycsp.current.io = io 53 | pycsp.current.Process = Process 54 | pycsp.current.process = process 55 | pycsp.current.Sequence = Sequence 56 | pycsp.current.Parallel = Parallel 57 | pycsp.current.Spawn = Spawn 58 | pycsp.current.current_process_id = current_process_id 59 | pycsp.current.FairSelect = FairSelect 60 | pycsp.current.AltSelect = AltSelect 61 | pycsp.current.PriSelect = PriSelect 62 | pycsp.current.InputGuard = InputGuard 63 | pycsp.current.OutputGuard = OutputGuard 64 | pycsp.current.shutdown = shutdown 65 | -------------------------------------------------------------------------------- /pycsp/greenlets/alternation.py: -------------------------------------------------------------------------------- 1 | """ 2 | Alternation module 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | """ 8 | 9 | # Imports 10 | import inspect 11 | import types 12 | from pycsp.greenlets.channel import * 13 | from pycsp.common.const import * 14 | import collections 15 | 16 | # Decorators 17 | def choice(func): 18 | """ 19 | Decorator for creating choice objets 20 | """ 21 | # __choice_fn func_name used to identify function in Alternation.execute 22 | def __choice_fn(*args, **kwargs): 23 | return Choice(func, *args, **kwargs) 24 | return __choice_fn 25 | 26 | # Classes 27 | class Choice(object): 28 | """ Choice(func, *args, **kwargs) 29 | It is recommended to use the @choice decorator, to create Choice instances 30 | """ 31 | def __init__(self, fn, *args, **kwargs): 32 | self.fn = fn 33 | self.args = args 34 | self.kwargs = kwargs 35 | 36 | def invoke_on_input(self, channel_input): 37 | self.kwargs['channel_input'] = channel_input 38 | self.fn(*self.args, **self.kwargs) 39 | del self.kwargs['channel_input'] 40 | 41 | def invoke_on_output(self): 42 | self.fn(*self.args, **self.kwargs) 43 | 44 | 45 | class Alternation(object): 46 | """ 47 | Alternation supports input and output guards. Guards are ChannelEnd 48 | or Guard objects. 49 | 50 | Note that alternation always performs the guard that was chosen, 51 | i.e. channel input or output is executed within the alternation so 52 | even the empty choice with an alternation execution or a choice where 53 | the results are simply ignored, still performs the guarded input or 54 | output. 55 | """ 56 | def __init__(self, guards, ensurePriority=True): 57 | # Preserve tuple entries and convert dictionary entries to tuple entries 58 | self.guards = [] 59 | for g in guards: 60 | if type(g) == tuple: 61 | self.guards.append(g) 62 | elif type(g) == dict: 63 | for elem in list(g.keys()): 64 | if type(elem) == tuple: 65 | self.guards.append((elem[0], elem[1], g[elem])) 66 | else: 67 | self.guards.append((elem, g[elem])) 68 | 69 | # The internal representation of guards is a prioritized list 70 | # of tuples: 71 | # input guard: (channel end, action) 72 | # output guard: (channel end, msg, action) 73 | 74 | self.s = Scheduler() 75 | 76 | # Default is to go one up in stackframe. 77 | self.execute_frame = -1 78 | 79 | def _set_execute_frame(self, steps): 80 | if steps > 0: 81 | self.execute_frame = -1*steps 82 | else: 83 | self.execute_frame = steps 84 | 85 | def __result(self, reqs): 86 | act=None 87 | poison=False 88 | retire=False 89 | for req in list(reqs.keys()): 90 | _, c, op = reqs[req] 91 | if op==READ: 92 | c._remove_read(req) 93 | else: 94 | c._remove_write(req) 95 | if req.result==SUCCESS: 96 | act=req 97 | if req.result==POISON: 98 | poison=True 99 | if req.result==RETIRE: 100 | retire=True 101 | return (act, poison, retire) 102 | 103 | def choose(self): 104 | reqs={} 105 | act = None 106 | poison = False 107 | retire = False 108 | 109 | self.s.current.setstate(ACTIVE) 110 | try: 111 | idx = 0 112 | for prio_item in self.guards: 113 | if len(prio_item) == 3: 114 | c, msg, action = prio_item 115 | req = ChannelReq(self.s.current, msg=msg) 116 | c._post_write(req) 117 | op=WRITE 118 | else: 119 | c, action = prio_item 120 | req = ChannelReq(self.s.current) 121 | c._post_read(req) 122 | op=READ 123 | reqs[req]=(idx, c, op) 124 | idx += 1 125 | except ChannelPoisonException: 126 | act, poison, retire = self.__result(reqs) 127 | if not act: 128 | raise ChannelPoisonException 129 | except ChannelRetireException: 130 | act, poison, retire = self.__result(reqs) 131 | if not act: 132 | raise ChannelRetireException 133 | 134 | # If noone have offered a channelrequest, we wait. 135 | if not act: 136 | self.s.current.wait() 137 | 138 | if not act: 139 | act, poison, retire = self.__result(reqs) 140 | 141 | if not act: 142 | if poison: 143 | raise ChannelPoisonException() 144 | if retire: 145 | raise ChannelRetireException() 146 | 147 | print('We should not get here in choice!!!') 148 | 149 | idx, c, op = reqs[act] 150 | return (idx, act, c, op) 151 | 152 | def execute(self): 153 | """ 154 | Selects the guard and executes the attached action. Action is a function or python code passed in a string. 155 | """ 156 | idx, req, c, op = self.choose() 157 | if self.guards[idx]: 158 | action = self.guards[idx][-1] 159 | 160 | # Executing Choice object method 161 | if isinstance(action, Choice): 162 | if op==WRITE: 163 | action.invoke_on_output() 164 | else: 165 | action.invoke_on_input(req.msg) 166 | 167 | # Executing callback function object 168 | elif isinstance(action, collections.Callable): 169 | # Choice function not allowed as callback 170 | if type(action) == types.FunctionType and action.__name__ == '__choice_fn': 171 | raise Exception('@choice function is not instantiated. Please use action() and not just action') 172 | else: 173 | # Execute callback function 174 | if op==WRITE: 175 | action() 176 | else: 177 | action(channel_input=req.msg) 178 | 179 | # Compiling and executing string 180 | elif type(action) == str: 181 | # Fetch process frame and namespace 182 | processframe= inspect.currentframe() 183 | steps = self.execute_frame 184 | while (steps < 0): 185 | processframe = processframe.f_back 186 | steps += 1 187 | 188 | # Compile source provided in a string. 189 | code = compile(action,processframe.f_code.co_filename + ' line ' + str(processframe.f_lineno) + ' in string' ,'exec') 190 | f_globals = processframe.f_globals 191 | f_locals = processframe.f_locals 192 | if op==READ: 193 | f_locals.update({'channel_input':req.msg}) 194 | 195 | # Execute action 196 | exec(code, f_globals, f_locals) 197 | 198 | elif type(action) == type(None): 199 | pass 200 | else: 201 | raise Exception('Failed executing action: '+str(action)) 202 | 203 | return (c, req.msg) 204 | 205 | def select(self): 206 | """ 207 | Selects the guard. 208 | """ 209 | idx, req, c, op = self.choose() 210 | return (c, req.msg) 211 | 212 | -------------------------------------------------------------------------------- /pycsp/greenlets/buffer.py: -------------------------------------------------------------------------------- 1 | """ 2 | BufferedChannel implementation. 3 | 4 | Automatically instantiated if buffer argument is used. 5 | 6 | A = Channel(buffer=10) 7 | 8 | Copyright (c) 2009 John Markus Bjoerndalen , 9 | Brian Vinter , Rune M. Friborg . 10 | See LICENSE.txt for licensing details (MIT License). 11 | """ 12 | 13 | from pycsp.greenlets.channel import Channel, ChannelPoisonException, ChannelRetireException 14 | from pycsp.greenlets.channelend import poison, retire 15 | from pycsp.greenlets.process import process, Spawn 16 | from pycsp.greenlets.alternation import Alternation 17 | 18 | import pycsp.current 19 | if pycsp.current.trace: 20 | from pycsp.common.trace import * 21 | 22 | from collections import deque 23 | import time, random 24 | 25 | class BufferedChannel(object): 26 | """ Channel class. 27 | Blocking or buffered communication. 28 | 29 | >>> from pycsp import * 30 | 31 | >>> @process 32 | ... def P1(cout): 33 | ... while True: 34 | ... cout('Hello World') 35 | 36 | >>> C = Channel() 37 | >>> Spawn(P1(C.writer())) 38 | 39 | >>> cin = C.reader() 40 | >>> cin() 41 | 'Hello World' 42 | 43 | >>> retire(cin) 44 | 45 | Buffered channels are semantically equivalent with a chain 46 | of forwarding processes. 47 | >>> B = Channel(buffer=5) 48 | >>> cout = B.writer() 49 | >>> for i in range(5): 50 | ... cout(i) 51 | 52 | Poison and retire are attached to final element of the buffer. 53 | >>> poison(cout) 54 | 55 | >>> @process 56 | ... def sink(cin, L): 57 | ... while True: 58 | ... L.append(cin()) 59 | 60 | >>> L = [] 61 | >>> Parallel(sink(B.reader(), L)) 62 | >>> L 63 | [0, 1, 2, 3, 4] 64 | """ 65 | def __init__(self, name=None, buffer=1): 66 | if name == None: 67 | # Create unique name 68 | name = str(random.random())+str(time.time()) 69 | 70 | self.name = name 71 | self.__inChan = Channel(name=name+'inChan') 72 | self.__outChan = Channel(name=name+'outChan') 73 | self.__bufferProcess = self.Buffer(self.__inChan.reader(), 74 | self.__outChan.writer(), 75 | N=buffer) 76 | 77 | # Retrieve channel ends 78 | self.reader = self.__outChan.reader 79 | self.writer = self.__inChan.writer 80 | 81 | # Set buffer process as deamon to allow kill if mother process 82 | # exists. 83 | self.__bufferProcess.daemon = True 84 | 85 | # Start buffer process 86 | Spawn(self.__bufferProcess) 87 | 88 | def __pos__(self): 89 | return self.reader() 90 | 91 | def __neg__(self): 92 | return self.writer() 93 | 94 | def poison(self): 95 | self.__inChan.poison() 96 | self.__outChan.poison() 97 | 98 | @process 99 | def Buffer(self, cin, cout, N): 100 | queue = deque() 101 | poisoned = False 102 | retired = False 103 | while True: 104 | try: 105 | import pycsp.current 106 | if pycsp.current.trace: 107 | TraceMsg(len(queue)) 108 | 109 | # Handling poison / retire 110 | if (poisoned or retired): 111 | if len(queue): 112 | try: 113 | cout(queue.popleft()) 114 | except: 115 | if poisoned: 116 | poison(cin, cout) 117 | if retired: 118 | retire(cin, cout) 119 | else: 120 | if poisoned: 121 | poison(cin, cout) 122 | if retired: 123 | retire(cin, cout) 124 | return # quit 125 | # Queue empty 126 | elif len(queue) == 0: 127 | queue.append(cin()) 128 | # Queue not full and not empty 129 | elif len(queue) < N: 130 | g, msg = Alternation([ 131 | (cout, queue[0], None), 132 | (cin, None) 133 | ]).select() 134 | if g == cin: 135 | queue.append(msg) 136 | else: 137 | queue.popleft() 138 | # Queue full 139 | else: 140 | cout(queue.popleft()) 141 | except ChannelPoisonException as e: 142 | poisoned = True 143 | except ChannelRetireException as e: 144 | retired = True 145 | -------------------------------------------------------------------------------- /pycsp/greenlets/channel.py: -------------------------------------------------------------------------------- 1 | """ 2 | Channel module 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | """ 8 | 9 | # Imports 10 | from pycsp.greenlets.scheduling import Scheduler 11 | from pycsp.greenlets.channelend import ChannelEndRead, ChannelEndWrite, ChannelRetireException 12 | from pycsp.greenlets.exceptions import * 13 | 14 | from pycsp.common.const import * 15 | 16 | import time, random 17 | 18 | # Classes 19 | class ChannelReq(object): 20 | def __init__(self, process, msg=None): 21 | self.msg = msg 22 | self.result = FAIL 23 | self.process = process 24 | 25 | def poison(self): 26 | if self.result != SUCCESS: 27 | self.result = POISON 28 | self.process.notify(POISON) 29 | 30 | def retire(self): 31 | if self.result != SUCCESS: 32 | self.result = RETIRE 33 | self.process.notify(RETIRE) 34 | 35 | def offer(self, recipient): 36 | if self.process.state == recipient.process.state == ACTIVE: 37 | recipient.msg= self.msg 38 | self.result=SUCCESS 39 | recipient.result=SUCCESS 40 | self.process.notify(DONE) 41 | recipient.process.notify(DONE) 42 | return True 43 | return False 44 | 45 | 46 | class Channel(object): 47 | """ Channel class. Blocking communication 48 | """ 49 | 50 | def __new__(cls, *args, **kargs): 51 | if 'buffer' in kargs and kargs['buffer'] > 0: 52 | from . import buffer 53 | chan = buffer.BufferedChannel(*args, **kargs) 54 | return chan 55 | else: 56 | return object.__new__(cls) 57 | 58 | def __init__(self, name=None, buffer=0): 59 | 60 | if name == None: 61 | # Create unique name 62 | self.name = str(random.random())+str(time.time()) 63 | else: 64 | self.name=name 65 | 66 | self.readqueue = [] 67 | self.writequeue = [] 68 | 69 | # Count, makes sure that all processes knows how many channel ends have retired 70 | self.readers = 0 71 | self.writers = 0 72 | 73 | self.ispoisoned = False 74 | self.isretired = False 75 | 76 | self.s = Scheduler() 77 | 78 | def check_termination(self): 79 | if self.ispoisoned: 80 | raise ChannelPoisonException() 81 | if self.isretired: 82 | raise ChannelRetireException() 83 | 84 | def _read(self): 85 | self.check_termination() 86 | 87 | p = self.s.current 88 | 89 | # If anyone is on the writequeue and ACTIVE, then we can do the match right away 90 | # This hack provides a 150% performance improvement and can be removed 91 | # without breaking anything. 92 | for w in self.writequeue: 93 | if w.process.state == ACTIVE: 94 | msg = w.msg 95 | w.result = SUCCESS 96 | w.process.state = DONE 97 | if p != w.process: 98 | self.s.nextQ.append(w.process) 99 | return msg 100 | 101 | p.setstate(ACTIVE) 102 | req = ChannelReq(p) 103 | self._post_read(req) 104 | req.process.wait() 105 | self._remove_read(req) 106 | 107 | if req.result==SUCCESS: 108 | return req.msg 109 | 110 | self.check_termination() 111 | 112 | print('We should not get here in read!!!') 113 | return None #Here we should handle that a read was cancled... 114 | 115 | 116 | def _write(self, msg): 117 | self.check_termination() 118 | 119 | p = self.s.current 120 | 121 | # If anyone is on the readqueue and ACTIVE, then we can do the match right away 122 | # This hack provides a 150% performance improvement and can be removed 123 | # without breaking anything. 124 | for r in self.readqueue: 125 | if r.process.state == ACTIVE: 126 | r.msg = msg 127 | r.result = SUCCESS 128 | r.process.state = DONE 129 | if p != r.process: 130 | self.s.nextQ.append(r.process) 131 | return True 132 | 133 | p.setstate(ACTIVE) 134 | req = ChannelReq(p,msg=msg) 135 | self._post_write(req) 136 | req.process.wait() 137 | self._remove_write(req) 138 | 139 | if req.result==SUCCESS: 140 | return True 141 | 142 | self.check_termination() 143 | 144 | print('We should not get here in write!!!') 145 | return None #Here we should handle that a read was cancled... 146 | 147 | def _post_read(self, req): 148 | self.check_termination() 149 | self.readqueue.append(req) 150 | self.match() 151 | 152 | def _remove_read(self, req): 153 | self.readqueue.remove(req) 154 | 155 | def _post_write(self, req): 156 | self.check_termination() 157 | self.writequeue.append(req) 158 | self.match() 159 | 160 | def _remove_write(self, req): 161 | self.writequeue.remove(req) 162 | 163 | def match(self): 164 | if self.readqueue and self.writequeue: 165 | for w in self.writequeue: 166 | for r in self.readqueue: 167 | if w.offer(r): 168 | # Did an offer 169 | # We can guarantee, that there will always be someone to call offer, 170 | # since everything is run in a single thread. Thus we break the loop. 171 | return 172 | 173 | def poison(self): 174 | if not self.ispoisoned: 175 | self.ispoisoned = True 176 | list(map(ChannelReq.poison, self.readqueue)) 177 | list(map(ChannelReq.poison, self.writequeue)) 178 | 179 | def __pos__(self): 180 | return self.reader() 181 | 182 | def __neg__(self): 183 | return self.writer() 184 | 185 | def __mul__(self, multiplier): 186 | new = [self] 187 | for i in range(multiplier-1): 188 | new.append(Channel(name=self.name+str(i+1))) 189 | return new 190 | 191 | def __rmul__(self, multiplier): 192 | return self.__mul__(multiplier) 193 | 194 | def reader(self): 195 | self.join_reader() 196 | return ChannelEndRead(self) 197 | 198 | def writer(self): 199 | self.join_writer() 200 | return ChannelEndWrite(self) 201 | 202 | def join_reader(self): 203 | self.readers+=1 204 | 205 | def join_writer(self): 206 | self.writers+=1 207 | 208 | def leave_reader(self): 209 | if not self.isretired: 210 | self.readers-=1 211 | if self.readers==0: 212 | # Set channel retired 213 | self.isretired = True 214 | for p in self.writequeue[:]: 215 | p.retire() 216 | 217 | def leave_writer(self): 218 | if not self.isretired: 219 | self.writers-=1 220 | if self.writers==0: 221 | # Set channel retired 222 | self.isretired = True 223 | for p in self.readqueue[:]: # ATOMIC copy 224 | p.retire() 225 | 226 | -------------------------------------------------------------------------------- /pycsp/greenlets/channelend.py: -------------------------------------------------------------------------------- 1 | """ 2 | Channelend module 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | """ 8 | 9 | from pycsp.greenlets.exceptions import * 10 | from pycsp.common.const import * 11 | 12 | def retire(*list_of_channelEnds): 13 | """ Retire reader or writer, to do auto-poisoning 14 | When all readers or writer of a channel have retired. The channel is retired. 15 | """ 16 | for channelEnd in list_of_channelEnds: 17 | channelEnd.retire() 18 | 19 | def poison(*list_of_channelEnds): 20 | """ Poison channel 21 | """ 22 | for channelEnd in list_of_channelEnds: 23 | channelEnd.poison() 24 | 25 | # Classes 26 | class ChannelEndWrite(object): 27 | def __init__(self, channel): 28 | self.channel = channel 29 | self._op = WRITE 30 | 31 | # Prevention against multiple retires 32 | self.isretired = False 33 | 34 | self._post_write = self.channel._post_write 35 | self._remove_write = self.channel._remove_write 36 | self.poison = self.channel.poison 37 | 38 | def __lt__(self, other): 39 | # Needed for sorting in FairSelect 40 | return self 41 | 42 | def __call__(self, *args, **kwargs): 43 | return self.channel._write(*args, **kwargs) 44 | 45 | def _retire(self, *ignore): 46 | raise ChannelRetireException() 47 | 48 | def retire(self): 49 | if not self.isretired: 50 | self.channel.leave_writer() 51 | self.__call__ = self._retire 52 | self._post_write = self._retire 53 | self.isretired = True 54 | 55 | def __repr__(self): 56 | if self.channel.name == None: 57 | return "" % self.channel 58 | else: 59 | return "" % (self.channel, self.channel.name) 60 | 61 | def isWriter(self): 62 | return True 63 | 64 | def isReader(self): 65 | return False 66 | 67 | class ChannelEndRead(object): 68 | def __init__(self, channel): 69 | self.channel = channel 70 | self._op = READ 71 | 72 | # Prevention against multiple retires 73 | self.isretired = False 74 | 75 | self._post_read = self.channel._post_read 76 | self._remove_read = self.channel._remove_read 77 | self.poison = self.channel.poison 78 | 79 | def __lt__(self, other): 80 | # Needed for sorting in FairSelect 81 | return self 82 | 83 | def __call__(self, *args, **kwargs): 84 | return self.channel._read(*args, **kwargs) 85 | 86 | def _retire(self, *ignore): 87 | raise ChannelRetireException() 88 | 89 | def retire(self): 90 | if not self.isretired: 91 | self.channel.leave_reader() 92 | self.__call__ = self._retire 93 | self._post_read = self._retire 94 | self.isretired = True 95 | 96 | def __repr__(self): 97 | if self.channel.name == None: 98 | return "" % self.channel 99 | else: 100 | return "" % (self.channel, self.channel.name) 101 | 102 | def isWriter(self): 103 | return False 104 | 105 | def isReader(self): 106 | return True 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /pycsp/greenlets/compat.py: -------------------------------------------------------------------------------- 1 | """ 2 | Constructs added to allow easy switching between PyCSP implementations. 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | """ 8 | 9 | from pycsp.greenlets.exceptions import * 10 | 11 | def shutdown(): 12 | """ 13 | Perform shutdown of non-active hosted channels. Wait 14 | for active hosted channels to become non-active. 15 | """ 16 | return 17 | 18 | def multiprocess(func=None, pycsp_host='', pycsp_port=None): 19 | raise InfoException("multiprocess not available for greenlets. Use pycsp.parallel") 20 | 21 | class MultiProcess(object): 22 | def __init__(self, fn, *args, **kwargs): 23 | raise InfoException("MultiProcess not available for greenlets. Use pycsp.parallel") 24 | 25 | def sshprocess(func=None, pycsp_host='', pycsp_port=0, ssh_host='localhost', ssh_port=22, ssh_user=None, ssh_password=None, ssh_python='python'): 26 | raise InfoException("sshprocess not available for greenlets. Use pycsp.parallel") 27 | 28 | class SSHProcess(object): 29 | def __init__(self, fn, *args, **kwargs): 30 | raise InfoException("SSHProcess not available for greenlets. Use pycsp.parallel") 31 | 32 | def clusterprocess(func=None, cluster_nodefile="$PBS_NODEFILE", cluster_pin=None, cluster_hint='blocked', cluster_ssh_port=22, cluster_python='python'): 33 | raise InfoException("clusterprocess not available for greenlets. Use pycsp.parallel") 34 | 35 | class ClusterProcess(object): 36 | def __init__(self, fn, *args, **kwargs): 37 | raise InfoException("ClusterProcess not available for greenlets. Use pycsp.parallel") 38 | 39 | class ChannelSocketException(Exception): 40 | def __init__(self, addr, msg): 41 | self.msg = msg 42 | self.addr = addr 43 | def __str__(self): 44 | return repr("%s %s" % (self.msg, self.addr)) 45 | 46 | 47 | SOCKETS_CONNECT_TIMEOUT = 0 48 | SOCKETS_CONNECT_RETRY_DELAY = 1 49 | SOCKETS_BIND_TIMEOUT = 2 50 | SOCKETS_BIND_RETRY_DELAY = 3 51 | PYCSP_PORT = 5 52 | PYCSP_HOST = 6 53 | SOCKETS_STRICT_MODE = 4 54 | 55 | class Configuration(object): 56 | """ 57 | This is dummy Configuration class, as the greenlets 58 | does not require any configuration. 59 | """ 60 | __instance = None # the unique instance 61 | __conf = {} 62 | 63 | def __new__(cls, *args, **kargs): 64 | return cls.getInstance(cls, *args, **kargs) 65 | 66 | def __init__(self): 67 | pass 68 | 69 | def getInstance(cls, *args, **kwargs): 70 | '''Static method to have a reference to **THE UNIQUE** instance''' 71 | if cls.__instance is None: 72 | # Initialize **the unique** instance 73 | cls.__instance = object.__new__(cls) 74 | 75 | cls.__conf = { 76 | SOCKETS_CONNECT_TIMEOUT:0, 77 | SOCKETS_CONNECT_RETRY_DELAY:0, 78 | SOCKETS_BIND_TIMEOUT:0, 79 | SOCKETS_BIND_RETRY_DELAY:0, 80 | PYCSP_PORT:0, 81 | PYCSP_HOST:'', 82 | SOCKETS_STRICT_MODE:False 83 | } 84 | 85 | return cls.__instance 86 | getInstance = classmethod(getInstance) 87 | 88 | def get(self, conf_id): 89 | return self.__conf[conf_id] 90 | 91 | def set(self, conf_id, value): 92 | self.__conf[conf_id] = value 93 | 94 | 95 | -------------------------------------------------------------------------------- /pycsp/greenlets/exceptions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Public and private exceptions 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | """ 8 | 9 | # Public exceptions 10 | class ChannelPoisonException(Exception): 11 | def __init__(self): 12 | pass 13 | 14 | class ChannelRetireException(Exception): 15 | def __init__(self): 16 | pass 17 | 18 | class FatalException(Exception): 19 | def __init__(self, msg): 20 | self.msg = msg 21 | def __str__(self): 22 | return repr(self.msg) 23 | 24 | class InfoException(Exception): 25 | def __init__(self, msg): 26 | self.msg = msg 27 | def __str__(self): 28 | return repr(self.msg) 29 | -------------------------------------------------------------------------------- /pycsp/greenlets/guard.py: -------------------------------------------------------------------------------- 1 | """ 2 | Adds Skip and Timeout guards 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | """ 8 | 9 | # Imports 10 | from pycsp.greenlets.scheduling import Scheduler 11 | from pycsp.greenlets.channel import ChannelReq 12 | from pycsp.greenlets.process import Process 13 | from pycsp.common.const import * 14 | 15 | # Classes 16 | class Guard(object): 17 | """ 18 | The empty interface of a guard. 19 | """ 20 | def _post_read(self, req): 21 | pass 22 | 23 | def _post_write(self, req): 24 | pass 25 | 26 | def _remove_read(self, req): 27 | pass 28 | 29 | def _remove_write(self, req): 30 | pass 31 | 32 | 33 | class SkipGuard(Guard): 34 | """ 35 | Skip will try to accept a read or a write, the moment it is posted. 36 | """ 37 | def __init__(self, action=None): 38 | self.g = (self, action) 39 | 40 | def empty(self): 41 | pass 42 | 43 | # Start process 44 | def process(self): 45 | p = Process(self.empty) 46 | p.start() 47 | p.setstate(ACTIVE) 48 | return p 49 | 50 | # Offer instantly 51 | def _post_read(self, reader): 52 | ChannelReq(self.process(), msg=None).offer(reader) 53 | 54 | # Offer instantly 55 | def _post_write(self, writer): 56 | writer.offer(ChannelReq(self.process())) 57 | 58 | 59 | class TimeoutGuard(Guard): 60 | """ 61 | Timeout spawns a timer thread, when posted. If removed 62 | before timeout, then the timer thread is cancelled. 63 | """ 64 | def __init__(self, seconds, action=None): 65 | self.seconds = seconds 66 | 67 | self.posted = (None, None) 68 | self.s = Scheduler() 69 | self.p = None 70 | 71 | self.g = (self, action) 72 | 73 | # Timer expired, offer an active Channel Request 74 | def expire(self): 75 | op, req = self.posted 76 | if op == READ: 77 | ChannelReq(self.p, msg=None).offer(req) 78 | elif op == WRITE: 79 | req.offer(ChannelReq(self.p)) 80 | 81 | def _post_read(self, reader): 82 | self.posted = (READ, reader) 83 | 84 | # Start process 85 | self.p = Process(self.expire) 86 | self.p.start() 87 | self.p.setstate(ACTIVE) 88 | 89 | # Put process on the scheduler timer queue 90 | self.s.timer_wait(self.p, self.seconds) 91 | 92 | def _post_write(self, writer): 93 | self.posted = (WRITE, writer) 94 | 95 | # Start process 96 | self.p = Process(self.expire) 97 | self.p.start() 98 | self.p.setstate(ACTIVE) 99 | 100 | # Put process on the scheduler timer queue 101 | self.s.timer_wait(self.p, self.seconds) 102 | 103 | def _remove_read(self, req): 104 | self.s.timer_cancel(self.p) 105 | 106 | def _remove_write(self, req): 107 | self.s.timer_cancel(self.p) 108 | 109 | # Backwards compatibility 110 | Skip = SkipGuard 111 | Timeout = TimeoutGuard 112 | 113 | -------------------------------------------------------------------------------- /pycsp/greenlets/process.py: -------------------------------------------------------------------------------- 1 | """ 2 | Processes and execution 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | """ 8 | 9 | # Imports 10 | try: from greenlet import greenlet 11 | except ImportError as e: 12 | from py.magic import greenlet 13 | 14 | import time, random 15 | import types 16 | from pycsp.greenlets.scheduling import Scheduler 17 | from pycsp.greenlets.channel import ChannelPoisonException, ChannelRetireException 18 | from pycsp.common.const import * 19 | 20 | # Decorators 21 | def process(func): 22 | """ 23 | @process decorator for creating process functions 24 | """ 25 | def _call(*args, **kwargs): 26 | return Process(func, *args, **kwargs) 27 | return _call 28 | 29 | # Classes 30 | class Process(object): 31 | """ Process(fn, *args, **kwargs) 32 | It is recommended to use the @process decorator, to create Process instances 33 | See process.__doc__ 34 | """ 35 | def __init__(self, fn, *args, **kwargs): 36 | self.fn = fn 37 | self.args = args 38 | self.kwargs = kwargs 39 | self.return_value = None 40 | 41 | # Create unique id 42 | self.id = str(random.random())+str(time.time()) 43 | 44 | # Greenlet specific 45 | self.greenlet = None 46 | 47 | # Synchronization specific 48 | self.state = None 49 | self.s = Scheduler() 50 | self.executed = False 51 | 52 | def setstate(self, new_state): 53 | self.state = new_state 54 | 55 | # Reschedule, without putting this process on either the next[] or the blocking[] list. 56 | def wait(self): 57 | while self.state == ACTIVE: 58 | self.s.getNext().greenlet.switch() 59 | 60 | # Notify, by activating and setting state. 61 | def notify(self, new_state, force=False): 62 | self.state = new_state 63 | 64 | # Only activate, if we are activating someone other than ourselves 65 | # or we force an activation, which happens when an Io thread finishes, while 66 | # the calling process is still current process. 67 | if self.s.current != self or force: 68 | self.s.activate(self) 69 | 70 | 71 | # Init greenlet code 72 | # It must be called from the main thread. 73 | # Since we are only allowing that processes may be created in the main 74 | # thread or in other processes we can be certain that we are running in 75 | # the main thread. 76 | def start(self): 77 | self.greenlet = greenlet(self.run) 78 | 79 | # Main process execution 80 | def run(self): 81 | self.executed = False 82 | try: 83 | self.return_value = self.fn(*self.args, **self.kwargs) 84 | except ChannelPoisonException: 85 | # look for channels and channel ends 86 | self.__check_poison(self.args) 87 | self.__check_poison(list(self.kwargs.values())) 88 | except ChannelRetireException: 89 | # look for channel ends 90 | self.__check_retire(self.args) 91 | self.__check_retire(list(self.kwargs.values())) 92 | self.executed = True 93 | 94 | 95 | def __check_poison(self, args): 96 | for arg in args: 97 | try: 98 | if list == type(arg) or tuple == type(arg): 99 | self.__check_poison(arg) 100 | elif dict == type(arg): 101 | self.__check_poison(list(arg.keys())) 102 | self.__check_poison(list(arg.values())) 103 | elif type(arg.poison) == types.MethodType: 104 | arg.poison() 105 | except AttributeError: 106 | pass 107 | 108 | def __check_retire(self, args): 109 | for arg in args: 110 | try: 111 | if list == type(arg) or tuple == type(arg): 112 | self.__check_retire(arg) 113 | elif dict == type(arg): 114 | self.__check_retire(list(arg.keys())) 115 | self.__check_retire(list(arg.values())) 116 | elif type(arg.retire) == types.MethodType: 117 | # Ignore if try to retire an already retired channel end. 118 | try: 119 | arg.retire() 120 | except ChannelRetireException: 121 | pass 122 | except AttributeError: 123 | pass 124 | 125 | # syntactic sugar: Process() * 2 == [Process<1>,Process<2>] 126 | def __mul__(self, multiplier): 127 | return [self] + [Process(self.fn, *self.__mul_channel_ends(self.args), **self.__mul_channel_ends(self.kwargs)) for i in range(multiplier - 1)] 128 | 129 | # syntactic sugar: 2 * Process() == [Process<1>,Process<2>] 130 | def __rmul__(self, multiplier): 131 | return [self] + [Process(self.fn, *self.__mul_channel_ends(self.args), **self.__mul_channel_ends(self.kwargs)) for i in range(multiplier - 1)] 132 | 133 | # Copy lists and dictionaries 134 | def __mul_channel_ends(self, args): 135 | if list == type(args) or tuple == type(args): 136 | R = [] 137 | for item in args: 138 | try: 139 | if type(item.isReader) == types.MethodType and item.isReader(): 140 | R.append(item.channel.reader()) 141 | elif type(item.isWriter) == types.MethodType and item.isWriter(): 142 | R.append(item.channel.writer()) 143 | except AttributeError: 144 | if item == list or item == dict or item == tuple: 145 | R.append(self.__mul_channel_ends(item)) 146 | else: 147 | R.append(item) 148 | 149 | if tuple == type(args): 150 | return tuple(R) 151 | else: 152 | return R 153 | 154 | elif dict == type(args): 155 | R = {} 156 | for key in args: 157 | try: 158 | if type(key.isReader) == types.MethodType and key.isReader(): 159 | R[key.channel.reader()] = args[key] 160 | elif type(key.isWriter) == types.MethodType and key.isWriter(): 161 | R[key.channel.writer()] = args[key] 162 | elif type(args[key].isReader) == types.MethodType and args[key].isReader(): 163 | R[key] = args[key].channel.reader() 164 | elif type(args[key].isWriter) == types.MethodType and args[key].isWriter(): 165 | R[key] = args[key].channel.writer() 166 | except AttributeError: 167 | if args[key] == list or args[key] == dict or args[key] == tuple: 168 | R[key] = self.__mul_channel_ends(args[key]) 169 | else: 170 | R[key] = args[key] 171 | return R 172 | return args 173 | 174 | 175 | def Parallel(*plist): 176 | """ Parallel(P1, [P2, .. ,PN]) 177 | 178 | Returns a list of return values from P1..PN 179 | """ 180 | return _parallel(plist, True) 181 | 182 | def Spawn(*plist): 183 | """ Spawn(P1, [P2, .. ,PN]) 184 | """ 185 | _parallel(plist, False) 186 | 187 | def _parallel(plist, block = True): 188 | processes=[] 189 | for p in plist: 190 | if type(p)==list: 191 | for q in p: 192 | processes.append(q) 193 | else: 194 | processes.append(p) 195 | 196 | for p in processes: 197 | p.start() 198 | 199 | s = Scheduler() 200 | s.addBulk(processes) 201 | 202 | if block: 203 | s.join(processes) 204 | return [p.return_value for p in processes] 205 | 206 | 207 | def Sequence(*plist): 208 | """ Sequence(P1, [P2, .. ,PN]) 209 | 210 | Returns a list of return values from P1..PN 211 | """ 212 | processes=[] 213 | for p in plist: 214 | if type(p)==list: 215 | for q in p: 216 | processes.append(q) 217 | else: 218 | processes.append(p) 219 | 220 | # For every process we simulate a new process_id. When executing 221 | # in Main thread/process we set the new id in a global variable. 222 | 223 | s = Scheduler() 224 | _p = s.current 225 | _p_original_id = _p.id 226 | return_values = [] 227 | for p in processes: 228 | _p.id = p.id 229 | 230 | # Call Run directly instead of start() and join() 231 | p.run() 232 | return_values.append(p.return_value) 233 | _p.id = _p_original_id 234 | return return_values 235 | 236 | def current_process_id(): 237 | s = Scheduler() 238 | g = s.current 239 | return g.id 240 | 241 | -------------------------------------------------------------------------------- /pycsp/parallel/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | PyCSP implementation of the CSP Core functionality (Channels, Processes, PAR, ALT). 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | """ 8 | 9 | # Imports 10 | 11 | from pycsp.parallel.guard import Skip, SkipGuard, Timeout, TimeoutGuard 12 | from pycsp.parallel.alternation import choice, Alternation 13 | from pycsp.parallel.altselect import FairSelect, PriSelect, AltSelect, InputGuard, OutputGuard 14 | from pycsp.parallel.channel import Channel, retire, poison 15 | from pycsp.parallel.process import Process, process, Sequence, Parallel, Spawn, current_process_id, shutdown 16 | from pycsp.parallel.multiprocess import MultiProcess, multiprocess 17 | from pycsp.parallel.sshprocess import SSHProcess, sshprocess 18 | from pycsp.parallel.clusterprocess import ClusterProcess, clusterprocess 19 | from pycsp.parallel.exceptions import ChannelRetireException, ChannelPoisonException, ChannelSocketException, ChannelConnectException, ChannelBindException, ChannelLostException, FatalException, InfoException 20 | from pycsp.parallel.configuration import * 21 | from pycsp.parallel.compat import * 22 | 23 | __all__ = ['Skip', 'SkipGuard', 'Timeout', 'TimeoutGuard', 'InputGuard', 'OutputGuard', 'choice', 'Alternation', 'FairSelect', 'PriSelect', 'AltSelect', 'Channel', 'retire', 'poison', 'Process', 'process', 'MultiProcess', 'multiprocess', 'ClusterProcess', 'clusterprocess', 'SSHProcess', 'sshprocess', 'Sequence', 'Parallel', 'Spawn', 'current_process_id', 'shutdown', 'ChannelRetireException', 'ChannelPoisonException', 'ChannelSocketException', 'ChannelConnectException', 'ChannelBindException', 'ChannelLostException', 'InfoException', 'FatalException', 'io', 'Io', 'Configuration', 'SOCKETS_CONNECT_TIMEOUT', 'SOCKETS_CONNECT_RETRY_DELAY', 'SOCKETS_BIND_TIMEOUT', 'SOCKETS_BIND_RETRY_DELAY', 'PYCSP_PORT', 'PYCSP_HOST', 'SOCKETS_STRICT_MODE', 'version'] 24 | 25 | version = (0,9,2, 'parallel') 26 | 27 | # Set current implementation 28 | import pycsp.current 29 | pycsp.current.version = version 30 | pycsp.current.trace = False 31 | 32 | pycsp.current.Skip = Skip 33 | pycsp.current.Timeout = Timeout 34 | pycsp.current.SkipGuard = SkipGuard 35 | pycsp.current.TimeoutGuard = TimeoutGuard 36 | pycsp.current.choice = choice 37 | pycsp.current.Alternation = Alternation 38 | pycsp.current.Channel = Channel 39 | pycsp.current.ChannelPoisonException = ChannelPoisonException 40 | pycsp.current.ChannelRetireException = ChannelRetireException 41 | pycsp.current.ChannelSocketException = ChannelSocketException 42 | pycsp.current.ChannelConnectException = ChannelConnectException 43 | pycsp.current.ChannelBindException = ChannelBindException 44 | pycsp.current.ChannelLostException = ChannelLostException 45 | pycsp.current.FatalException = FatalException 46 | pycsp.current.InfoException = InfoException 47 | pycsp.current.retire = retire 48 | pycsp.current.poison = poison 49 | pycsp.current.io = io 50 | pycsp.current.Process = Process 51 | pycsp.current.process = process 52 | pycsp.current.Sequence = Sequence 53 | pycsp.current.Parallel = Parallel 54 | pycsp.current.Spawn = Spawn 55 | pycsp.current.current_process_id = current_process_id 56 | pycsp.current.FairSelect = FairSelect 57 | pycsp.current.AltSelect = AltSelect 58 | pycsp.current.PriSelect = PriSelect 59 | pycsp.current.InputGuard = InputGuard 60 | pycsp.current.OutputGuard = OutputGuard 61 | pycsp.current.shutdown = shutdown 62 | 63 | pycsp.current.MultiProcess = MultiProcess 64 | pycsp.current.multiprocess = multiprocess 65 | pycsp.current.ClusterProcess = ClusterProcess 66 | pycsp.current.clusterprocess = clusterprocess 67 | pycsp.current.SSHProcess = SSHProcess 68 | pycsp.current.sshprocess = sshprocess 69 | 70 | -------------------------------------------------------------------------------- /pycsp/parallel/compat.py: -------------------------------------------------------------------------------- 1 | """ 2 | Constructs added to allow easy switching between PyCSP implementations. 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | """ 8 | 9 | class Io(object): 10 | pass 11 | 12 | def io(func): 13 | """ 14 | @io decorator for blocking io operations. 15 | In pycsp.parallel it has no effect, other than compatibility 16 | 17 | >>> @io 18 | ... def sleep(n): 19 | ... import time 20 | ... time.sleep(n) 21 | 22 | >>> sleep(0.01) 23 | """ 24 | return func 25 | -------------------------------------------------------------------------------- /pycsp/parallel/configuration.py: -------------------------------------------------------------------------------- 1 | """ 2 | Configuration module 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | """ 8 | 9 | # Constants 10 | SOCKETS_CONNECT_TIMEOUT = 0 11 | SOCKETS_CONNECT_RETRY_DELAY = 1 12 | SOCKETS_BIND_TIMEOUT = 2 13 | SOCKETS_BIND_RETRY_DELAY = 3 14 | PYCSP_PORT = 5 15 | PYCSP_HOST = 6 16 | 17 | SOCKETS_STRICT_MODE = 4 18 | 19 | # Classes 20 | class Configuration(object): 21 | """ 22 | Configuration is a singleton class. 23 | 24 | >>> A = Configuration() 25 | >>> B = Configuration() 26 | >>> A == B 27 | True 28 | 29 | Retrieve value ( default is 10) 30 | >>> Configuration().get(SOCKETS_CONNECT_TIMEOUT) 31 | 10 32 | 33 | Set value to 200 34 | >>> Configuration().set(SOCKETS_CONNECT_TIMEOUT, 200) 35 | >>> Configuration().get(SOCKETS_CONNECT_TIMEOUT) 36 | 200 37 | """ 38 | 39 | __instance = None # the unique instance 40 | __conf = {} 41 | 42 | def __new__(cls, *args, **kargs): 43 | return cls.getInstance(cls, *args, **kargs) 44 | 45 | def __init__(self): 46 | pass 47 | 48 | def getInstance(cls, *args, **kwargs): 49 | '''Static method to have a reference to **THE UNIQUE** instance''' 50 | if cls.__instance is None: 51 | # Initialize **the unique** instance 52 | cls.__instance = object.__new__(cls) 53 | 54 | cls.__conf = { 55 | SOCKETS_CONNECT_TIMEOUT:2, 56 | SOCKETS_CONNECT_RETRY_DELAY:0.2, 57 | SOCKETS_BIND_TIMEOUT:2, 58 | SOCKETS_BIND_RETRY_DELAY:0.2, 59 | PYCSP_PORT:0, 60 | PYCSP_HOST:'', 61 | SOCKETS_STRICT_MODE:False 62 | } 63 | 64 | return cls.__instance 65 | getInstance = classmethod(getInstance) 66 | 67 | def get(self, conf_id): 68 | return self.__conf[conf_id] 69 | 70 | def set(self, conf_id, value): 71 | self.__conf[conf_id] = value 72 | 73 | -------------------------------------------------------------------------------- /pycsp/parallel/const.py: -------------------------------------------------------------------------------- 1 | """ 2 | Constants 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | """ 8 | 9 | import threading 10 | try: 11 | import multiprocessing 12 | except: 13 | pass 14 | 15 | ENVVAL_PORT = 'PYCSP_PORT' 16 | ENVVAL_HOST = 'PYCSP_HOST' 17 | 18 | # Setup (consider moving to configuration.py) 19 | PICKLE_PROTOCOL= 2 20 | ENABLE_CACHE = 1 21 | 22 | # Operation type 23 | READ, WRITE = list(range(2)) 24 | 25 | # Constants used for both ChannelReq results and ReqStatus states. 26 | READY, FAIL, SUCCESS, POISON, RETIRE = list(range(5)) 27 | 28 | 29 | def getThreadAndName(init=True): 30 | thread = None 31 | name = None 32 | 33 | # Get thread from threading first, since if thread is set, then 34 | # we do not have to look up multiprocessing 35 | try: 36 | # compatible with Python 2.6+ 37 | thread = threading.current_thread() 38 | except AttributeError: 39 | # compatible with Python 2.5- 40 | thread = threading.currentThread() 41 | 42 | name = thread.getName() 43 | 44 | if name == 'MainThread': 45 | # This might be a multiprocess, thus multiprocessing must be checked 46 | p = None 47 | parent_pid = None 48 | try: 49 | p = multiprocessing.current_process() 50 | parent_pid = p._parent_pid 51 | except: 52 | pass 53 | 54 | if not parent_pid: 55 | # This is the main process! 56 | try: 57 | if thread.id: 58 | name = thread.id 59 | except AttributeError: 60 | # Not initialised yet 61 | pass 62 | else: 63 | # p is a MultiProcess 64 | thread = p 65 | name = p.name 66 | 67 | try: 68 | if thread.id: 69 | pass 70 | except AttributeError: 71 | if init: 72 | # Engaging auto init 73 | from pycsp.parallel.process import init 74 | init() 75 | 76 | return (thread, name) 77 | -------------------------------------------------------------------------------- /pycsp/parallel/exceptions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Public and private exceptions 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | """ 8 | 9 | # Public exceptions 10 | class ChannelPoisonException(Exception): 11 | """ ChannelPoisonException() 12 | 13 | Exception thrown by a read or write operation on a channel end. 14 | 15 | In case a ChannelPoisonException is raised in a CSP process and not caught, the CSP process 16 | will look for channel ends in the argument list and invoke a poison signal to every found channel end. 17 | 18 | The following network can be shutdown like this: 19 | >>> @process 20 | ... def P1(cin, cout): 21 | ... while True: 22 | ... cout(cin()+cin()) 23 | 24 | >>> L1, L2, L3 = Channel(), Channel(), Channel() 25 | >>> Parallel( 26 | ... P1(L1.reader(), L2.writer()), 27 | ... P1(L2.reader(), L3.writer()) 28 | ... ) 29 | >>> cout = L1.writer() 30 | 31 | The first P1 process will automatically propagate the signal to the other P1 process 32 | >>> cout.poison() 33 | 34 | Another configuration for process P1 using a custom propagation: 35 | >>> @process 36 | ... def P1(cin, cout): 37 | ... try: 38 | ... while True: 39 | ... cout(cin()+cin()) 40 | ... except ChannelPoisonException: 41 | ... print("Terminating P1") 42 | ... cout.poison() 43 | """ 44 | def __init__(self): 45 | pass 46 | 47 | class ChannelRetireException(Exception): 48 | """ ChannelRetireException() 49 | 50 | Exception thrown by a read or write operation on a channel end. 51 | 52 | In case a ChannelRetireException is raised in a CSP process and not caught, the CSP process 53 | will look for channel ends in the argument list and invoke a retire signal to every found channel end. 54 | 55 | The following network can be shutdown like this: 56 | >>> @process 57 | ... def P1(cin, cout): 58 | ... while True: 59 | ... cout(cin()+cin()) 60 | 61 | >>> L1, L2, L3 = Channel(), Channel(), Channel() 62 | >>> Parallel( 63 | ... P1(L1.reader(), L2.writer()), 64 | ... P1(L2.reader(), L3.writer()) 65 | ... ) 66 | >>> cout = L1.writer() 67 | 68 | The first P1 process will automatically propagate the signal to the other P1 process 69 | >>> cout.retire() 70 | 71 | Another configuration for process P1 using a custom propagation: 72 | >>> @process 73 | ... def P1(cin, cout): 74 | ... try: 75 | ... while True: 76 | ... cout(cin()+cin()) 77 | ... except ChannelRetireException: 78 | ... print("Terminating P1") 79 | ... cout.retire() 80 | """ 81 | def __init__(self): 82 | pass 83 | 84 | class ChannelSocketException(Exception): 85 | """ ChannelSocketException(addr, msg) 86 | 87 | The super class for the exceptions: 88 | ChannelConnectException(addr, msg) 89 | ChannelBindException(addr, msg) 90 | ChannelLostException(addr, msg) 91 | """ 92 | def __init__(self, addr, msg): 93 | self.msg = msg 94 | self.addr = addr 95 | def __str__(self): 96 | return repr("%s %s" % (self.msg, self.addr)) 97 | 98 | class ChannelConnectException(ChannelSocketException): 99 | """ ChannelConnectException(addr, msg) 100 | 101 | This exception is raised when a channel is unable to connect 102 | to the destination provided in the connect parameter. 103 | 104 | Usage: 105 | >>> try: 106 | ... A = Channel('A', connect=('unknown', 999)) 107 | ... except ChannelConnectException as e: 108 | ... print("Addr %s is unavailable\n", % (str(e.addr))) 109 | 110 | If a mobile channel end is sent to another remote interpreter, where 111 | the channel end is unable to reconnect with the channel host, then 112 | a ChannelConnectException is also raised. 113 | """ 114 | def __init__(self, addr, msg): 115 | ChannelSocketException.__init__(self, addr, msg) 116 | 117 | class ChannelBindException(ChannelSocketException): 118 | """ ChannelBindException(addr, msg) 119 | 120 | This exception is raised when PyCSP is unable to bind to a port. 121 | 122 | The host and port to bind to is ('', 0) which binds 123 | to 0.0.0.0 and any available port number, unless provided through 124 | environment variables, configuration variables or from parameters 125 | to multiprocess. 126 | 127 | Usage: 128 | >>> @multiprocess(port=99) 129 | ... def runner(chanName): 130 | ... A = Channel(chanName) 131 | ... cin = A.reader() 132 | ... print(cin()) 133 | 134 | >>> try: 135 | ... Parallel(runner('A')) 136 | ... except ChannelBindException: 137 | ... print("Can not bind to port 80") 138 | """ 139 | def __init__(self, addr, msg): 140 | ChannelSocketException.__init__(self, addr, msg) 141 | 142 | class ChannelLostException(ChannelSocketException): 143 | """ ChannelLostException(addr, msg) 144 | 145 | This exception is raised when PyCSP has a channel which is left 146 | in an unstable state caused by a broken network connection, which 147 | could not be reestablished. 148 | 149 | Usually PyCSP can not recover from this exception. 150 | """ 151 | def __init__(self, addr, msg): 152 | ChannelSocketException.__init__(self, addr, msg) 153 | 154 | 155 | class FatalException(Exception): 156 | """ FatalException(msg) 157 | 158 | This exception is raised if PyCSP is in an unexpected unstable state, which 159 | is guaranteed to be unrecoverable. 160 | """ 161 | def __init__(self, msg): 162 | self.msg = msg 163 | def __str__(self): 164 | return repr(self.msg) 165 | 166 | class InfoException(Exception): 167 | """ InfoException(msg) 168 | 169 | This exception is raised to inform that there is an error in the usage of 170 | PyCSP and also provide a likely solution to fix the error. 171 | """ 172 | def __init__(self, msg): 173 | self.msg = msg 174 | def __str__(self): 175 | return repr(self.msg) 176 | 177 | # Private exceptions 178 | class AddrUnavailableException(Exception): 179 | def __init__(self, addr): 180 | self.addr = addr 181 | def __str__(self): 182 | return repr(self.addr) 183 | 184 | class SocketException(Exception): 185 | def __init__(self): 186 | pass 187 | 188 | class SocketDispatchException(SocketException): 189 | def __init__(self): 190 | pass 191 | 192 | class SocketClosedException(SocketException): 193 | def __init__(self): 194 | pass 195 | 196 | class SocketConnectException(SocketException): 197 | def __init__(self): 198 | pass 199 | 200 | class SocketBindException(SocketException): 201 | def __init__(self, addr): 202 | self.addr = addr 203 | def __str__(self): 204 | return repr(self.addr) 205 | 206 | class SocketSendException(SocketException): 207 | def __init__(self): 208 | pass 209 | -------------------------------------------------------------------------------- /pycsp/parallel/guard.py: -------------------------------------------------------------------------------- 1 | """ 2 | Adds Skip and Timeout guards 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | """ 8 | 9 | # Imports 10 | import threading 11 | import uuid 12 | 13 | from pycsp.parallel.const import * 14 | from pycsp.parallel.protocol import AddrID, ChannelReq, LockMessenger 15 | from pycsp.parallel.dispatch import SocketDispatcher 16 | from pycsp.parallel.exceptions import * 17 | 18 | # Classes 19 | class Guard(object): 20 | """ 21 | The empty interface of a guard. 22 | """ 23 | def __init__(self, action=None): 24 | self.g = (self, action) 25 | 26 | # Id similar to channel name, to correctly select the chosen guard among the guard set. 27 | self.id = uuid.uuid1().hex 28 | self.id = self.id.encode() 29 | 30 | # Necessary to allow for correct locking 31 | self.dispatch = SocketDispatcher().getThread() 32 | self.dispatch.registerGuard(self.id) 33 | self.LM = LockMessenger(self.id) 34 | 35 | def _offer(self, req): 36 | try: 37 | # Acquire lock 38 | conn, state, seq = self.LM.remote_acquire_and_get_state(req.process) 39 | 40 | # Check sequence number 41 | if seq != req.seq_check: 42 | state = FAIL 43 | 44 | # Success? 45 | if (state == READY): 46 | self.LM.remote_notify(conn, req.process, req.ch_id, None) 47 | 48 | # Release lock 49 | self.LM.remote_release(conn, req.process) 50 | 51 | except AddrUnavailableException: 52 | # Unable to reach process during offer 53 | # The primary reason is probably because a request were part of an alting and the process have exited. 54 | if conf.get(SOCKETS_STRICT_MODE): 55 | raise FatalException("PyCSP unable to reach process during Guard.offer(%s)" % str(self.process)) 56 | else: 57 | sys.stderr.write("PyCSP unable to reach process during Guard.offer(%s)\n" % str(self.process)) 58 | 59 | def _close(self): 60 | # Invoked from Alternation 61 | self.dispatch.deregisterGuard(self.id) 62 | 63 | 64 | class SkipGuard(Guard): 65 | """ SkipGuard(action=None) 66 | 67 | SkipGuard will commit a successful communication the moment it is posted. 68 | 69 | Usage: 70 | >>> C = Channel() 71 | >>> Cin = C.reader() 72 | >>> (g, msg) = AltSelect(InputGuard(Cin), SkipGuard() ) 73 | 74 | SkipGuard(action=None) 75 | action 76 | An action may be provided as a string, a callable function object or a Choice object. 77 | The Choice object is the recommended use of action. 78 | 79 | A string: 80 | >>> action="L.append(channel_input)" 81 | 82 | The string passed to the action parameter is evaluted in the current namespace and can 83 | read variables, but can only write output by editing the content of existing mutable variables. 84 | Newly created immutable and mutable variables will only exist in the evalutation of this string. 85 | 86 | callable(func): 87 | >>> def func(channel_input=None) 88 | ... L.append(channel_input) 89 | >>> action=func 90 | 91 | The callable function object must accept one parameter for actions on InputGuards and must 92 | accept zero parameters for actions on OutputGuards. 93 | 94 | Choice: 95 | >>> @choice 96 | ... def func(L, channel_input=None) 97 | ... L.append(channel_input) 98 | >>> action=func(gatherList) 99 | 100 | The choice decorator can be used to make a Choice factory, which can generate actions with 101 | different parameters depending on the use case. See help(pycsp.choice) 102 | """ 103 | def __init__(self, action=None): 104 | Guard.__init__(self, action) 105 | 106 | # Offer instantly 107 | def _post_read(self, process, ack=False): 108 | proc_addr_id = AddrID(process.addr, process.id) 109 | self._offer(ChannelReq(self.LM, proc_addr_id, 110 | process.sequence_number, 111 | self.id)) 112 | 113 | # Send acknowledgement to process. (used to ensure prioritized select) 114 | if ack: 115 | self.LM.ack(proc_addr_id) 116 | 117 | 118 | def _post_write(self, process, msg, ask=False): 119 | raise InfoException("Can not use SkipGuard with msg") 120 | 121 | 122 | class TimeoutGuard(Guard): 123 | """ TimeoutGuard(seconds, action=None) 124 | 125 | TimeoutGuard spawns a timer thread, when posted. If removed 126 | before timeout, then the timer thread is cancelled. 127 | 128 | When the timer expires, the timer thread will commit a successful communication. 129 | 130 | Usage: 131 | >>> C = Channel() 132 | >>> Cin = C.reader() 133 | >>> (g, msg) = AltSelect( InputGuard(Cin), TimeoutGuard(seconds=0.5) ) 134 | 135 | TimeoutGuard(action=None) 136 | seconds 137 | Set the seconds to wait before timeout. eg. 0.5s 138 | action 139 | An action may be provided as a string, a callable function object or a Choice object. 140 | The Choice object is the recommended use of action. 141 | 142 | A string: 143 | >>> action="L.append(channel_input)" 144 | 145 | The string passed to the action parameter is evaluted in the current namespace and can 146 | read variables, but can only write output by editing the content of existing mutable variables. 147 | Newly created immutable and mutable variables will only exist in the evalutation of this string. 148 | 149 | callable(func): 150 | >>> def func(channel_input=None) 151 | ... L.append(channel_input) 152 | >>> action=func 153 | 154 | The callable function object must accept one parameter for actions on InputGuards and must 155 | accept zero parameters for actions on OutputGuards. 156 | 157 | Choice: 158 | >>> @choice 159 | ... def func(L, channel_input=None) 160 | ... L.append(channel_input) 161 | >>> action=func(gatherList) 162 | 163 | The choice decorator can be used to make a Choice factory, which can generate actions with 164 | different parameters depending on the use case. See help(pycsp.choice) 165 | """ 166 | def __init__(self, seconds, action=None): 167 | Guard.__init__(self, action) 168 | self.seconds = seconds 169 | self.posted_req = None 170 | self.timer_cancelled=False 171 | self.lock = threading.Lock() 172 | 173 | # Timer expired, offer an active Channel Request 174 | def _expire(self): 175 | self.lock.acquire() 176 | if not self.timer_cancelled: 177 | self._offer(self.posted_req) 178 | self.lock.release() 179 | 180 | def _post_read(self, process, ack=False): 181 | proc_addr_id = AddrID(process.addr, process.id) 182 | 183 | # Send acknowledgement to process. (used to ensure prioritized select) 184 | if ack: 185 | self.LM.ack(proc_addr_id) 186 | 187 | self.posted_req = ChannelReq(self.LM, proc_addr_id, 188 | process.sequence_number, 189 | self.id) 190 | self.timer = threading.Timer(self.seconds, self._expire) 191 | self.timer.start() 192 | 193 | def _close(self): 194 | self.lock.acquire() 195 | self.timer_cancelled=True 196 | Guard._close(self) 197 | self.lock.release() 198 | 199 | 200 | # Backwards compatibility 201 | Skip = SkipGuard 202 | Timeout = TimeoutGuard 203 | -------------------------------------------------------------------------------- /pycsp/parallel/header.py: -------------------------------------------------------------------------------- 1 | """ 2 | The header specification for the message protocol 3 | 4 | Copyright (c) 2009 John Markus Bjoerndalen , 5 | Brian Vinter , Rune M. Friborg . 6 | See LICENSE.txt for licensing details (MIT License). 7 | """ 8 | 9 | import ctypes 10 | from pycsp.parallel.const import * 11 | 12 | # Bit patters for selecting types 13 | GUARD_CMD = 1<<13 14 | PROCESS_CMD = 1<<12 15 | CHANNEL_CMD = 1<<11 16 | HAS_PAYLOAD = 1<<10 17 | REQ_REPLY = 1<<9 18 | IS_REPLY = 1<<8 19 | NATFIX = 1<<7 20 | IGN_UNKNOWN = 1<<6 21 | 22 | ERROR_CMD = 0 23 | 24 | """ 25 | GUARD_CMD, PROCESS_CMD and CHANNEL_CMD encodes the destination. 26 | HAS_PAYLOAD tells the receiver, that it must read N bytes containing a payload message 27 | REQ_REPLY informs that if the destination is not available, an error must be returned, such that the sender does not deadlock by waiting eternally for a reply 28 | IS_REPLY informs which queue to post the incoming message to. 29 | NATFIX informs that the receiving socket should also be used as a sending socket 30 | IGN_UNKNOWN informs that it is ok to drop this message, if the destination is not found 31 | """ 32 | 33 | # CMDs for processes 34 | LOCKTHREAD_ACQUIRE_LOCK = PROCESS_CMD | 0 | REQ_REPLY 35 | LOCKTHREAD_ACCEPT_LOCK = CHANNEL_CMD | GUARD_CMD | 1 | IS_REPLY 36 | LOCKTHREAD_UNAVAILABLE = CHANNEL_CMD | GUARD_CMD | 2 | IS_REPLY 37 | 38 | LOCKTHREAD_NOTIFY_SUCCESS = PROCESS_CMD | 3 | IS_REPLY | HAS_PAYLOAD 39 | LOCKTHREAD_POISON = PROCESS_CMD | 4 | IS_REPLY 40 | LOCKTHREAD_RETIRE = PROCESS_CMD | 5 | IS_REPLY 41 | LOCKTHREAD_RELEASE_LOCK = PROCESS_CMD | 6 | IS_REPLY | IGN_UNKNOWN 42 | LOCKTHREAD_QUIT = PROCESS_CMD | 30 43 | LOCKTHREAD_ACK = PROCESS_CMD | 42 44 | SOCKETTHREAD_SHUTDOWN = PROCESS_CMD | CHANNEL_CMD | 7 45 | SOCKETTHREAD_PING = PROCESS_CMD | CHANNEL_CMD | 20 46 | 47 | # CMDs for channels 48 | CHANTHREAD_JOIN_READER = CHANNEL_CMD | 8 49 | CHANTHREAD_JOIN_WRITER = CHANNEL_CMD | 9 50 | CHANTHREAD_RETIRE_READER = CHANNEL_CMD | 12 51 | CHANTHREAD_RETIRE_WRITER = CHANNEL_CMD | 13 52 | CHANTHREAD_POISON_READER = CHANNEL_CMD | 14 53 | CHANTHREAD_POISON_WRITER = CHANNEL_CMD | 15 54 | CHANTHREAD_REGISTER = CHANNEL_CMD | 16 55 | CHANTHREAD_DEREGISTER = CHANNEL_CMD | 17 56 | CHANTHREAD_POST_READ = CHANNEL_CMD | 18 57 | CHANTHREAD_POST_WRITE = CHANNEL_CMD | 19 | HAS_PAYLOAD 58 | CHANTHREAD_POST_ACK_READ = CHANNEL_CMD | 40 59 | CHANTHREAD_POST_ACK_WRITE = CHANNEL_CMD | 41 | HAS_PAYLOAD 60 | CHANTHREAD_ENTER = CHANNEL_CMD | 24 | NATFIX 61 | CHANTHREAD_LEAVE = CHANNEL_CMD | 26 62 | 63 | def cmd2str(cmd): 64 | """ 65 | Translate command IDs to their string representation 66 | 67 | Use for debugging and error messages 68 | """ 69 | D = { 70 | ERROR_CMD:"ERROR_CMD", 71 | LOCKTHREAD_ACQUIRE_LOCK :"LOCKTHREAD_ACQUIRE_LOCK", 72 | LOCKTHREAD_ACCEPT_LOCK :"LOCKTHREAD_ACCEPT_LOCK", 73 | LOCKTHREAD_UNAVAILABLE :"LOCKTHREAD_UNAVAILABLE", 74 | LOCKTHREAD_NOTIFY_SUCCESS:"LOCKTHREAD_NOTIFY_SUCCESS", 75 | LOCKTHREAD_POISON :"LOCKTHREAD_POISON", 76 | LOCKTHREAD_RETIRE :"LOCKTHREAD_RETIRE", 77 | LOCKTHREAD_RELEASE_LOCK :"LOCKTHREAD_RELEASE_LOCK", 78 | LOCKTHREAD_QUIT :"LOCKTHREAD_QUIT ", 79 | SOCKETTHREAD_SHUTDOWN :"SOCKETTHREAD_SHUTDOWN", 80 | CHANTHREAD_JOIN_READER :"CHANTHREAD_JOIN_READER", 81 | CHANTHREAD_JOIN_WRITER :"CHANTHREAD_JOIN_WRITER", 82 | CHANTHREAD_RETIRE_READER :"CHANTHREAD_RETIRE_READER", 83 | CHANTHREAD_RETIRE_WRITER :"CHANTHREAD_RETIRE_WRITER", 84 | CHANTHREAD_POISON_READER :"CHANTHREAD_POISON_READER", 85 | CHANTHREAD_POISON_WRITER :"CHANTHREAD_POISON_WRITER", 86 | CHANTHREAD_REGISTER :"CHANTHREAD_REGISTER", 87 | CHANTHREAD_DEREGISTER :"CHANTHREAD_DEREGISTER", 88 | CHANTHREAD_POST_READ :"CHANTHREAD_POST_READ", 89 | CHANTHREAD_POST_WRITE :"CHANTHREAD_POST_WRITE", 90 | CHANTHREAD_ENTER :"CHANTHREAD_ENTER", 91 | CHANTHREAD_LEAVE :"CHANTHREAD_LEAVE" 92 | } 93 | 94 | return D[cmd] 95 | 96 | 97 | class Header(ctypes.Structure): 98 | """ 99 | cmd : type of package 100 | id : string, uuid1 in bytes format 101 | seq_number : sequence number used for ignoring channel requests, that was left behind. 102 | arg : contains the payload size following this header 103 | _source_host,_source_port,_source_id enables the receiver to reply to a message 104 | _result_id : updated with the chosen channel in an offer and match 105 | """ 106 | _fields_ = [ 107 | ("cmd", ctypes.c_short), 108 | ("id", ctypes.c_char * 64), 109 | ("seq_number", ctypes.c_long), 110 | ("arg", ctypes.c_long), 111 | ("_source_host", ctypes.c_char * 16), 112 | ("_source_port", ctypes.c_int), 113 | ("_source_id", ctypes.c_char * 64), 114 | ("_result_id", ctypes.c_char * 64) 115 | ] 116 | 117 | -------------------------------------------------------------------------------- /pycsp/parallel/noderunner.py: -------------------------------------------------------------------------------- 1 | """ 2 | NodeRunner module 3 | 4 | Requires the paramiko module. 5 | 6 | Copyright (c) 2009 Rune M. Friborg . 7 | See LICENSE.txt for licensing details (MIT License). 8 | """ 9 | 10 | # Imports 11 | import sys 12 | import threading 13 | 14 | 15 | try: 16 | import multiprocessing 17 | MULTIPROCESSING_ENABLED=1 18 | except ImportError: 19 | MULTIPROCESSING_ENABLED=0 20 | 21 | has_paramiko= False 22 | try: 23 | import paramiko, select 24 | has_paramiko= True 25 | except ImportError as e: 26 | # Ignore for now 27 | pass 28 | 29 | from pycsp.parallel.channel import Channel 30 | 31 | 32 | class NodeRunnerThread(threading.Thread): 33 | def __init__(self, ssh_host, ssh_port, ssh_python, cwd, arg_chan_host, arg_chan_port, arg_chan_name): 34 | threading.Thread.__init__(self) 35 | 36 | self.ssh_host = ssh_host 37 | self.ssh_port = ssh_port 38 | self.ssh_python = ssh_python 39 | self.ssh_user = None 40 | self.ssh_password = None 41 | self.cwd = cwd 42 | self.arg_chan_host = arg_chan_host 43 | self.arg_chan_port = arg_chan_port 44 | self.arg_chan_name = arg_chan_name 45 | 46 | def run(self): 47 | 48 | try: 49 | 50 | client = paramiko.SSHClient() 51 | client.load_system_host_keys() 52 | client.set_missing_host_key_policy(paramiko.WarningPolicy()) 53 | 54 | client.connect(self.ssh_host, port=self.ssh_port, username=self.ssh_user, password=self.ssh_password) 55 | 56 | command= " ".join(["/usr/bin/env", 57 | self.ssh_python, "-m", "pycsp.parallel.server", 58 | self.cwd, self.arg_chan_host, self.arg_chan_port, self.arg_chan_name]) 59 | 60 | transport = client.get_transport() 61 | session = transport.open_session() 62 | session.exec_command(command) 63 | 64 | while True: 65 | (r, w, e) = select.select([session], [], [], 10) 66 | if r: 67 | got_data = False 68 | if session.recv_ready(): 69 | data = r[0].recv(4096) 70 | if data: 71 | got_data = True 72 | sys.stdout.write(data.decode()) 73 | if session.recv_stderr_ready(): 74 | data = r[0].recv_stderr(4096) 75 | if data: 76 | got_data = True 77 | sys.stderr.write(data.decode()) 78 | if not got_data: 79 | break 80 | 81 | 82 | finally: 83 | client.close() 84 | 85 | 86 | 87 | class NodeRunner(object): 88 | """ 89 | NodeRunner singleton 90 | 91 | Will be handling connections to remote hosts through ssh 92 | """ 93 | __condObj = threading.Condition() # lock object 94 | __instance = None # the unique instance 95 | def __new__(cls, *args, **kargs): 96 | return cls.getInstance(cls, *args, **kargs) 97 | 98 | def __init__(self, reset=False): 99 | pass 100 | 101 | def getInstance(cls, *args, **kwargs): 102 | '''Static method to have a reference to **THE UNIQUE** instance''' 103 | 104 | # Check that this is not a stale singleton from another interpreter. Using the multiprocessing 105 | # module to create new subprocesses with individual interpreters, has such a side-effect. 106 | # If the singleton is from another interpreter, then recreate a new singleton for this interpreter. 107 | 108 | # Critical section start 109 | cls.__condObj.acquire() 110 | 111 | try: 112 | if MULTIPROCESSING_ENABLED: 113 | if cls.__instance is not None: 114 | subprocess = multiprocessing.current_process() 115 | if cls.__instance.interpreter != subprocess: 116 | del cls.__condObj 117 | cls.__condObj = threading.Condition() 118 | del cls.__instance 119 | cls.__instance = None 120 | 121 | if cls.__instance is None: 122 | # Initialize **the unique** instance 123 | cls.__instance = object.__new__(cls) 124 | cls.__instance.condObj = cls.__condObj 125 | 126 | # Record interpreter subprocess if multiprocessing is available 127 | if MULTIPROCESSING_ENABLED: 128 | cls.__instance.interpreter = multiprocessing.current_process() 129 | 130 | 131 | # Init ConnectionDict 132 | cls.__instance.connections = {} 133 | cls.__instance.running = {} 134 | cls.__instance.keys = {} 135 | cls.__instance.threads = {} 136 | 137 | finally: 138 | # Exit from critical section whatever happens 139 | cls.__condObj.release() 140 | # Critical section end 141 | 142 | return cls.__instance 143 | getInstance = classmethod(getInstance) 144 | 145 | def get_result(self, result_chan): 146 | 147 | # Fetch result 148 | cin = result_chan.reader() 149 | result = cin() 150 | 151 | self.condObj.acquire() 152 | key = self.keys.pop(result_chan) 153 | 154 | self.running[key].remove(result_chan) 155 | 156 | # If no more processes running at host, then poison 157 | if not self.running[key]: 158 | self.connections[key].reader().poison() 159 | 160 | del self.connections[key] 161 | del self.running[key] 162 | 163 | # join thread 164 | t = self.threads.pop(key) 165 | t.join() 166 | 167 | self.condObj.release() 168 | 169 | return result 170 | 171 | 172 | def run(self, ssh_host, ssh_port, ssh_python, cwd, pycsp_host, pycsp_port, script_path, func_name, func_args, func_kwargs, cluster_state = None): 173 | 174 | 175 | result_chan = Channel(buffer=1) 176 | 177 | key = (ssh_host, ssh_port, ssh_python, cwd) 178 | self.keys[result_chan] = key 179 | 180 | self.condObj.acquire() 181 | if key in self.connections: 182 | arg_chan = self.connections[key] 183 | running = self.running[key] 184 | else: 185 | # Setup channels to communicate data to process server.py 186 | arg_chan = Channel(buffer=1) 187 | running = [] 188 | self.connections[key] = arg_chan 189 | self.running[key] = running 190 | 191 | # Start NodeRunnerThread 192 | t = NodeRunnerThread(ssh_host, ssh_port, ssh_python, cwd, arg_chan.address[0].decode(), str(arg_chan.address[1]), arg_chan.name.decode()) 193 | t.start() 194 | self.threads[key] = t 195 | 196 | running.append(result_chan) 197 | 198 | self.condObj.release() 199 | 200 | cout = arg_chan.writer() 201 | 202 | if cluster_state: 203 | cout( (pycsp_host, pycsp_port, result_chan.name, script_path, func_name, func_args, func_kwargs, cluster_state) ) 204 | else: 205 | cout( (pycsp_host, pycsp_port, result_chan.name, script_path, func_name, func_args, func_kwargs) ) 206 | 207 | return result_chan 208 | -------------------------------------------------------------------------------- /pycsp/parallel/server.py: -------------------------------------------------------------------------------- 1 | """ 2 | process delegator service 3 | 4 | Must be executable by 5 | python -m pycsp.parallel.server 6 | 7 | Used to handle the creation of external processes (sshprocess / clusterprocess) 8 | 9 | Copyright (c) 2009 John Markus Bjoerndalen , 10 | Brian Vinter , Rune M. Friborg . 11 | See LICENSE.txt for licensing details (MIT License). 12 | """ 13 | 14 | 15 | import sys 16 | import os 17 | 18 | # Extract paramenters 19 | cwd, ip, port, input_name = sys.argv[1:] 20 | 21 | # Change to working dir 22 | os.chdir(cwd) 23 | 24 | # Load pycsp modules 25 | from pycsp.parallel.clusterprocess import NodePlacement 26 | from pycsp.parallel.process import init 27 | from pycsp.parallel import * 28 | 29 | # Init main process 30 | init() 31 | 32 | # Connect to channel 33 | input_chan = Channel(input_name, connect=(ip, int(port))) 34 | 35 | # Get channel ends 36 | input_chan_end = input_chan.reader() 37 | 38 | 39 | # PyCSP MultiProcess (Spawn) 40 | def RunFunc(output_chan_name, fn, args, kwargs): 41 | output_chan = Channel(output_chan_name, connect=(ip, int(port))) 42 | send_return_value = output_chan.writer() 43 | 44 | val = Parallel(Process(fn, *args, **kwargs)) 45 | 46 | send_return_value(val[0]) 47 | 48 | try: 49 | while True: 50 | 51 | # Retrive args, kwargs 52 | val = input_chan_end() 53 | if len(val) == 7: 54 | h, p, output_chan_name, scriptPath, funcName, args, kwargs = val 55 | else: 56 | # For clusterprocesses 57 | h, p, output_chan_name, scriptPath, funcName, args, kwargs, available_nodes = val 58 | if available_nodes: 59 | nodefile, group_state = available_nodes 60 | NodePlacement().set_nodegroup(nodefile, group_state) 61 | 62 | # Load script 63 | sys.path.insert(0, os.path.dirname(scriptPath)) 64 | moduleName = os.path.basename(scriptPath) 65 | 66 | if moduleName[-3:] == '.py': 67 | moduleName = moduleName[:-3] 68 | 69 | m = __import__(moduleName) 70 | 71 | # Get function by 72 | # 1. retrieve process factory function. 73 | # 2. generate process from process factory 74 | # 3. Fetch function from generated process 75 | fn = getattr(m, funcName)().fn 76 | 77 | # Spawn a runner 78 | Spawn(MultiProcess(RunFunc, output_chan_name, fn, args, kwargs), pycsp_host=h, pycsp_port=p) 79 | 80 | except ChannelPoisonException: 81 | pass 82 | 83 | # The rest of process clean up is done in shutdown 84 | shutdown() 85 | 86 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: latin-1 -*- 3 | # 4 | # see http://docs.python.org/dist/dist.html 5 | # 6 | """ 7 | Copyright (c) 2009 John Markus Bjoerndalen , 8 | Brian Vinter , Rune M. Friborg . 9 | Permission is hereby granted, free of charge, to any person obtaining 10 | a copy of this software and associated documentation files (the 11 | "Software"), to deal in the Software without restriction, including 12 | without limitation the rights to use, copy, modify, merge, publish, 13 | distribute, sublicense, and/or sell copies of the Software, and to 14 | permit persons to whom the Software is furnished to do so, subject to 15 | the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be 18 | included in all copies or substantial portions of the Software. THE 19 | SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | """ 27 | 28 | from setuptools import setup 29 | import os 30 | 31 | def read(fname): 32 | return open(os.path.join(os.path.dirname(__file__), fname)).read() 33 | 34 | setup(name='pycsp', 35 | version='0.9.2', 36 | description='PyCSP - Python CSP Library', 37 | long_description=read('README.md'), 38 | keywords = "python csp concurrency parallel distributed communicating sequential processes", 39 | author='Rune M. Friborg', 40 | author_email='rune.m.friborg@gmail.com', 41 | url='https://github.com/runefriborg/pycsp', 42 | license='MIT', 43 | packages=['pycsp', 'pycsp.parallel', 'pycsp.greenlets', 'pycsp.common', 'pycsp.current'], 44 | platforms=['any'], 45 | classifiers=[ 46 | "Development Status :: 5 - Production/Stable", 47 | "Intended Audience :: Developers", 48 | "License :: OSI Approved :: MIT License", 49 | "Programming Language :: Python", 50 | ], 51 | ) 52 | -------------------------------------------------------------------------------- /test/autotest.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | from pycsp_import import * 8 | import check 9 | import time 10 | import random 11 | 12 | @choice 13 | def action(assertCheck, id, channel_input=None): 14 | if assertCheck: 15 | assertCheck(id) 16 | 17 | @process 18 | def reader(cin, id, sleeper, assertCheck=None): 19 | while True: 20 | if sleeper: sleeper() 21 | got = cin() 22 | if assertCheck: 23 | assertCheck(id) 24 | 25 | @process 26 | def writer(cout, id, cnt, sleeper): 27 | for i in range(cnt): 28 | if sleeper: sleeper() 29 | cout((id, i)) 30 | retire(cout) 31 | 32 | @process 33 | def par_reader(cin1,cin2,cin3,cin4, cnt, sleeper, assertCheck=None): 34 | while True: 35 | if sleeper: sleeper() 36 | 37 | AltSelect( 38 | InputGuard(cin1, action(assertCheck, 0)), 39 | InputGuard(cin2, action(assertCheck, 1)), 40 | InputGuard(cin3, action(assertCheck, 2)), 41 | InputGuard(cin4, action(assertCheck, 3)) 42 | ) 43 | 44 | @process 45 | def par_fair_reader(cin1,cin2,cin3,cin4, cnt, sleeper, assertCheck=None): 46 | while True: 47 | if sleeper: sleeper() 48 | 49 | FairSelect( 50 | InputGuard(cin1, action(assertCheck, 0)), 51 | InputGuard(cin2, action(assertCheck, 1)), 52 | InputGuard(cin3, action(assertCheck, 2)), 53 | InputGuard(cin4, action(assertCheck, 3)) 54 | ) 55 | 56 | @process 57 | def par_pri_reader(cin1,cin2,cin3,cin4, cnt, sleeper, assertCheck=None): 58 | while True: 59 | if sleeper: sleeper() 60 | 61 | PriSelect( 62 | InputGuard(cin1, action(assertCheck, 0)), 63 | InputGuard(cin2, action(assertCheck, 1)), 64 | InputGuard(cin3, action(assertCheck, 2)), 65 | InputGuard(cin4, action(assertCheck, 3)) 66 | ) 67 | 68 | @process 69 | def return_msg(cin, sleeper): 70 | if sleeper: sleeper() 71 | return cin() 72 | 73 | @io 74 | def sleep_one(): 75 | time.sleep(0.01) 76 | 77 | @io 78 | def sleep_random(): 79 | time.sleep(random.random()/100) 80 | 81 | 82 | def Parallel_Test(sleeper): 83 | 84 | c1=Channel() 85 | 86 | L= Parallel(writer(c1.writer(), 0, 10, sleeper), 10 * return_msg(c1.reader(), sleeper)) 87 | 88 | if len(L) == 11 and L[0] == None and not None in L[1:]: 89 | print(("OK - Parallel_Test"+str(sleeper))) 90 | else: 91 | print(("Error - Parallel_Test"+str(sleeper))) 92 | print((str(L))) 93 | 94 | def Sequence_Test(sleeper): 95 | 96 | c1=Channel() 97 | 98 | Spawn(writer(c1.writer(), 0, 10, sleeper)) 99 | L= Sequence(10 * return_msg(c1.reader(), sleeper)) 100 | 101 | if len(L) == 10 and not None in L: 102 | print(("OK - Sequence_Test"+str(sleeper))) 103 | else: 104 | print(("Error - Sequence_Test"+str(sleeper))) 105 | print((str(L))) 106 | 107 | 108 | def One2One_Test(read_sleeper, write_sleeper): 109 | x = Channel() 110 | Spawn(check.Assert(x.reader(), "One2One_Test"+str(read_sleeper)+str(write_sleeper), count=10, vocabulary=[0])) 111 | 112 | c1=Channel() 113 | Parallel(reader(c1.reader(), 0 , read_sleeper, x.writer()), writer(c1.writer(),1,10, write_sleeper)) 114 | 115 | def Any2One_Alting_Test(read_sleeper, write_sleeper): 116 | x = Channel() 117 | Spawn(check.Assert(x.reader(), "Any2One_Alting_Test"+str(read_sleeper)+str(write_sleeper), count=40, minimum=10, vocabulary=[0,1,2,3], quit_on_count=True)) 118 | 119 | c1=Channel() 120 | c2=Channel() 121 | c3=Channel() 122 | c4=Channel() 123 | 124 | cnt = 10 125 | 126 | Parallel(par_reader(c1.reader(), c2.reader(), c3.reader(), c4.reader(),cnt, read_sleeper, x.writer()), 127 | writer(c1.writer(),0,cnt, write_sleeper), 128 | writer(c2.writer(),1,cnt, write_sleeper), 129 | writer(c3.writer(),2,cnt, write_sleeper), 130 | writer(c4.writer(),3,cnt, write_sleeper)) 131 | 132 | def Any2One_FairAlting_Test(read_sleeper, write_sleeper): 133 | x = Channel() 134 | Spawn(check.Assert(x.reader(), "Any2One_FairAlting_Test"+str(read_sleeper)+str(write_sleeper), count=40, minimum=10, vocabulary=[0,1,2,3], quit_on_count=True)) 135 | 136 | c1=Channel() 137 | c2=Channel() 138 | c3=Channel() 139 | c4=Channel() 140 | 141 | cnt = 10 142 | 143 | Parallel(par_fair_reader(c1.reader(), c2.reader(), c3.reader(), c4.reader(),cnt, read_sleeper, x.writer()), 144 | writer(c1.writer(),0,cnt, write_sleeper), 145 | writer(c2.writer(),1,cnt, write_sleeper), 146 | writer(c3.writer(),2,cnt, write_sleeper), 147 | writer(c4.writer(),3,cnt, write_sleeper)) 148 | 149 | def Any2One_PriAlting_Test(read_sleeper, write_sleeper): 150 | x = Channel() 151 | Spawn(check.Assert(x.reader(), "Any2One_PriAlting_Test"+str(read_sleeper)+str(write_sleeper), count=40, minimum=10, vocabulary=[0,1,2,3], quit_on_count=True)) 152 | 153 | c1=Channel() 154 | c2=Channel() 155 | c3=Channel() 156 | c4=Channel() 157 | 158 | cnt = 10 159 | 160 | Parallel(par_pri_reader(c1.reader(), c2.reader(), c3.reader(), c4.reader(),cnt, read_sleeper, x.writer()), 161 | writer(c1.writer(),0,cnt, write_sleeper), 162 | writer(c2.writer(),1,cnt, write_sleeper), 163 | writer(c3.writer(),2,cnt, write_sleeper), 164 | writer(c4.writer(),3,cnt, write_sleeper)) 165 | 166 | def Any2Any_Test(read_sleeper, write_sleeper): 167 | x = Channel() 168 | Spawn(check.Assert(x.reader(), "Any2Any_Test"+str(read_sleeper)+str(write_sleeper), count=40, vocabulary=[0,1,2,3])) 169 | 170 | c1=Channel() 171 | cnt = 10 172 | 173 | Parallel(reader(c1.reader(),0, read_sleeper, x.writer()), writer(c1.writer(),0,cnt, write_sleeper), 174 | reader(c1.reader(),1, read_sleeper, x.writer()), writer(c1.writer(),1,cnt, write_sleeper), 175 | reader(c1.reader(),2, read_sleeper, x.writer()), writer(c1.writer(),2,cnt, write_sleeper), 176 | reader(c1.reader(),3, read_sleeper, x.writer()), writer(c1.writer(),3,cnt, write_sleeper)) 177 | 178 | 179 | def autotest(): 180 | for read_sleep in [('Zero', None), ('One',sleep_one), ('Random',sleep_random)]: 181 | 182 | Sequence_Test(read_sleep[1]) 183 | Parallel_Test(read_sleep[1]) 184 | 185 | for write_sleep in [('Zero', None), ('One',sleep_one), ('Random',sleep_random)]: 186 | rname, rsleep = read_sleep 187 | wname, wsleep = write_sleep 188 | 189 | 190 | if not rsleep==wsleep==sleep_one: 191 | One2One_Test(rsleep, wsleep) 192 | Any2One_Alting_Test(rsleep, wsleep) 193 | Any2One_FairAlting_Test(rsleep, wsleep) 194 | Any2One_PriAlting_Test(rsleep, wsleep) 195 | Any2Any_Test(rsleep, wsleep) 196 | 197 | if __name__ == '__main__': 198 | autotest() 199 | shutdown() 200 | -------------------------------------------------------------------------------- /test/buffertest.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | from pycsp_import import * 8 | import check 9 | import time 10 | import random 11 | 12 | @choice 13 | def action(assertCheck, id, channel_input=None): 14 | if assertCheck: 15 | assertCheck(id) 16 | 17 | @process 18 | def reader(cin, id, sleeper, assertCheck=None): 19 | while True: 20 | if sleeper: sleeper() 21 | got = cin() 22 | if assertCheck: 23 | assertCheck(id) 24 | 25 | @process 26 | def writer(cout, id, cnt, sleeper): 27 | for i in range(cnt): 28 | if sleeper: sleeper() 29 | cout((id, i)) 30 | retire(cout) 31 | 32 | @process 33 | def par_reader(cin1,cin2,cin3,cin4, sleeper, assertCheck=None): 34 | while True: 35 | if sleeper: sleeper() 36 | AltSelect( 37 | InputGuard(cin1, action(assertCheck, 0)), 38 | InputGuard(cin2, action(assertCheck, 1)), 39 | InputGuard(cin3, action(assertCheck, 2)), 40 | InputGuard(cin4, action(assertCheck, 3)) 41 | ) 42 | 43 | @process 44 | def par_writer(cout1,cout2,cout3,cout4, cnt, sleeper): 45 | for i in range(cnt*4): 46 | if sleeper: sleeper() 47 | AltSelect( 48 | OutputGuard(cout1, i), 49 | OutputGuard(cout2, i), 50 | OutputGuard(cout3, i), 51 | OutputGuard(cout4, i) 52 | ) 53 | 54 | retire(cout1, cout2, cout3, cout4) 55 | 56 | @io 57 | def sleep_random(): 58 | time.sleep(random.random()/100) 59 | 60 | @io 61 | def sleep_one(): 62 | time.sleep(0.01) 63 | 64 | def Buffer_Test(read_sleeper, write_sleeper): 65 | x = Channel() 66 | Spawn(check.Assert(x.reader(), "Buffer_Test"+str(read_sleeper)+str(write_sleeper), count=10, vocabulary=list(range(10)))) 67 | 68 | cnt = 10 69 | c=Channel(buffer=cnt) 70 | Parallel(writer(-c,0,cnt, write_sleeper)) 71 | Parallel(reader(+c, 0, read_sleeper, x.writer())) 72 | 73 | 74 | def One2One_Test(read_sleeper, write_sleeper): 75 | x = Channel() 76 | Spawn(check.Assert(x.reader(), "One2One_Test"+str(read_sleeper)+str(write_sleeper), count=40, vocabulary=[0,1,2,3])) 77 | 78 | c1=Channel(buffer=1) 79 | c2=Channel(buffer=5) 80 | c3=Channel(buffer=10) 81 | c4=Channel(buffer=20) 82 | 83 | cnt = 10 84 | 85 | Parallel(reader(+c1,0, read_sleeper, x.writer()), writer(-c1,0,cnt, write_sleeper), 86 | reader(+c2,1, read_sleeper, x.writer()), writer(-c2,1,cnt, write_sleeper), 87 | reader(+c3,2, read_sleeper, x.writer()), writer(-c3,2,cnt, write_sleeper), 88 | reader(+c4,3, read_sleeper, x.writer()), writer(-c4,3,cnt, write_sleeper)) 89 | 90 | def Any2One_Test(read_sleeper, write_sleeper): 91 | x = Channel() 92 | Spawn(check.Assert(x.reader(), "Any2One_Test"+str(read_sleeper)+str(write_sleeper), count=40, vocabulary=[0])) 93 | 94 | c1=Channel(buffer=20) 95 | 96 | cnt = 10 97 | 98 | Parallel(reader(c1.reader(),0, read_sleeper, x.writer()), 99 | writer(c1.writer(),0,cnt, write_sleeper), 100 | writer(c1.writer(),1,cnt, write_sleeper), 101 | writer(c1.writer(),2,cnt, write_sleeper), 102 | writer(c1.writer(),3,cnt, write_sleeper)) 103 | 104 | def One2Any_Test(read_sleeper, write_sleeper): 105 | x = Channel() 106 | Spawn(check.Assert(x.reader(), "One2Any_Test"+str(read_sleeper)+str(write_sleeper), count=40, vocabulary=[0,1,2,3])) 107 | 108 | c1=Channel(buffer=20) 109 | 110 | cnt = 10 111 | 112 | Parallel(writer(c1.writer(),0,cnt*4, write_sleeper), 113 | reader(c1.reader(),0, read_sleeper, x.writer()), 114 | reader(c1.reader(),1, read_sleeper, x.writer()), 115 | reader(c1.reader(),2, read_sleeper, x.writer()), 116 | reader(c1.reader(),3, read_sleeper, x.writer())) 117 | 118 | 119 | def One_Alting2Any_Test(read_sleeper, write_sleeper): 120 | x = Channel() 121 | Spawn(check.Assert(x.reader(), "One_Alting2Any_Test"+str(read_sleeper)+str(write_sleeper), count=40, vocabulary=[0,1,2,3])) 122 | 123 | c1=Channel(buffer=1) 124 | c2=Channel(buffer=5) 125 | c3=Channel(buffer=10) 126 | c4=Channel(buffer=20) 127 | 128 | cnt = 10 129 | 130 | Parallel(par_writer(c1.writer(),c2.writer(),c3.writer(),c4.writer(),cnt, write_sleeper), 131 | reader(c1.reader(),0, read_sleeper, x.writer()), 132 | reader(c2.reader(),1, read_sleeper, x.writer()), 133 | reader(c3.reader(),2, read_sleeper, x.writer()), 134 | reader(c4.reader(),3, read_sleeper, x.writer())) 135 | 136 | def Any2Any_Test(read_sleeper, write_sleeper): 137 | x = Channel() 138 | Spawn(check.Assert(x.reader(), "Any2Any_Test"+str(read_sleeper)+str(write_sleeper), count=40, vocabulary=[0,1,2,3])) 139 | 140 | c1=Channel(buffer=20) 141 | cnt = 10 142 | 143 | Parallel(reader(+c1,0, read_sleeper, x.writer()), writer(-c1,0,cnt, write_sleeper), 144 | reader(+c1,1, read_sleeper, x.writer()), writer(-c1,1,cnt, write_sleeper), 145 | reader(+c1,2, read_sleeper, x.writer()), writer(-c1,2,cnt, write_sleeper), 146 | reader(+c1,3, read_sleeper, x.writer()), writer(-c1,3,cnt, write_sleeper)) 147 | 148 | def Any_Alting2Any_Alting_Test(read_sleeper, write_sleeper): 149 | x = Channel() 150 | Spawn(check.Assert(x.reader(), "Any_Alting2Any_Alting_Test"+str(read_sleeper)+str(write_sleeper), count=160, minimum=40, vocabulary=[0,1,2,3])) 151 | 152 | c1=Channel(buffer=1) 153 | c2=Channel(buffer=5) 154 | c3=Channel(buffer=10) 155 | c4=Channel(buffer=20) 156 | 157 | cnt = 10 158 | 159 | Parallel(par_writer(-c1, -c2, -c3, -c4,cnt, write_sleeper), 160 | par_writer(-c1, -c2, -c3, -c4,cnt, write_sleeper), 161 | par_writer(-c1, -c2, -c3, -c4,cnt, write_sleeper), 162 | par_writer(-c1, -c2, -c3, -c4,cnt, write_sleeper), 163 | par_reader(+c1, +c2, +c3, +c4, read_sleeper, x.writer()), 164 | par_reader(+c1, +c2, +c3, +c4, read_sleeper, x.writer()), 165 | par_reader(+c1, +c2, +c3, +c4, read_sleeper, x.writer()), 166 | par_reader(+c1, +c2, +c3, +c4, read_sleeper, x.writer())) 167 | 168 | 169 | 170 | def commtest(): 171 | for read_sleep in [('Zero', None), ('One',sleep_one), ('Random',sleep_random)]: 172 | for write_sleep in [('Zero', None), ('One',sleep_one), ('Random',sleep_random)]: 173 | rname, rsleep = read_sleep 174 | wname, wsleep = write_sleep 175 | if not rsleep==wsleep==sleep_one: #No reason to test with both sleep_one 176 | Buffer_Test(rsleep, wsleep) 177 | One2One_Test(rsleep, wsleep) 178 | Any2One_Test(rsleep, wsleep) 179 | One2Any_Test(rsleep, wsleep) 180 | One_Alting2Any_Test(rsleep, wsleep) 181 | Any2Any_Test(rsleep,wsleep) 182 | Any_Alting2Any_Alting_Test(rsleep, wsleep) 183 | 184 | if __name__ == '__main__': 185 | commtest() 186 | shutdown() 187 | -------------------------------------------------------------------------------- /test/check.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | import sys 8 | from pycsp_import import * 9 | 10 | 11 | def print_state(received, poison, retire): 12 | sys.stdout.write("Received: " + str(received) + "\n") 13 | if poison: 14 | sys.stdout.write("Poisoned\n") 15 | if retire: 16 | sys.stdout.write("Retired\n") 17 | sys.stdout.flush() 18 | 19 | @process 20 | def Assert(cin, name = "", count = 0, minimum = 0, vocabulary = [], ordered = False, quit_on_count = False, debug = False): 21 | received = [] 22 | poison = False 23 | retire = False 24 | while True: 25 | try: 26 | val = cin() 27 | if debug: 28 | sys.stdout.write("Debug: "+str(val)+"\n") 29 | sys.stdout.flush() 30 | received.append(val) 31 | except ChannelPoisonException: 32 | poison = True 33 | break 34 | except ChannelRetireException: 35 | retire = True 36 | break 37 | 38 | if quit_on_count and len(received) == count: 39 | break 40 | 41 | error = "" 42 | 43 | if (len(received) < minimum): 44 | error += "Wrong number of values: "+str(len(received))+"\n" 45 | error += "Expected the minimum number of values: "+str(minimum)+"\n" 46 | 47 | if count: 48 | if minimum: 49 | if (len(received) > count): 50 | error += "Wrong number of values: "+str(len(received))+"\n" 51 | error += "Expected a maximum number of values: "+str(count)+"\n" 52 | else: 53 | if not (len(received) == count): 54 | error += "Wrong number of values: "+str(len(received))+"\n" 55 | error += "Expected number of values: "+str(count)+"\n" 56 | 57 | 58 | if vocabulary: 59 | for i in range(len(received)): 60 | if received[i] not in vocabulary: 61 | error += "Value "+ str(received[i]) + " not in vocabulary\n" 62 | 63 | if (ordered): 64 | for i in range(len(received)): 65 | if received[i] != vocabulary[i % len(vocabulary)]: 66 | error += "Value "+ str(received[i]) + " != " + str(vocabulary[i % len(vocabulary)])+" in vocabulary\n" 67 | 68 | if error: 69 | sys.stdout.write(name+"\n") 70 | sys.stdout.write(error) 71 | print_state(received, poison, retire) 72 | else: 73 | sys.stdout.write("OK - "+ name+ "\n") 74 | -------------------------------------------------------------------------------- /test/commtest.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | from pycsp_import import * 8 | import check 9 | import time 10 | import random 11 | 12 | @choice 13 | def action(assertCheck, id, channel_input=None): 14 | if assertCheck: 15 | assertCheck(id) 16 | 17 | @process 18 | def reader(cin, id, sleeper, assertCheck=None): 19 | while True: 20 | if sleeper: sleeper() 21 | got = cin() 22 | if assertCheck: 23 | assertCheck(id) 24 | 25 | @process 26 | def writer(cout, id, cnt, sleeper): 27 | for i in range(cnt): 28 | if sleeper: sleeper() 29 | cout((id, i)) 30 | retire(cout) 31 | 32 | @process 33 | def par_reader(cin1,cin2,cin3,cin4, sleeper, assertCheck=None): 34 | while True: 35 | if sleeper: sleeper() 36 | AltSelect( 37 | InputGuard(cin1, action(assertCheck, 0)), 38 | InputGuard(cin2, action(assertCheck, 1)), 39 | InputGuard(cin3, action(assertCheck, 2)), 40 | InputGuard(cin4, action(assertCheck, 3)) 41 | ) 42 | 43 | @process 44 | def par_writer(cout1,cout2,cout3,cout4, cnt, sleeper): 45 | for i in range(cnt*4): 46 | if sleeper: sleeper() 47 | AltSelect( 48 | OutputGuard(cout1, i), 49 | OutputGuard(cout2, i), 50 | OutputGuard(cout3, i), 51 | OutputGuard(cout4, i) 52 | ) 53 | 54 | retire(cout1, cout2, cout3, cout4) 55 | 56 | @io 57 | def sleep_random(): 58 | time.sleep(random.random()/100) 59 | 60 | @io 61 | def sleep_one(): 62 | time.sleep(0.01) 63 | 64 | def One2One_Test(read_sleeper, write_sleeper): 65 | x = Channel() 66 | Spawn(check.Assert(x.reader(), "One2One_Test"+str(read_sleeper)+str(write_sleeper), count=40, vocabulary=[0,1,2,3])) 67 | 68 | c1=Channel() 69 | c2=Channel() 70 | c3=Channel() 71 | c4=Channel() 72 | 73 | cnt = 10 74 | 75 | Parallel(reader(+c1,0, read_sleeper, x.writer()), writer(-c1,0,cnt, write_sleeper), 76 | reader(+c2,1, read_sleeper, x.writer()), writer(-c2,1,cnt, write_sleeper), 77 | reader(+c3,2, read_sleeper, x.writer()), writer(-c3,2,cnt, write_sleeper), 78 | reader(+c4,3, read_sleeper, x.writer()), writer(-c4,3,cnt, write_sleeper)) 79 | 80 | def Any2One_Test(read_sleeper, write_sleeper): 81 | x = Channel() 82 | Spawn(check.Assert(x.reader(), "Any2One_Test"+str(read_sleeper)+str(write_sleeper), count=40, vocabulary=[0])) 83 | 84 | c1=Channel() 85 | 86 | cnt = 10 87 | 88 | Parallel(reader(c1.reader(),0, read_sleeper, x.writer()), 89 | writer(c1.writer(),0,cnt, write_sleeper), 90 | writer(c1.writer(),1,cnt, write_sleeper), 91 | writer(c1.writer(),2,cnt, write_sleeper), 92 | writer(c1.writer(),3,cnt, write_sleeper)) 93 | 94 | def One2Any_Test(read_sleeper, write_sleeper): 95 | x = Channel() 96 | Spawn(check.Assert(x.reader(), "One2Any_Test"+str(read_sleeper)+str(write_sleeper), count=40, vocabulary=[0,1,2,3])) 97 | 98 | c1=Channel() 99 | 100 | cnt = 10 101 | 102 | Parallel(writer(c1.writer(),0,cnt*4, write_sleeper), 103 | reader(c1.reader(),0, read_sleeper, x.writer()), 104 | reader(c1.reader(),1, read_sleeper, x.writer()), 105 | reader(c1.reader(),2, read_sleeper, x.writer()), 106 | reader(c1.reader(),3, read_sleeper, x.writer())) 107 | 108 | 109 | def One_Alting2Any_Test(read_sleeper, write_sleeper): 110 | x = Channel() 111 | Spawn(check.Assert(x.reader(), "One_Alting2Any_Test"+str(read_sleeper)+str(write_sleeper), count=40, vocabulary=[0,1,2,3])) 112 | 113 | c1=Channel() 114 | c2=Channel() 115 | c3=Channel() 116 | c4=Channel() 117 | 118 | cnt = 10 119 | 120 | Parallel(par_writer(c1.writer(),c2.writer(),c3.writer(),c4.writer(),cnt, write_sleeper), 121 | reader(c1.reader(),0, read_sleeper, x.writer()), 122 | reader(c2.reader(),1, read_sleeper, x.writer()), 123 | reader(c3.reader(),2, read_sleeper, x.writer()), 124 | reader(c4.reader(),3, read_sleeper, x.writer())) 125 | 126 | def Any2Any_Test(read_sleeper, write_sleeper): 127 | x = Channel() 128 | Spawn(check.Assert(x.reader(), "Any2Any_Test"+str(read_sleeper)+str(write_sleeper), count=40, vocabulary=[0,1,2,3])) 129 | 130 | c1=Channel() 131 | cnt = 10 132 | 133 | Parallel(reader(+c1,0, read_sleeper, x.writer()), writer(-c1,0,cnt, write_sleeper), 134 | reader(+c1,1, read_sleeper, x.writer()), writer(-c1,1,cnt, write_sleeper), 135 | reader(+c1,2, read_sleeper, x.writer()), writer(-c1,2,cnt, write_sleeper), 136 | reader(+c1,3, read_sleeper, x.writer()), writer(-c1,3,cnt, write_sleeper)) 137 | 138 | def Any_Alting2Any_Alting_Test(read_sleeper, write_sleeper): 139 | x = Channel() 140 | Spawn(check.Assert(x.reader(), "Any_Alting2Any_Alting_Test"+str(read_sleeper)+str(write_sleeper), count=160, minimum=40, vocabulary=[0,1,2,3])) 141 | 142 | c1=Channel() 143 | c2=Channel() 144 | c3=Channel() 145 | c4=Channel() 146 | 147 | cnt = 10 148 | 149 | Parallel(par_writer(-c1, -c2, -c3, -c4,cnt, write_sleeper), 150 | par_writer(-c1, -c2, -c3, -c4,cnt, write_sleeper), 151 | par_writer(-c1, -c2, -c3, -c4,cnt, write_sleeper), 152 | par_writer(-c1, -c2, -c3, -c4,cnt, write_sleeper), 153 | par_reader(+c1, +c2, +c3, +c4, read_sleeper, x.writer()), 154 | par_reader(+c1, +c2, +c3, +c4, read_sleeper, x.writer()), 155 | par_reader(+c1, +c2, +c3, +c4, read_sleeper, x.writer()), 156 | par_reader(+c1, +c2, +c3, +c4, read_sleeper, x.writer())) 157 | 158 | 159 | 160 | def commtest(): 161 | for read_sleep in [('Zero', None), ('One',sleep_one), ('Random',sleep_random)]: 162 | for write_sleep in [('Zero', None), ('One',sleep_one), ('Random',sleep_random)]: 163 | rname, rsleep = read_sleep 164 | wname, wsleep = write_sleep 165 | if not rsleep==wsleep==sleep_one: #No reason to test with both sleep_one 166 | One2One_Test(rsleep, wsleep) 167 | Any2One_Test(rsleep, wsleep) 168 | One2Any_Test(rsleep, wsleep) 169 | One_Alting2Any_Test(rsleep, wsleep) 170 | Any2Any_Test(rsleep,wsleep) 171 | Any_Alting2Any_Alting_Test(rsleep, wsleep) 172 | 173 | if __name__ == '__main__': 174 | commtest() 175 | shutdown() 176 | -------------------------------------------------------------------------------- /test/guardtest.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | from pycsp_import import * 8 | import time 9 | import random 10 | 11 | @io 12 | def sleep_long(): 13 | time.sleep(2) 14 | 15 | @io 16 | def sleep_random(): 17 | time.sleep(random.random()/2) 18 | 19 | @io 20 | def sleep_long_random(): 21 | time.sleep(random.random()*2) 22 | 23 | 24 | @process 25 | def writer(cout, id, cnt, sleeper): 26 | for i in range(cnt): 27 | if sleeper: sleeper() 28 | cout((id, i)) 29 | 30 | @process 31 | def par_reader_skip_sel(cin1,cin2,cin3,cin4, cnt, sleeper): 32 | for i in range(cnt*4): 33 | if sleeper: sleeper() 34 | 35 | c, msg = PriSelect( 36 | InputGuard(cin1), 37 | InputGuard(cin2), 38 | SkipGuard(), 39 | InputGuard(cin3), 40 | InputGuard(cin4) 41 | ) 42 | 43 | print('From ',c ,'got',msg) 44 | retire(cin1, cin2, cin3, cin4) 45 | 46 | @process 47 | def par_reader_timeout_sel(cin1,cin2,cin3,cin4, cnt, sleeper): 48 | for i in range(cnt*4): 49 | if sleeper: sleeper() 50 | 51 | c, msg = PriSelect( 52 | InputGuard(cin1), 53 | InputGuard(cin2), 54 | InputGuard(cin3), 55 | InputGuard(cin4), 56 | TimeoutGuard(seconds=0.1) 57 | ) 58 | 59 | print('From ',c ,'got',msg) 60 | retire(cin1, cin2, cin3, cin4) 61 | 62 | @process 63 | def par_reader_skip_exec(cin1,cin2,cin3,cin4, cnt, sleeper): 64 | for i in range(cnt*4): 65 | if sleeper: sleeper() 66 | 67 | PriSelect( 68 | InputGuard(cin1, action="print('From cin1 got', channel_input)"), 69 | InputGuard(cin2, action="print('From cin2 got', channel_input)"), 70 | SkipGuard(action="print('SkipGuard()')"), 71 | InputGuard(cin3, action="print('From cin3 got', channel_input)"), 72 | InputGuard(cin4, action="print('From cin4 got', channel_input)") 73 | ) 74 | 75 | retire(cin1, cin2, cin3, cin4) 76 | 77 | @process 78 | def par_reader_timeout_exec(cin1,cin2,cin3,cin4, cnt, sleeper): 79 | for i in range(cnt*4): 80 | if sleeper: sleeper() 81 | 82 | PriSelect( 83 | InputGuard(cin1, action="print('From cin1 got', channel_input)"), 84 | InputGuard(cin2, action="print('From cin2 got', channel_input)"), 85 | InputGuard(cin3, action="print('From cin3 got', channel_input)"), 86 | InputGuard(cin4, action="print('From cin4 got', channel_input)"), 87 | TimeoutGuard(seconds=0.1, action="print('TimeoutGuard(seconds=0.1)')") 88 | ) 89 | 90 | retire(cin1, cin2, cin3, cin4) 91 | 92 | 93 | def Any2One_Alting_Test(par_reader, read_sleeper, write_sleeper): 94 | c1=Channel() 95 | c2=Channel() 96 | c3=Channel() 97 | c4=Channel() 98 | 99 | cnt = 10 100 | 101 | Parallel(par_reader(c1.reader(),c2.reader(),c3.reader(),c4.reader(),cnt, read_sleeper), 102 | writer(c1.writer(),0,cnt, write_sleeper), 103 | writer(c2.writer(),1,cnt, write_sleeper), 104 | writer(c3.writer(),2,cnt, write_sleeper), 105 | writer(c4.writer(),3,cnt, write_sleeper)) 106 | 107 | 108 | def Any2Any_Alting_Test(par_reader, read_sleeper, write_sleeper): 109 | c1=Channel() 110 | c2=Channel() 111 | c3=Channel() 112 | c4=Channel() 113 | 114 | cnt = 40 115 | 116 | Parallel(par_reader(+c1,+c2,+c3,+c4,cnt, read_sleeper), 117 | writer(-c1,0,cnt, write_sleeper), 118 | writer(-c1,1,cnt, write_sleeper), 119 | writer(-c1,2,cnt, write_sleeper), 120 | writer(-c1,3,cnt, write_sleeper), 121 | writer(-c2,4,cnt, write_sleeper), 122 | writer(-c2,5,cnt, write_sleeper), 123 | writer(-c2,6,cnt, write_sleeper), 124 | writer(-c2,7,cnt, write_sleeper), 125 | writer(-c3,8,cnt, write_sleeper), 126 | writer(-c3,9,cnt, write_sleeper), 127 | writer(-c3,10,cnt, write_sleeper), 128 | writer(-c3,11,cnt, write_sleeper), 129 | writer(-c4,12,cnt, write_sleeper), 130 | writer(-c4,13,cnt, write_sleeper), 131 | writer(-c4,14,cnt, write_sleeper), 132 | writer(-c4,15,cnt, write_sleeper)) 133 | 134 | 135 | if __name__ == '__main__': 136 | print("Any2One_Alting_Test(par_reader_skip_sel, sleep_random, sleep_random)") 137 | Any2One_Alting_Test(par_reader_skip_sel, sleep_random, sleep_random) 138 | print() 139 | 140 | print("Any2One_Alting_Test(par_reader_timeout_sel, sleep_random, sleep_long_random)") 141 | Any2One_Alting_Test(par_reader_timeout_sel, sleep_random, sleep_long_random) 142 | print() 143 | 144 | print("Any2One_Alting_Test(par_reader_skip_exec, sleep_random, sleep_random)") 145 | Any2One_Alting_Test(par_reader_skip_exec, sleep_random, sleep_random) 146 | print() 147 | 148 | print("Any2One_Alting_Test(par_reader_timeout_exec, sleep_random, sleep_long_random)") 149 | Any2One_Alting_Test(par_reader_timeout_exec, sleep_random, sleep_long_random) 150 | print() 151 | 152 | print("Any2Any_Alting_Test(par_reader_skip_sel, None, sleep_long)") 153 | Any2Any_Alting_Test(par_reader_skip_sel, None, sleep_long) 154 | print() 155 | 156 | print("Any2Any_Alting_Test(par_reader_timeout_sel, None, sleep_long)") 157 | Any2Any_Alting_Test(par_reader_timeout_sel, None, sleep_long) 158 | print() 159 | 160 | 161 | shutdown() 162 | -------------------------------------------------------------------------------- /test/iotest.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | from pycsp_import import * 8 | import time 9 | 10 | @io 11 | def wait(seconds): 12 | time.sleep(seconds) 13 | 14 | @process 15 | def delay_output(msg, seconds): 16 | wait(seconds) 17 | print((str(msg))) 18 | 19 | Parallel( 20 | [ delay_output('%d second delay' % (i),i) for i in range(10)] 21 | ) 22 | 23 | shutdown() 24 | -------------------------------------------------------------------------------- /test/poisontest.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | from pycsp_import import * 8 | import check 9 | import time 10 | import random 11 | 12 | @choice 13 | def action(assertCheck, id, channel_input=None): 14 | if assertCheck: 15 | assertCheck(id) 16 | 17 | @process 18 | def reader(cin, id, sleeper, assertCheck=None): 19 | while True: 20 | if sleeper: sleeper() 21 | got = cin() 22 | if assertCheck: 23 | assertCheck(id) 24 | 25 | @process 26 | def writer(cout, id, cnt, sleeper): 27 | for i in range(cnt): 28 | if sleeper: sleeper() 29 | cout((id, i)) 30 | poison(cout) 31 | 32 | @process 33 | def par_reader(cin1,cin2,cin3,cin4, sleeper, assertCheck=None): 34 | while True: 35 | if sleeper: sleeper() 36 | AltSelect( 37 | InputGuard(cin1, action(assertCheck, 0)), 38 | InputGuard(cin2, action(assertCheck, 1)), 39 | InputGuard(cin3, action(assertCheck, 2)), 40 | InputGuard(cin4, action(assertCheck, 3)) 41 | ) 42 | 43 | @process 44 | def par_writer(cout1,cout2,cout3,cout4, cnt, sleeper): 45 | for i in range(cnt*4): 46 | if sleeper: sleeper() 47 | AltSelect( 48 | OutputGuard(cout1, i), 49 | OutputGuard(cout2, i), 50 | OutputGuard(cout3, i), 51 | OutputGuard(cout4, i) 52 | ) 53 | 54 | poison(cout1, cout2, cout3, cout4) 55 | 56 | @io 57 | def sleep_one(): 58 | time.sleep(0.01) 59 | 60 | @io 61 | def sleep_random(): 62 | time.sleep(random.random()/100) 63 | 64 | def One2One_Test(read_sleeper, write_sleeper): 65 | x = Channel() 66 | Spawn(check.Assert(x.reader(), "One2One_Test"+str(read_sleeper)+str(write_sleeper), count=10, vocabulary=[0])) 67 | 68 | c1=Channel() 69 | Parallel(reader(c1.reader(), 0 , read_sleeper, x.writer()), writer(c1.writer(),1,10, write_sleeper)) 70 | 71 | def Any2One_Alting_Test(read_sleeper, write_sleeper): 72 | x = Channel() 73 | Spawn(check.Assert(x.reader(), "Any2One_Alting_Test"+str(read_sleeper)+str(write_sleeper), count=40, minimum=10, vocabulary=[0,1,2,3], quit_on_count=True)) 74 | 75 | c1=Channel() 76 | c2=Channel() 77 | c3=Channel() 78 | c4=Channel() 79 | 80 | cnt = 10 81 | 82 | Parallel(par_reader(c1.reader(), c2.reader(), c3.reader(), c4.reader(), read_sleeper, x.writer()), 83 | writer(c1.writer(),0,cnt, write_sleeper), 84 | writer(c2.writer(),1,cnt, write_sleeper), 85 | writer(c3.writer(),2,cnt, write_sleeper), 86 | writer(c4.writer(),3,cnt, write_sleeper)) 87 | 88 | def Any2Any_Test(read_sleeper, write_sleeper): 89 | x = Channel() 90 | Spawn(check.Assert(x.reader(), "Any2Any_Test"+str(read_sleeper)+str(write_sleeper), count=40, minimum=10, vocabulary=[0,1,2,3])) 91 | 92 | c1=Channel() 93 | cnt = 10 94 | 95 | Parallel(reader(c1.reader(),0, read_sleeper, x.writer()), writer(c1.writer(),0,cnt, write_sleeper), 96 | reader(c1.reader(),1, read_sleeper, x.writer()), writer(c1.writer(),1,cnt, write_sleeper), 97 | reader(c1.reader(),2, read_sleeper, x.writer()), writer(c1.writer(),2,cnt, write_sleeper), 98 | reader(c1.reader(),3, read_sleeper, x.writer()), writer(c1.writer(),3,cnt, write_sleeper)) 99 | 100 | def Any_Alting2Any_Alting_Test(read_sleeper, write_sleeper): 101 | x = Channel() 102 | Spawn(check.Assert(x.reader(), "Any_Alting2Any_Alting_Test"+str(read_sleeper)+str(write_sleeper), count=80, minimum=40, vocabulary=[0,1,2,3])) 103 | 104 | c1=Channel() 105 | c2=Channel() 106 | c3=Channel() 107 | c4=Channel() 108 | 109 | cnt = 10 110 | Parallel(par_writer(-c1, -c2, -c3, -c4,cnt, write_sleeper), 111 | par_writer(-c1, -c2, -c3, -c4,cnt, write_sleeper), 112 | par_reader(+c1, +c2, +c3, +c4, read_sleeper, x.writer()), 113 | par_reader(+c1, +c2, +c3, +c4, read_sleeper, x.writer())) 114 | 115 | def poisontest(): 116 | for read_sleep in [('Zero', None), ('One',sleep_one), ('Random',sleep_random)]: 117 | for write_sleep in [('Zero', None), ('One',sleep_one), ('Random',sleep_random)]: 118 | rname, rsleep = read_sleep 119 | wname, wsleep = write_sleep 120 | 121 | if not rsleep==wsleep==sleep_one: 122 | One2One_Test(rsleep, wsleep) 123 | Any2One_Alting_Test(rsleep, wsleep) 124 | Any2Any_Test(rsleep, wsleep) 125 | Any_Alting2Any_Alting_Test(None,None) 126 | 127 | if __name__ == '__main__': 128 | poisontest() 129 | shutdown() 130 | -------------------------------------------------------------------------------- /test/pycsp_import.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | import sys 8 | sys.path.insert(0,"..") 9 | 10 | if len(sys.argv) > 1: 11 | mod = sys.argv[1] 12 | else: 13 | mod = '' 14 | 15 | if (mod == 'parallel'): 16 | from pycsp.parallel import * 17 | elif (mod == 'greenlets'): 18 | from pycsp.greenlets import * 19 | else: 20 | print(("python " + str(sys.argv[0]) + "[ parallel | greenlets ]")) 21 | from pycsp.parallel import * 22 | 23 | print(('Using version '+str(version))) 24 | 25 | -------------------------------------------------------------------------------- /test/runtests.bat: -------------------------------------------------------------------------------- 1 | @echo off set PYTHON=C:\python27\python.exe 2 | @echo off set IMPL=%1 3 | 4 | %PYTHON% autotest.py %IMPL% 5 | %PYTHON% buffertest.py %IMPL% 6 | %PYTHON% commtest.py %IMPL% 7 | %PYTHON% guardtest.py %IMPL% 8 | %PYTHON% iotest.py %IMPL% 9 | %PYTHON% poisontest.py %IMPL% 10 | %PYTHON% selecttest.py %IMPL% 11 | cd windows 12 | %PYTHON% remotetest.py %IMPL% 13 | -------------------------------------------------------------------------------- /test/runtests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | PYTHON=python 4 | IMPL=$1 5 | 6 | $PYTHON autotest.py $IMPL 7 | $PYTHON buffertest.py $IMPL 8 | $PYTHON commtest.py $IMPL 9 | $PYTHON guardtest.py $IMPL 10 | $PYTHON iotest.py $IMPL 11 | $PYTHON poisontest.py $IMPL 12 | $PYTHON selecttest.py $IMPL 13 | 14 | cd unix 15 | $PYTHON remotetest.py $IMPL 16 | $PYTHON multiprocesstest.py $IMPL 17 | $PYTHON sshprocesstest.py $IMPL 18 | $PYTHON clusterprocesstest.py $IMPL 19 | -------------------------------------------------------------------------------- /test/selecttest.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | from pycsp_import import * 8 | import time 9 | import random 10 | 11 | @io 12 | def sleep_random(): 13 | time.sleep(random.random()/10) 14 | 15 | @process 16 | def writer(cout, id, cnt, sleeper): 17 | for i in range(cnt): 18 | if sleeper: sleeper() 19 | cout((id, i)) 20 | 21 | @process 22 | def par_reader(cin1,cin2,cin3,cin4, cnt, sleeper): 23 | for i in range(cnt*4): 24 | if sleeper: sleeper() 25 | 26 | c, msg = AltSelect( 27 | InputGuard(cin1), 28 | InputGuard(cin2), 29 | InputGuard(cin3), 30 | InputGuard(cin4) 31 | ) 32 | 33 | print('From ',c ,'got',msg) 34 | 35 | @process 36 | def par_reader_pri(cin1,cin2,cin3,cin4, cnt, sleeper): 37 | for i in range(cnt*4): 38 | if sleeper: sleeper() 39 | 40 | c, msg = PriSelect( 41 | InputGuard(cin1), 42 | InputGuard(cin2), 43 | InputGuard(cin3), 44 | InputGuard(cin4) 45 | ) 46 | 47 | print('From ',c ,'got',msg) 48 | 49 | @process 50 | def par_reader_fair(cin1,cin2,cin3,cin4, cnt, sleeper): 51 | for i in range(cnt*4): 52 | if sleeper: sleeper() 53 | 54 | c, msg = FairSelect( 55 | InputGuard(cin1), 56 | InputGuard(cin2), 57 | InputGuard(cin3), 58 | InputGuard(cin4) 59 | ) 60 | 61 | print('From ',c ,'got',msg) 62 | 63 | 64 | def Any2One_Alting_Test(par_reader, read_sleeper, write_sleeper): 65 | c1=Channel() 66 | c2=Channel() 67 | c3=Channel() 68 | c4=Channel() 69 | 70 | cnt = 10 71 | 72 | Parallel(par_reader(+c1,+c2,+c3,+c4,cnt, read_sleeper), 73 | writer(-c1,0,cnt, write_sleeper), 74 | writer(-c2,1,cnt, write_sleeper), 75 | writer(-c3,2,cnt, write_sleeper), 76 | writer(-c4,3,cnt, write_sleeper)) 77 | 78 | if __name__ == '__main__': 79 | print("Any2One_Alting_Test - AltSelect") 80 | Any2One_Alting_Test(par_reader, sleep_random, sleep_random) 81 | print("Any2One_Alting_Test - PriSelect") 82 | Any2One_Alting_Test(par_reader_pri, sleep_random, sleep_random) 83 | print("Any2One_Alting_Test - FairSelect") 84 | Any2One_Alting_Test(par_reader_fair, sleep_random, sleep_random) 85 | 86 | shutdown() 87 | -------------------------------------------------------------------------------- /test/unix/check.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.insert(0, "../..") 3 | from pycsp.parallel import * 4 | 5 | 6 | def print_state(received, poison, retire): 7 | sys.stdout.write("Received: " + str(received) + "\n") 8 | if poison: 9 | sys.stdout.write("Poisoned\n") 10 | if retire: 11 | sys.stdout.write("Retired\n") 12 | sys.stdout.flush() 13 | 14 | @process 15 | def Assert(cin, name = "", count = 0, minimum = 0, vocabulary = [], ordered = False, quit_on_count = False, debug = False): 16 | received = [] 17 | poison = False 18 | retire = False 19 | while True: 20 | try: 21 | val = cin() 22 | if debug: 23 | sys.stdout.write("Debug: "+str(val)+"\n") 24 | sys.stdout.flush() 25 | received.append(val) 26 | except ChannelPoisonException: 27 | poison = True 28 | break 29 | except ChannelRetireException: 30 | retire = True 31 | break 32 | 33 | if quit_on_count and len(received) == count: 34 | break 35 | 36 | error = "" 37 | 38 | if (len(received) < minimum): 39 | error += "Wrong number of values: "+str(len(received))+"\n" 40 | error += "Expected the minimum number of values: "+str(minimum)+"\n" 41 | 42 | if count: 43 | if minimum: 44 | if (len(received) > count): 45 | error += "Wrong number of values: "+str(len(received))+"\n" 46 | error += "Expected a maximum number of values: "+str(count)+"\n" 47 | else: 48 | if not (len(received) == count): 49 | error += "Wrong number of values: "+str(len(received))+"\n" 50 | error += "Expected number of values: "+str(count)+"\n" 51 | 52 | 53 | if vocabulary: 54 | for i in range(len(received)): 55 | if received[i] not in vocabulary: 56 | error += "Value "+ str(received[i]) + " not in vocabulary\n" 57 | 58 | if (ordered): 59 | for i in range(len(received)): 60 | if received[i] != vocabulary[i % len(vocabulary)]: 61 | error += "Value "+ str(received[i]) + " != " + str(vocabulary[i % len(vocabulary)])+" in vocabulary\n" 62 | 63 | if error: 64 | sys.stdout.write(name+"\n") 65 | sys.stdout.write(error) 66 | print_state(received, poison, retire) 67 | else: 68 | sys.stdout.write("OK - "+ name+ "\n") 69 | -------------------------------------------------------------------------------- /test/unix/clusterprocesstest.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. THE 14 | SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | """ 22 | 23 | 24 | import sys 25 | sys.path.insert(0, "../..") 26 | from pycsp.parallel import * 27 | import check 28 | import time 29 | import random 30 | 31 | @choice 32 | def action(assertCheck, id, channel_input=None): 33 | if assertCheck: 34 | assertCheck(id) 35 | 36 | @clusterprocess(cluster_nodefile="./nodefile") 37 | def reader(cin, id, use_sleeper, assertCheck=None): 38 | while True: 39 | if use_sleeper: random_sleeper() 40 | got = cin() 41 | if assertCheck: 42 | assertCheck(id) 43 | 44 | @clusterprocess(cluster_nodefile="./nodefile") 45 | def writer(cout, id, cnt, use_sleeper): 46 | for i in range(cnt): 47 | if use_sleeper: random_sleeper() 48 | cout((id, i)) 49 | retire(cout) 50 | 51 | @clusterprocess(cluster_nodefile="./nodefile") 52 | def par_reader(cin1,cin2,cin3,cin4, cnt, use_sleeper, assertCheck=None): 53 | while True: 54 | if use_sleeper: 55 | random_sleeper() 56 | 57 | AltSelect( 58 | InputGuard(cin1, action(assertCheck, 0)), 59 | InputGuard(cin2, action(assertCheck, 1)), 60 | InputGuard(cin3, action(assertCheck, 2)), 61 | InputGuard(cin4, action(assertCheck, 3)) 62 | ) 63 | 64 | @clusterprocess(cluster_nodefile="./nodefile") 65 | def par_fair_reader(cin1,cin2,cin3,cin4, cnt, use_sleeper, assertCheck=None): 66 | while True: 67 | if use_sleeper: 68 | random_sleeper() 69 | 70 | FairSelect( 71 | InputGuard(cin1, action(assertCheck, 0)), 72 | InputGuard(cin2, action(assertCheck, 1)), 73 | InputGuard(cin3, action(assertCheck, 2)), 74 | InputGuard(cin4, action(assertCheck, 3)) 75 | ) 76 | 77 | @clusterprocess(cluster_nodefile="./nodefile") 78 | def par_pri_reader(cin1,cin2,cin3,cin4, cnt, use_sleeper, assertCheck=None): 79 | while True: 80 | if use_sleeper: 81 | random_sleeper() 82 | 83 | PriSelect( 84 | InputGuard(cin1, action(assertCheck, 0)), 85 | InputGuard(cin2, action(assertCheck, 1)), 86 | InputGuard(cin3, action(assertCheck, 2)), 87 | InputGuard(cin4, action(assertCheck, 3)) 88 | ) 89 | 90 | @clusterprocess(cluster_nodefile="./nodefile") 91 | def return_msg(cin, use_sleeper): 92 | if use_sleeper: random_sleeper() 93 | return cin() 94 | 95 | @io 96 | def random_sleeper(): 97 | time.sleep(random.random()/100) 98 | 99 | def Parallel_Test(sleeper): 100 | 101 | c1=Channel() 102 | 103 | L= Parallel(writer(c1.writer(), 0, 10, sleeper), 10 * return_msg(c1.reader(), sleeper)) 104 | 105 | if L and len(L) == 11 and L[0] == None and not None in L[1:]: 106 | print(("OK - ClusterProcess_Parallel_Test"+str(sleeper))) 107 | else: 108 | print(("Error - ClusterProcess_Parallel_Test"+str(sleeper))) 109 | print((str(L))) 110 | 111 | def Sequence_Test(sleeper): 112 | 113 | c1=Channel() 114 | 115 | Spawn(writer(c1.writer(), 0, 10, sleeper)) 116 | L= Sequence(10 * return_msg(c1.reader(), sleeper)) 117 | 118 | if L and len(L) == 10 and not None in L: 119 | print(("OK - ClusterProcess_Sequence_Test"+str(sleeper))) 120 | else: 121 | print(("Error - ClusterProcess_Sequence_Test"+str(sleeper))) 122 | print((str(L))) 123 | 124 | def One2One_Test(read_sleeper, write_sleeper): 125 | x = Channel() 126 | Spawn(check.Assert(x.reader(), "ClusterProcess_One2One_Test"+str(read_sleeper)+str(write_sleeper), count=10, vocabulary=[0])) 127 | 128 | c1=Channel() 129 | Parallel(reader(c1.reader(), 0 , read_sleeper, x.writer()), writer(c1.writer(),1,10, write_sleeper)) 130 | 131 | def Any2One_Alting_Test(read_sleeper, write_sleeper): 132 | x = Channel() 133 | Spawn(check.Assert(x.reader(), "ClusterProcess_Any2One_Alting_Test"+str(read_sleeper)+str(write_sleeper), count=40, minimum=10, vocabulary=[0,1,2,3], quit_on_count=True)) 134 | 135 | c1=Channel() 136 | c2=Channel() 137 | c3=Channel() 138 | c4=Channel() 139 | 140 | cnt = 10 141 | 142 | Parallel(par_reader(c1.reader(), c2.reader(), c3.reader(), c4.reader(),cnt, read_sleeper, x.writer()), 143 | writer(c1.writer(),0,cnt, write_sleeper), 144 | writer(c2.writer(),1,cnt, write_sleeper), 145 | writer(c3.writer(),2,cnt, write_sleeper), 146 | writer(c4.writer(),3,cnt, write_sleeper)) 147 | 148 | def Any2One_FairAlting_Test(read_sleeper, write_sleeper): 149 | x = Channel() 150 | Spawn(check.Assert(x.reader(), "ClusterProcess_Any2One_FairAlting_Test"+str(read_sleeper)+str(write_sleeper), count=40, minimum=10, vocabulary=[0,1,2,3], quit_on_count=True)) 151 | 152 | c1=Channel() 153 | c2=Channel() 154 | c3=Channel() 155 | c4=Channel() 156 | 157 | cnt = 10 158 | 159 | Parallel(par_fair_reader(c1.reader(), c2.reader(), c3.reader(), c4.reader(),cnt, read_sleeper, x.writer()), 160 | writer(c1.writer(),0,cnt, write_sleeper), 161 | writer(c2.writer(),1,cnt, write_sleeper), 162 | writer(c3.writer(),2,cnt, write_sleeper), 163 | writer(c4.writer(),3,cnt, write_sleeper)) 164 | 165 | def Any2One_PriAlting_Test(read_sleeper, write_sleeper): 166 | x = Channel() 167 | Spawn(check.Assert(x.reader(), "ClusterProcess_Any2One_PriAlting_Test"+str(read_sleeper)+str(write_sleeper), count=40, minimum=10, vocabulary=[0,1,2,3], quit_on_count=True)) 168 | 169 | c1=Channel() 170 | c2=Channel() 171 | c3=Channel() 172 | c4=Channel() 173 | 174 | cnt = 10 175 | 176 | Parallel(par_pri_reader(c1.reader(), c2.reader(), c3.reader(), c4.reader(),cnt, read_sleeper, x.writer()), 177 | writer(c1.writer(),0,cnt, write_sleeper), 178 | writer(c2.writer(),1,cnt, write_sleeper), 179 | writer(c3.writer(),2,cnt, write_sleeper), 180 | writer(c4.writer(),3,cnt, write_sleeper)) 181 | 182 | def Any2Any_Test(read_sleeper, write_sleeper): 183 | x = Channel() 184 | Spawn(check.Assert(x.reader(), "ClusterProcess_Any2Any_Test"+str(read_sleeper)+str(write_sleeper), count=40, vocabulary=[0,1,2,3])) 185 | 186 | c1=Channel() 187 | cnt = 10 188 | 189 | Parallel(reader(c1.reader(),0, read_sleeper, x.writer()), writer(c1.writer(),0,cnt, write_sleeper), 190 | reader(c1.reader(),1, read_sleeper, x.writer()), writer(c1.writer(),1,cnt, write_sleeper), 191 | reader(c1.reader(),2, read_sleeper, x.writer()), writer(c1.writer(),2,cnt, write_sleeper), 192 | reader(c1.reader(),3, read_sleeper, x.writer()), writer(c1.writer(),3,cnt, write_sleeper)) 193 | 194 | 195 | def autotest(): 196 | for rsleep in [False,True]: 197 | 198 | Sequence_Test(rsleep) 199 | Parallel_Test(rsleep) 200 | 201 | for wsleep in [False,True]: 202 | 203 | One2One_Test(rsleep, wsleep) 204 | Any2One_Alting_Test(rsleep, wsleep) 205 | Any2One_FairAlting_Test(rsleep, wsleep) 206 | Any2One_PriAlting_Test(rsleep, wsleep) 207 | Any2Any_Test(rsleep, wsleep) 208 | shutdown() 209 | 210 | if __name__ == '__main__': 211 | autotest() 212 | shutdown() 213 | -------------------------------------------------------------------------------- /test/unix/multiprocesstest.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. THE 14 | SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | """ 22 | 23 | 24 | import sys 25 | sys.path.insert(0, "../..") 26 | from pycsp.parallel import * 27 | import check 28 | import time 29 | import random 30 | 31 | @choice 32 | def action(assertCheck, id, channel_input=None): 33 | if assertCheck: 34 | assertCheck(id) 35 | 36 | @multiprocess 37 | def reader(cin, id, sleeper, assertCheck=None): 38 | while True: 39 | if sleeper: sleeper() 40 | got = cin() 41 | if assertCheck: 42 | assertCheck(id) 43 | 44 | @multiprocess 45 | def writer(cout, id, cnt, sleeper): 46 | for i in range(cnt): 47 | if sleeper: sleeper() 48 | cout((id, i)) 49 | retire(cout) 50 | 51 | @multiprocess 52 | def par_reader(cin1,cin2,cin3,cin4, cnt, sleeper, assertCheck=None): 53 | while True: 54 | if sleeper: sleeper() 55 | 56 | AltSelect( 57 | InputGuard(cin1, action(assertCheck, 0)), 58 | InputGuard(cin2, action(assertCheck, 1)), 59 | InputGuard(cin3, action(assertCheck, 2)), 60 | InputGuard(cin4, action(assertCheck, 3)) 61 | ) 62 | 63 | @multiprocess 64 | def par_fair_reader(cin1,cin2,cin3,cin4, cnt, sleeper, assertCheck=None): 65 | while True: 66 | if sleeper: sleeper() 67 | 68 | FairSelect( 69 | InputGuard(cin1, action(assertCheck, 0)), 70 | InputGuard(cin2, action(assertCheck, 1)), 71 | InputGuard(cin3, action(assertCheck, 2)), 72 | InputGuard(cin4, action(assertCheck, 3)) 73 | ) 74 | 75 | @multiprocess 76 | def par_pri_reader(cin1,cin2,cin3,cin4, cnt, sleeper, assertCheck=None): 77 | while True: 78 | if sleeper: sleeper() 79 | 80 | PriSelect( 81 | InputGuard(cin1, action(assertCheck, 0)), 82 | InputGuard(cin2, action(assertCheck, 1)), 83 | InputGuard(cin3, action(assertCheck, 2)), 84 | InputGuard(cin4, action(assertCheck, 3)) 85 | ) 86 | 87 | @multiprocess 88 | def return_msg(cin, sleeper): 89 | if sleeper: sleeper() 90 | return cin() 91 | 92 | 93 | @io 94 | def sleep_one(): 95 | time.sleep(0.01) 96 | 97 | @io 98 | def sleep_random(): 99 | time.sleep(random.random()/100) 100 | 101 | def Parallel_Test(sleeper): 102 | 103 | c1=Channel() 104 | 105 | L= Parallel(writer(c1.writer(), 0, 10, sleeper), 10 * return_msg(c1.reader(), sleeper)) 106 | 107 | if L and len(L) == 11 and L[0] == None and not None in L[1:]: 108 | print(("OK - MultiProcess_Parallel_Test"+str(sleeper))) 109 | else: 110 | print(("Error - MultiProcess_Parallel_Test"+str(sleeper))) 111 | print((str(L))) 112 | 113 | def Sequence_Test(sleeper): 114 | 115 | c1=Channel() 116 | 117 | Spawn(writer(c1.writer(), 0, 10, sleeper)) 118 | L= Sequence(10 * return_msg(c1.reader(), sleeper)) 119 | 120 | if L and len(L) == 10 and not None in L: 121 | print(("OK - MultiProcess_Sequence_Test"+str(sleeper))) 122 | else: 123 | print(("Error - MultiProcess_Sequence_Test"+str(sleeper))) 124 | print((str(L))) 125 | 126 | def One2One_Test(read_sleeper, write_sleeper): 127 | x = Channel() 128 | Spawn(check.Assert(x.reader(), "MultiProcess_One2One_Test"+str(read_sleeper)+str(write_sleeper), count=10, vocabulary=[0])) 129 | 130 | c1=Channel() 131 | Parallel(reader(c1.reader(), 0 , read_sleeper, x.writer()), writer(c1.writer(),1,10, write_sleeper)) 132 | 133 | def Any2One_Alting_Test(read_sleeper, write_sleeper): 134 | x = Channel() 135 | Spawn(check.Assert(x.reader(), "MultiProcess_Any2One_Alting_Test"+str(read_sleeper)+str(write_sleeper), count=40, minimum=10, vocabulary=[0,1,2,3], quit_on_count=True)) 136 | 137 | c1=Channel() 138 | c2=Channel() 139 | c3=Channel() 140 | c4=Channel() 141 | 142 | cnt = 10 143 | 144 | Parallel(par_reader(c1.reader(), c2.reader(), c3.reader(), c4.reader(),cnt, read_sleeper, x.writer()), 145 | writer(c1.writer(),0,cnt, write_sleeper), 146 | writer(c2.writer(),1,cnt, write_sleeper), 147 | writer(c3.writer(),2,cnt, write_sleeper), 148 | writer(c4.writer(),3,cnt, write_sleeper)) 149 | 150 | def Any2One_FairAlting_Test(read_sleeper, write_sleeper): 151 | x = Channel() 152 | Spawn(check.Assert(x.reader(), "MultiProcess_Any2One_FairAlting_Test"+str(read_sleeper)+str(write_sleeper), count=40, minimum=10, vocabulary=[0,1,2,3], quit_on_count=True)) 153 | 154 | c1=Channel() 155 | c2=Channel() 156 | c3=Channel() 157 | c4=Channel() 158 | 159 | cnt = 10 160 | 161 | Parallel(par_fair_reader(c1.reader(), c2.reader(), c3.reader(), c4.reader(),cnt, read_sleeper, x.writer()), 162 | writer(c1.writer(),0,cnt, write_sleeper), 163 | writer(c2.writer(),1,cnt, write_sleeper), 164 | writer(c3.writer(),2,cnt, write_sleeper), 165 | writer(c4.writer(),3,cnt, write_sleeper)) 166 | 167 | def Any2One_PriAlting_Test(read_sleeper, write_sleeper): 168 | x = Channel() 169 | Spawn(check.Assert(x.reader(), "MultiProcess_Any2One_PriAlting_Test"+str(read_sleeper)+str(write_sleeper), count=40, minimum=10, vocabulary=[0,1,2,3], quit_on_count=True)) 170 | 171 | c1=Channel() 172 | c2=Channel() 173 | c3=Channel() 174 | c4=Channel() 175 | 176 | cnt = 10 177 | 178 | Parallel(par_pri_reader(c1.reader(), c2.reader(), c3.reader(), c4.reader(),cnt, read_sleeper, x.writer()), 179 | writer(c1.writer(),0,cnt, write_sleeper), 180 | writer(c2.writer(),1,cnt, write_sleeper), 181 | writer(c3.writer(),2,cnt, write_sleeper), 182 | writer(c4.writer(),3,cnt, write_sleeper)) 183 | 184 | def Any2Any_Test(read_sleeper, write_sleeper): 185 | x = Channel() 186 | Spawn(check.Assert(x.reader(), "MultiProcess_Any2Any_Test"+str(read_sleeper)+str(write_sleeper), count=40, vocabulary=[0,1,2,3])) 187 | 188 | c1=Channel() 189 | cnt = 10 190 | 191 | Parallel(reader(c1.reader(),0, read_sleeper, x.writer()), writer(c1.writer(),0,cnt, write_sleeper), 192 | reader(c1.reader(),1, read_sleeper, x.writer()), writer(c1.writer(),1,cnt, write_sleeper), 193 | reader(c1.reader(),2, read_sleeper, x.writer()), writer(c1.writer(),2,cnt, write_sleeper), 194 | reader(c1.reader(),3, read_sleeper, x.writer()), writer(c1.writer(),3,cnt, write_sleeper)) 195 | 196 | 197 | def autotest(): 198 | for read_sleep in [('Zero', None), ('One',sleep_one), ('Random',sleep_random)]: 199 | 200 | Sequence_Test(read_sleep[1]) 201 | Parallel_Test(read_sleep[1]) 202 | 203 | for write_sleep in [('Zero', None), ('One',sleep_one), ('Random',sleep_random)]: 204 | rname, rsleep = read_sleep 205 | wname, wsleep = write_sleep 206 | 207 | if not rsleep==wsleep==sleep_one: 208 | One2One_Test(rsleep, wsleep) 209 | Any2One_Alting_Test(rsleep, wsleep) 210 | Any2One_FairAlting_Test(rsleep, wsleep) 211 | Any2One_PriAlting_Test(rsleep, wsleep) 212 | Any2Any_Test(rsleep, wsleep) 213 | 214 | if __name__ == '__main__': 215 | autotest() 216 | shutdown() 217 | -------------------------------------------------------------------------------- /test/unix/nodefile: -------------------------------------------------------------------------------- 1 | localhost 2 | localhost 3 | -------------------------------------------------------------------------------- /test/unix/remotetest.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | import sys 8 | sys.path.insert(0, "../..") 9 | from pycsp.parallel import * 10 | 11 | import time 12 | import random 13 | import sys 14 | 15 | @io 16 | def sleep_random(): 17 | time.sleep(random.random()/10) 18 | 19 | @io 20 | def sleep_long_random(): 21 | time.sleep(random.random()*5) 22 | 23 | 24 | @process 25 | def connect_reader(remote_addr): 26 | while True: 27 | try: 28 | X=Channel('A', connect=remote_addr) 29 | cin = X.reader() 30 | val = cin() 31 | sys.stdout.write(str(val) + ' ') 32 | return 33 | 34 | except ChannelConnectException as e: 35 | sys.stdout.write('.') 36 | 37 | @process 38 | def connect_reader_quit(remote_addr): 39 | while True: 40 | try: 41 | X=Channel('A', connect=remote_addr) 42 | cin = X.reader() 43 | val = cin() 44 | raise Exception("Failed!") 45 | 46 | except ChannelConnectException as e: 47 | sys.stdout.write('OK') 48 | return 49 | 50 | 51 | def host_writer(N=1): 52 | X=Channel('A') 53 | cout = X.writer() 54 | for i in range(N): 55 | cout(i) 56 | 57 | def ConnectCatchFailed(): 58 | addr = ('localhost', 22222) 59 | Parallel(connect_reader_quit(addr)) 60 | 61 | def BindCatchFailed(): 62 | addr = ('localhost', 22223) 63 | Spawn(MultiProcess(host_writer, pycsp_host=addr[0], pycsp_port=addr[1])) 64 | 65 | # Wait for spawned process 66 | time.sleep(1) 67 | 68 | # Fail to bind! 69 | try: 70 | Parallel(MultiProcess(host_writer, pycsp_host=addr[0], pycsp_port=addr[1])) 71 | except ChannelBindException as e: 72 | sys.stdout.write('OK') 73 | 74 | # Connect to spawned process 75 | X=Channel('A', connect=addr) 76 | cin = X.reader() 77 | X= cin() 78 | cin.disconnect() 79 | 80 | def ConnectOne(sleeper, port): 81 | addr = ('localhost', port) 82 | Spawn(connect_reader(addr)) 83 | 84 | if sleeper: 85 | sleeper() 86 | 87 | Parallel(MultiProcess(host_writer, pycsp_host=addr[0], pycsp_port=addr[1])) 88 | 89 | sys.stdout.write('OK') 90 | 91 | 92 | def ConnectMultiple(sleeper, port): 93 | addr = ('localhost', port) 94 | Spawn(10 * connect_reader(addr)) 95 | 96 | if sleeper: 97 | sleeper() 98 | 99 | Parallel(MultiProcess(host_writer, N=10, pycsp_host=addr[0], pycsp_port=addr[1])) 100 | 101 | sys.stdout.write('OK') 102 | 103 | if __name__ == '__main__': 104 | 105 | 106 | sys.stdout.write("ConnectCatchFailed:") 107 | ConnectCatchFailed() 108 | sys.stdout.write("\n") 109 | 110 | sys.stdout.write("BindCatchFailed:") 111 | BindCatchFailed() 112 | sys.stdout.write("\n") 113 | 114 | sys.stdout.write("ConnectOne-sleep_random:") 115 | ConnectOne(sleep_random, 12346) 116 | sys.stdout.write("\n") 117 | 118 | sys.stdout.write("ConnectOne-sleep_long_random:") 119 | ConnectOne(sleep_long_random, 12347) 120 | sys.stdout.write("\n") 121 | 122 | sys.stdout.write("ConnectMultiple-sleep_random:") 123 | ConnectMultiple(sleep_random, 12348) 124 | sys.stdout.write("\n") 125 | 126 | sys.stdout.write("ConnectMultiple-sleep_long_random:") 127 | ConnectMultiple(sleep_long_random, 12349) 128 | sys.stdout.write("\n") 129 | 130 | 131 | shutdown() 132 | -------------------------------------------------------------------------------- /test/unix/sshprocesstest.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. THE 14 | SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | """ 22 | 23 | 24 | import sys 25 | sys.path.insert(0, "../..") 26 | from pycsp.parallel import * 27 | import check 28 | import time 29 | import random 30 | 31 | @choice 32 | def action(assertCheck, id, channel_input=None): 33 | if assertCheck: 34 | assertCheck(id) 35 | 36 | @sshprocess(ssh_host="localhost") 37 | def reader(cin, id, use_sleeper, assertCheck=None): 38 | while True: 39 | if use_sleeper: random_sleeper() 40 | got = cin() 41 | if assertCheck: 42 | assertCheck(id) 43 | 44 | @sshprocess(ssh_host="localhost") 45 | def writer(cout, id, cnt, use_sleeper): 46 | for i in range(cnt): 47 | if use_sleeper: random_sleeper() 48 | cout((id, i)) 49 | retire(cout) 50 | 51 | @sshprocess 52 | def par_reader(cin1,cin2,cin3,cin4, cnt, use_sleeper, assertCheck=None): 53 | while True: 54 | if use_sleeper: 55 | random_sleeper() 56 | 57 | AltSelect( 58 | InputGuard(cin1, action(assertCheck, 0)), 59 | InputGuard(cin2, action(assertCheck, 1)), 60 | InputGuard(cin3, action(assertCheck, 2)), 61 | InputGuard(cin4, action(assertCheck, 3)) 62 | ) 63 | 64 | @sshprocess 65 | def par_fair_reader(cin1,cin2,cin3,cin4, cnt, use_sleeper, assertCheck=None): 66 | while True: 67 | if use_sleeper: 68 | random_sleeper() 69 | 70 | FairSelect( 71 | InputGuard(cin1, action(assertCheck, 0)), 72 | InputGuard(cin2, action(assertCheck, 1)), 73 | InputGuard(cin3, action(assertCheck, 2)), 74 | InputGuard(cin4, action(assertCheck, 3)) 75 | ) 76 | 77 | @sshprocess 78 | def par_pri_reader(cin1,cin2,cin3,cin4, cnt, use_sleeper, assertCheck=None): 79 | while True: 80 | if use_sleeper: 81 | random_sleeper() 82 | 83 | PriSelect( 84 | InputGuard(cin1, action(assertCheck, 0)), 85 | InputGuard(cin2, action(assertCheck, 1)), 86 | InputGuard(cin3, action(assertCheck, 2)), 87 | InputGuard(cin4, action(assertCheck, 3)) 88 | ) 89 | 90 | @sshprocess 91 | def return_msg(cin, use_sleeper): 92 | if use_sleeper: random_sleeper() 93 | return cin() 94 | 95 | @io 96 | def random_sleeper(): 97 | time.sleep(random.random()/100) 98 | 99 | def Parallel_Test(sleeper): 100 | 101 | c1=Channel() 102 | 103 | L= Parallel(writer(c1.writer(), 0, 10, sleeper), 10 * return_msg(c1.reader(), sleeper)) 104 | 105 | if L and len(L) == 11 and L[0] == None and not None in L[1:]: 106 | print(("OK - SSHProcess_Parallel_Test"+str(sleeper))) 107 | else: 108 | print(("Error - SSHProcess_Parallel_Test"+str(sleeper))) 109 | print((str(L))) 110 | 111 | def Sequence_Test(sleeper): 112 | 113 | c1=Channel() 114 | 115 | Spawn(writer(c1.writer(), 0, 10, sleeper)) 116 | L= Sequence(10 * return_msg(c1.reader(), sleeper)) 117 | 118 | if L and len(L) == 10 and not None in L: 119 | print(("OK - SSHProcess_Sequence_Test"+str(sleeper))) 120 | else: 121 | print(("Error - SSHProcess_Sequence_Test"+str(sleeper))) 122 | print((str(L))) 123 | 124 | def One2One_Test(read_sleeper, write_sleeper): 125 | x = Channel() 126 | Spawn(check.Assert(x.reader(), "SSHProcess_One2One_Test"+str(read_sleeper)+str(write_sleeper), count=10, vocabulary=[0])) 127 | 128 | c1=Channel() 129 | Parallel(reader(c1.reader(), 0 , read_sleeper, x.writer()), writer(c1.writer(),1,10, write_sleeper)) 130 | 131 | def Any2One_Alting_Test(read_sleeper, write_sleeper): 132 | x = Channel() 133 | Spawn(check.Assert(x.reader(), "SSHProcess_Any2One_Alting_Test"+str(read_sleeper)+str(write_sleeper), count=40, minimum=10, vocabulary=[0,1,2,3], quit_on_count=True)) 134 | 135 | c1=Channel() 136 | c2=Channel() 137 | c3=Channel() 138 | c4=Channel() 139 | 140 | cnt = 10 141 | 142 | Parallel(par_reader(c1.reader(), c2.reader(), c3.reader(), c4.reader(),cnt, read_sleeper, x.writer()), 143 | writer(c1.writer(),0,cnt, write_sleeper), 144 | writer(c2.writer(),1,cnt, write_sleeper), 145 | writer(c3.writer(),2,cnt, write_sleeper), 146 | writer(c4.writer(),3,cnt, write_sleeper)) 147 | 148 | def Any2One_FairAlting_Test(read_sleeper, write_sleeper): 149 | x = Channel() 150 | Spawn(check.Assert(x.reader(), "SSHProcess_Any2One_FairAlting_Test"+str(read_sleeper)+str(write_sleeper), count=40, minimum=10, vocabulary=[0,1,2,3], quit_on_count=True)) 151 | 152 | c1=Channel() 153 | c2=Channel() 154 | c3=Channel() 155 | c4=Channel() 156 | 157 | cnt = 10 158 | 159 | Parallel(par_fair_reader(c1.reader(), c2.reader(), c3.reader(), c4.reader(),cnt, read_sleeper, x.writer()), 160 | writer(c1.writer(),0,cnt, write_sleeper), 161 | writer(c2.writer(),1,cnt, write_sleeper), 162 | writer(c3.writer(),2,cnt, write_sleeper), 163 | writer(c4.writer(),3,cnt, write_sleeper)) 164 | 165 | def Any2One_PriAlting_Test(read_sleeper, write_sleeper): 166 | x = Channel() 167 | Spawn(check.Assert(x.reader(), "SSHProcess_Any2One_PriAlting_Test"+str(read_sleeper)+str(write_sleeper), count=40, minimum=10, vocabulary=[0,1,2,3], quit_on_count=True)) 168 | 169 | c1=Channel() 170 | c2=Channel() 171 | c3=Channel() 172 | c4=Channel() 173 | 174 | cnt = 10 175 | 176 | Parallel(par_pri_reader(c1.reader(), c2.reader(), c3.reader(), c4.reader(),cnt, read_sleeper, x.writer()), 177 | writer(c1.writer(),0,cnt, write_sleeper), 178 | writer(c2.writer(),1,cnt, write_sleeper), 179 | writer(c3.writer(),2,cnt, write_sleeper), 180 | writer(c4.writer(),3,cnt, write_sleeper)) 181 | 182 | def Any2Any_Test(read_sleeper, write_sleeper): 183 | x = Channel() 184 | Spawn(check.Assert(x.reader(), "SSHProcess_Any2Any_Test"+str(read_sleeper)+str(write_sleeper), count=40, vocabulary=[0,1,2,3])) 185 | 186 | c1=Channel() 187 | cnt = 10 188 | 189 | Parallel(reader(c1.reader(),0, read_sleeper, x.writer()), writer(c1.writer(),0,cnt, write_sleeper), 190 | reader(c1.reader(),1, read_sleeper, x.writer()), writer(c1.writer(),1,cnt, write_sleeper), 191 | reader(c1.reader(),2, read_sleeper, x.writer()), writer(c1.writer(),2,cnt, write_sleeper), 192 | reader(c1.reader(),3, read_sleeper, x.writer()), writer(c1.writer(),3,cnt, write_sleeper)) 193 | 194 | 195 | def autotest(): 196 | for rsleep in [False,True]: 197 | 198 | Sequence_Test(rsleep) 199 | Parallel_Test(rsleep) 200 | 201 | for wsleep in [False,True]: 202 | 203 | One2One_Test(rsleep, wsleep) 204 | Any2One_Alting_Test(rsleep, wsleep) 205 | Any2One_FairAlting_Test(rsleep, wsleep) 206 | Any2One_PriAlting_Test(rsleep, wsleep) 207 | Any2Any_Test(rsleep, wsleep) 208 | shutdown() 209 | 210 | if __name__ == '__main__': 211 | autotest() 212 | shutdown() 213 | -------------------------------------------------------------------------------- /test/windows/remotetest.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2009 John Markus Bjoerndalen , 3 | Brian Vinter , Rune M. Friborg . 4 | See LICENSE.txt for licensing details (MIT License). 5 | """ 6 | 7 | import sys 8 | sys.path.insert(0, "../..") 9 | from pycsp.parallel import * 10 | 11 | import time 12 | import random 13 | import sys 14 | 15 | def sleep_random(): 16 | time.sleep(2+random.random()/10) 17 | 18 | def sleep_long_random(): 19 | time.sleep(2+random.random()*5) 20 | 21 | 22 | def connect_reader(remote_addr): 23 | while True: 24 | try: 25 | X=Channel('A', connect=remote_addr) 26 | cin = X.reader() 27 | val = cin() 28 | sys.stdout.write(str(val) + ' ') 29 | return 30 | 31 | except ChannelConnectException as e: 32 | sys.stdout.write('.') 33 | 34 | def connect_reader_quit(remote_addr): 35 | while True: 36 | try: 37 | X=Channel('A', connect=remote_addr) 38 | cin = X.reader() 39 | val = cin() 40 | raise Exception("Failed!") 41 | 42 | except ChannelConnectException as e: 43 | sys.stdout.write('OK') 44 | return 45 | 46 | 47 | def host_writer(N=1): 48 | X=Channel('A') 49 | cout = X.writer() 50 | for i in range(N): 51 | cout(i) 52 | 53 | def ConnectCatchFailed(): 54 | addr = ('localhost', 22222) 55 | Parallel(Process(connect_reader_quit,addr)) 56 | 57 | def BindCatchFailed(): 58 | addr = ('localhost', 22223) 59 | Spawn(MultiProcess(host_writer, pycsp_host=addr[0], pycsp_port=addr[1])) 60 | 61 | import time 62 | time.sleep(5) 63 | 64 | # Fail to bind! 65 | try: 66 | Parallel(MultiProcess(host_writer, pycsp_host=addr[0], pycsp_port=addr[1])) 67 | except ChannelBindException as e: 68 | sys.stdout.write('OK') 69 | 70 | # Connect to spawned process 71 | X=Channel('A', connect=addr) 72 | cin = X.reader() 73 | X= cin() 74 | cin.disconnect() 75 | 76 | def ConnectOne(sleeper, port): 77 | addr = ('localhost', port) 78 | Spawn(Process(connect_reader,addr)) 79 | 80 | if sleeper: 81 | sleeper() 82 | 83 | Parallel(MultiProcess(host_writer, pycsp_host=addr[0], pycsp_port=addr[1])) 84 | 85 | sys.stdout.write('OK') 86 | 87 | 88 | def ConnectMultiple(sleeper, port): 89 | addr = ('localhost', port) 90 | Spawn(10 * Process(connect_reader,addr)) 91 | 92 | if sleeper: 93 | sleeper() 94 | 95 | Parallel(MultiProcess(host_writer, N=10, pycsp_host=addr[0], pycsp_port=addr[1])) 96 | 97 | sys.stdout.write('OK') 98 | 99 | if __name__ == '__main__': 100 | 101 | sys.stdout.write("ConnectCatchFailed:") 102 | ConnectCatchFailed() 103 | sys.stdout.write("\n") 104 | 105 | sys.stdout.write("ConnectOne-sleep_random:") 106 | ConnectOne(sleep_random, 12346) 107 | sys.stdout.write("\n") 108 | 109 | sys.stdout.write("ConnectOne-sleep_long_random:") 110 | ConnectOne(sleep_long_random, 12347) 111 | sys.stdout.write("\n") 112 | 113 | sys.stdout.write("ConnectMultiple-sleep_random:") 114 | ConnectMultiple(sleep_random, 12348) 115 | sys.stdout.write("\n") 116 | 117 | sys.stdout.write("ConnectMultiple-sleep_long_random:") 118 | ConnectMultiple(sleep_long_random, 12349) 119 | sys.stdout.write("\n") 120 | 121 | 122 | shutdown() 123 | -------------------------------------------------------------------------------- /tools/PlayTrace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runefriborg/pycsp/6e5c2af90d1bebe4a4bf4de66a2af7a4e9c907be/tools/PlayTrace.png --------------------------------------------------------------------------------