├── .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
--------------------------------------------------------------------------------