├── .hgignore ├── ChangeLog ├── IRClogs └── Europython2010Sprint.log ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.md ├── applications └── python-csp.desktop ├── benchmark ├── commstime │ ├── commstime.mcsp │ └── commstime.py └── tokenring │ ├── plot_results.py │ └── tokenring.py ├── csp ├── __init__.py ├── builtins.py ├── cchannels │ ├── CChannel.py │ ├── Channel.c │ ├── Channel.h │ ├── Channel.i │ ├── Channel.py │ ├── Channel_wrap.c │ ├── Makefile │ └── tests │ │ ├── commstime.py │ │ ├── fulladder.py │ │ ├── patterns.py │ │ ├── simple.py │ │ └── tokenring.py ├── csp.py ├── dsp.py ├── guards.py ├── lint │ ├── __init__.py │ ├── channels.py │ ├── lint.py │ └── processes.py ├── os_process.py ├── os_thread.py ├── patterns.py └── tracer │ ├── __init__.py │ ├── cspmodel.py │ └── tracer.py ├── docs ├── doctrees │ ├── builtins.doctree │ ├── csp.doctree │ ├── environment.pickle │ ├── guards.doctree │ ├── index.doctree │ ├── mandelbrot.doctree │ ├── patterns.doctree │ └── tracer.doctree └── html │ ├── .buildinfo │ ├── _sources │ ├── builtins.txt │ ├── csp.txt │ ├── guards.txt │ ├── index.txt │ ├── mandelbrot.txt │ ├── patterns.txt │ └── tracer.txt │ ├── _static │ ├── basic.css │ ├── default.css │ ├── doctools.js │ ├── file.png │ ├── jquery.js │ ├── minus.png │ ├── plus.png │ ├── pygments.css │ ├── pythoncsp-docs.png │ └── searchtools.js │ ├── builtins.html │ ├── csp.html │ ├── genindex.html │ ├── guards.html │ ├── index.html │ ├── mandelbrot.html │ ├── modindex.html │ ├── objects.inv │ ├── patterns.html │ ├── search.html │ ├── searchindex.js │ └── tracer.html ├── examples ├── barber │ ├── barber.py │ ├── kbox.occ │ └── queue.py ├── boids │ ├── boidprocs-obstacles.dia │ ├── boidprocs.dia │ ├── boids-part1.png │ ├── boids-part2.png │ ├── boids-part3.png │ ├── boids-part4.png │ ├── boids-sliders.png │ ├── part1-classes.png │ ├── part1.py │ ├── part2-classes.png │ ├── part2.py │ ├── part3-classes.png │ ├── part3.py │ ├── part4-classes.png │ ├── part4-sliders.py │ └── part4.py ├── builtins │ └── builtin-example.py ├── circuits │ └── fulladder.py ├── mandelbrot │ ├── mandelbrot-WorkerFarmer.py │ ├── mandelbrot-noalt.py │ ├── mandelbrot-onech.py │ └── mandelbrot.py ├── matrix │ └── matrix.py ├── monte_carlo │ └── pi.py ├── raytracer │ └── raytracer.py └── sensors │ ├── dsp.py │ ├── hidsensor.py │ ├── oak_oscope.py │ ├── oscilloscope.py │ ├── toradex.py │ └── toradex_csp.py ├── exstatic ├── __init__.py ├── cspwarnings.py ├── icode.py ├── py2icode.py ├── stack.py ├── visitor.py └── warnings.py ├── gadget └── readme.xml ├── logo ├── logo-square.png ├── pythoncsp-docs.png ├── pythoncsp-logo.png └── pythoncsp-logo.xcf ├── make.bat ├── maketags.sh ├── rst ├── Tutorial.wiki ├── TutorialPage0.wiki ├── TutorialPage1.wiki ├── TutorialPage2.wiki ├── TutorialPage3.wiki ├── TutorialPage4.wiki ├── TutorialPage5.wiki ├── TutorialPage7.wiki ├── TutorialPage8.wiki ├── builtins.rst ├── conf.py ├── csp.rst ├── guards.rst ├── index.rst ├── mandelbrot.rst └── patterns.rst ├── scripts ├── cspdb ├── csplint └── python-csp ├── setup.cfg ├── setup.py ├── test ├── test_builtins.py ├── test_contexts.py ├── test_forever.py ├── test_tracer.py ├── testcsp.py ├── testpar.py ├── testrep.py ├── testsock.py └── winder_bug │ ├── pi_python_python-csp_multiple_nested_deep.py │ ├── pi_python_python-csp_multiple_nested_shallow.py │ ├── pi_python_python-csp_multiple_separate.py │ ├── pi_python_python-csp_single_nested_deep.py │ ├── pi_python_python-csp_single_nested_shallow.py │ └── pi_python_python-csp_single_separate.py └── tutorial ├── README ├── part01 └── webserver.py ├── part02 └── filecount.py ├── part03 └── mandelbrot.py ├── part04 └── shop.py ├── part07 ├── Oscilloscope.png ├── oscilloscope.py └── traces.py └── part08 ├── Queue.dia └── Queue.png /.hgignore: -------------------------------------------------------------------------------- 1 | TAGS 2 | python_csp.egg-info 3 | build 4 | dist 5 | syntax: glob 6 | *.pyc 7 | examples/mandelbrot/mandelbrot.png 8 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 8 May 2010 2 | Introduced documented readsets and writesets. Added lint-like 3 | static checker to determine whether readsets and writesets are 4 | correctly documented. 5 | 2 May 2010 6 | Introduced CSPServer processes and a @forever decorator to easily 7 | create them. 8 | 1 May 2010 9 | Removed the _process keyword from CSPProcess objects. 10 | Refactored builtin processes to their own library. 11 | Updated documentation in the python-csp shell. 12 | 9 Apr 2010: 13 | Moved documentation to Sphinx. 14 | Added new project logo. 15 | 6 Apr 2010: 16 | Added packages for bulk synchronous processing and reactive 17 | programming. Added directory structure for tutorial examples. 18 | 15 Nov 2009: 19 | Major poisoning bug fixed. Other bug fixes in test scripts and 20 | synchronisation fixed. 21 | 9 Nov 2009: 22 | Added token ring example to benchmark/ directory. Added bsp 23 | package containing barriers. These are automatically imported into 24 | csp modules. 25 | 26 Oct 2009: 26 | Added Boids demo to the examples/ directory. 27 | 28 June 2009: 28 | Added unit testing, in addition to test scripts. Sam Wilson added 29 | Jython version of the CSP library / DSL. 30 | 20 June 2009: 31 | Added threaded version of python-csp. Made main CSP code PEP8 32 | compliant. 33 | 24 March 2009: 34 | Fixed bug in channel poisoning. 35 | 6 January 2009: 36 | Added ALTing to CSP package. Added example parallel programs, 37 | including Mandelbrot fractal generator. 38 | 22 December 2008: 39 | Added initial version of CSP package. Added python-csp 40 | shell. Added .desktop files for GNU/Linux desktop integration. 41 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README ChangeLog LICENSE 2 | include scripts/python-csp 3 | include scripts/cspdb 4 | 5 | recursive-include csp/ *.py 6 | recursive-include exstatic/ *.py 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | RST = rst 5 | BUILD = docs 6 | 7 | # You can set these variables from the command line. 8 | SPHINXOPTS = $(RST) 9 | SPHINXBUILD = sphinx-build 10 | PAPER = a4 11 | 12 | # Internal variables. 13 | PAPEROPT_a4 = -D latex_paper_size=a4 14 | PAPEROPT_letter = -D latex_paper_size=letter 15 | ALLSPHINXOPTS = -d $(BUILD)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) 16 | 17 | .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest 18 | 19 | help: 20 | @echo "Please use \`make ' where is one of" 21 | @echo " html to make standalone HTML files" 22 | @echo " dirhtml to make HTML files named index.html in directories" 23 | @echo " pickle to make pickle files" 24 | @echo " json to make JSON files" 25 | @echo " htmlhelp to make HTML files and a HTML help project" 26 | @echo " qthelp to make HTML files and a qthelp project" 27 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 28 | @echo " changes to make an overview of all changed/added/deprecated items" 29 | @echo " linkcheck to check all external links for integrity" 30 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 31 | 32 | clean: 33 | -rm -rf $(BUILD)/* 34 | 35 | html: 36 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILD)/html 37 | @echo 38 | @echo "Build finished. The HTML pages are in $(BUILD)/html." 39 | 40 | dirhtml: 41 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILD)/dirhtml 42 | @echo 43 | @echo "Build finished. The HTML pages are in $(BUILD)/dirhtml." 44 | 45 | pickle: 46 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILD)/pickle 47 | @echo 48 | @echo "Build finished; now you can process the pickle files." 49 | 50 | json: 51 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILD)/json 52 | @echo 53 | @echo "Build finished; now you can process the JSON files." 54 | 55 | htmlhelp: 56 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILD)/htmlhelp 57 | @echo 58 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 59 | ".hhp project file in $(BUILD)/htmlhelp." 60 | 61 | qthelp: 62 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILD)/qthelp 63 | @echo 64 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 65 | ".qhcp project file in $(BUILD)/qthelp, like this:" 66 | @echo "# qcollectiongenerator $(BUILD)/qthelp/python-csp.qhcp" 67 | @echo "To view the help file:" 68 | @echo "# assistant -collectionFile $(BUILD)/qthelp/python-csp.qhc" 69 | 70 | latex: 71 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILD)/latex 72 | @echo 73 | @echo "Build finished; the LaTeX files are in $(BUILD)/latex." 74 | @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ 75 | "run these through (pdf)latex." 76 | 77 | changes: 78 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILD)/changes 79 | @echo 80 | @echo "The overview file is in $(BUILD)/changes." 81 | 82 | linkcheck: 83 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILD)/linkcheck 84 | @echo 85 | @echo "Link check complete; look for any errors in the above output " \ 86 | "or in $(BUILD)/linkcheck/output.txt." 87 | 88 | doctest: 89 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILD)/doctest 90 | @echo "Testing of doctests in the sources finished, look at the " \ 91 | "results in $(BUILD)/doctest/output.txt." 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | python-csp: Communicating Sequential Processes for Python 2 | ========================================================= 3 | 4 | Copyright (C) Sarah Mount, 2009 under the GNU GPL v2. See the file LICENSE for 5 | more details. 6 | 7 | Installation 8 | ------------ 9 | 10 | python-csp can be installed using PIP (PIP Installs Python): 11 | 12 | $ sudo pip install python-csp 13 | 14 | or from a source distribution using setup.py: 15 | 16 | $ sudo python setup.py install 17 | 18 | 19 | Introduction 20 | ------------ 21 | 22 | python-csp adds C.A.R. (Tony) Hoare's Communicating Sequential Processes to 23 | Python. A brief example: 24 | 25 | ```python 26 | >>> @process 27 | ... def writer(channel, n): 28 | ... for i in xrange(n): 29 | ... channel.write(i) 30 | ... channel.poison() 31 | ... return 32 | ... 33 | >>> @process 34 | ... def reader(channel): 35 | ... while True: 36 | ... print channel.read() 37 | ... 38 | >>> chan = Channel() 39 | >>> Par(reader(chan), writer(chan, 5)).start() 40 | 0 41 | 1 42 | 2 43 | 3 44 | 4 45 | >>> 46 | ``` 47 | 48 | Documentation. 49 | ------------- 50 | 51 | There are several sources of documentation for python-csp: 52 | 53 | * If you are running the python-csp shell, type "info csp" to list available in-shell help. 54 | 55 | * A user guide exists in the `tutorial/` directory of the source. 56 | 57 | * `examples/` contains some larger example programs. 58 | 59 | 60 | Publications. 61 | ------------ 62 | 63 | S. Mount, M. Hammoudeh, S. Wilson, R. Newman (2009) CSP as a Domain-Specific 64 | Language Embedded in Python and Jython. In Proceedings of Communicating Process 65 | Architectures 2009. Eindoven, Netherlands. 1st -- 4th November 2009. Published 66 | IOS Press. 67 | -------------------------------------------------------------------------------- /applications/python-csp.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Python-CSP 3 | Comment=Communicating Sequential Processes in Python 4 | Exec=/usr/bin/python-csp 5 | Icon=/usr/share/pixmaps/python.xpm 6 | Terminal=true 7 | MultipleArgs=false 8 | Type=Application 9 | Categories=Application;Development; 10 | StartupNotify=true 11 | -------------------------------------------------------------------------------- /benchmark/commstime/commstime.mcsp: -------------------------------------------------------------------------------- 1 | PREFIX (in,out) ::= out -> @x.(in -> out -> x) 2 | SUCC (in,out) ::= @x.(in -> out -> x) 3 | DELTA (in,out1,out2) ::= @x.(in -> out1 -> out2 -> x) 4 | CONSUME (in,report) ::= @x.((;[i=1,1000000] in); report -> x) 5 | SYSTEM (report) ::= ((PREFIX (a, b) || DELTA (b, c, d)) || 6 | (SUCC (c, a) || CONSUME (d, report))) \ {a,b,c,d} 7 | 8 | -------------------------------------------------------------------------------- /benchmark/commstime/commstime.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """CSP Commstime benchmark. 3 | 4 | See F.R.M. Barnes (2006) Compiling CSP. In Proceedings of 5 | Communicating Process Architectures 2006. 6 | 7 | Code adapted from PyCSP by John Markus Bjorndalen, available: 8 | http://www.cs.uit.no/~johnm/code/PyCSP/ 9 | 10 | PyCSP - Communicating Sequential Processes for Python. John Markus 11 | Bjorndalen, Brian Vinter, Otto Anshus. CPA 2007, Surrey, UK, July 12 | 8-11, 2007. IOS Press 2007, ISBN 978-1-58603-767-3, Concurrent 13 | Systems Engineering Series (ISSN 1383-7575). 14 | """ 15 | 16 | from csp.csp import * 17 | from csp.builtins import Prefix, Delta2, Succ 18 | 19 | import os 20 | import time 21 | 22 | @process 23 | def Consumer(cin): 24 | """Commstime consumer process 25 | 26 | readset = cin 27 | writeset = 28 | """ 29 | N = 5000 30 | ts = time.time 31 | t1 = ts() 32 | cin.read() 33 | t1 = ts() 34 | for i in range(N): 35 | cin.read() 36 | t2 = ts() 37 | dt = t2-t1 38 | tchan = dt / (4 * N) 39 | print("DT = {0}.\nTime per ch : {1}/(4*{2}) = {3} s = {4} us".format(dt, dt, N, tchan, tchan * 1000000)) 40 | print("consumer done, posioning channel") 41 | cin.poison() 42 | 43 | def CommsTimeBM(): 44 | print('Creating channels now...') 45 | # Create channels 46 | a = Channel() 47 | b = Channel() 48 | c = Channel() 49 | d = Channel() 50 | print("Running commstime test") 51 | Par(Prefix(c, a, prefix_item = 0), # Initiator 52 | Delta2(a, b, d), # Forwarding to two 53 | Succ(b, c), # Feeding back to prefix 54 | Consumer(d)).start() # Timing process 55 | print('Finished run...') 56 | 57 | 58 | if __name__ == '__main__': 59 | N_BM = 10 60 | for i in range(N_BM): 61 | print("----------- run {0}/{1} -------------".format(i+1, N_BM)) 62 | CommsTimeBM() 63 | print("------- Commstime finished ---------") 64 | -------------------------------------------------------------------------------- /benchmark/tokenring/plot_results.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Plotting results of variable ring buffer experiment. 5 | 6 | Copyright (C) Sarah Mount, 2009. 7 | 8 | This program is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU General Public License 10 | as published by the Free Software Foundation; either version 2 11 | of the License, or (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have rceeived a copy of the GNU General Public License 19 | along with this program; if not, write to the Free Software 20 | """ 21 | 22 | from scipy import * 23 | from pylab import * 24 | 25 | __author__ = 'Sarah Mount ' 26 | __date__ = 'November 2009' 27 | 28 | FILENAME = 'token_ring.png' 29 | 30 | subplots_adjust(hspace=0.4, wspace=0.6) 31 | 32 | # Num of nodes in token ring 33 | t = array([2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]) 34 | 35 | 36 | yvals = {1:{'procs':array([350.057995, 37 | 314.430736, 157.215372, 78.607687, 39.303844, 38 | 19.651922, 9.825962, 4.912981, 2.456491, None, None]), 39 | 'threads':array([314.430851, 157.215429, 78.607716, 39.303859, 40 | 19.651930, 9.825965, 4.912983, 2.456492, None, None]), 41 | 'jython':array([314.431448, 157.215729, 78.607867, 39.303935, 42 | 19.651969, 9.825985, 4.912993, 2.456502, 1.228249, 0.614125])} 43 | } 44 | 45 | 46 | subplot(111) 47 | title('Variable sized ring buffer \nwith one token') 48 | plot(t, yvals[1]['procs'], 'g^-') 49 | plot(t, yvals[1]['threads'], 'k*--') 50 | plot(t, yvals[1]['jython'], 'rx-.') 51 | 52 | legend(['Processes reified as OS processes', 53 | 'Processes reified as OS threads', 54 | 'Processes reified as Java threads'], 55 | loc='upper left') 56 | 57 | xlabel('Number of nodes in token ring') 58 | ylabel(r'Time $(\mu{}s)$') 59 | 60 | ### 61 | 62 | #subplot(222) 63 | #title('16 node ring buffer \nwith three tokens') 64 | #plot(t, yvals[1]['procs'], 'g^-') 65 | #plot(t, yvals[1]['threads'], 'k*--') 66 | #plot(t, yvals[1]['jython'], 'rx-.') 67 | 68 | #legend(['Processes reified as OS processes', 69 | # 'Processes reified as OS threads', 70 | # 'Processes reified as Java threads'], 71 | # loc='upper left') 72 | 73 | #xlabel('Number of nodes in token ring') 74 | #ylabel(r'Time $(\mu{}s)$') 75 | 76 | ### 77 | 78 | #subplot(223) 79 | #title('32 node ring buffer \nwith three tokens') 80 | #plot(t, yvals[1]['procs'], 'g^-') 81 | #plot(t, yvals[1]['threads'], 'k*--') 82 | #plot(t, yvals[1]['jython'], 'rx-.') 83 | 84 | #legend(['Processes reified as OS processes', 85 | # 'Processes reified as OS threads', 86 | # 'Processes reified as Java threads'], 87 | # loc='upper left') 88 | 89 | #xlabel('Number of nodes in token ring') 90 | #ylabel(r'Time $(\mu{}s)$') 91 | 92 | ### 93 | 94 | #subplot(224) 95 | #title('64 node ring buffer \nwith three tokens') 96 | #plot(t, yvals[1]['procs'], 'g^-') 97 | #plot(t, yvals[1]['threads'], 'k*--') 98 | #plot(t, yvals[1]['jython'], 'rx-.') 99 | 100 | #legend(['Processes reified as OS processes', 101 | # 'Processes reified as OS threads', 102 | # 'Processes reified as Java threads'], 103 | # loc='upper left') 104 | 105 | #xlabel('Number of nodes in token ring') 106 | #ylabel(r'Time $(\mu{}s)$') 107 | 108 | ### 109 | 110 | grid(True) 111 | savefig(FILENAME, format='png') 112 | show() 113 | -------------------------------------------------------------------------------- /benchmark/tokenring/tokenring.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Benchmark based on variable sized ring buffer. 5 | See also PyCSP papers in CPA2009 proceedings. 6 | 7 | Usage: tokenring-processes.py [options] 8 | 9 | Options: 10 | -h, --help show this help message and exit 11 | -t TOKENS, --tokens=TOKENS 12 | Number of tokens in token ring 13 | -n NODES, --nodes=NODES 14 | Number of nodes in token ring 15 | -x, --experiment Experimental mode. Run 10 token rings with nodes 2^1 16 | to 2^10 and print results 17 | 18 | Copyright (C) Sarah Mount, 2009. 19 | 20 | This program is free software; you can redistribute it and/or 21 | modify it under the terms of the GNU General Public License 22 | as published by the Free Software Foundation; either version 2 23 | of the License, or (at your option) any later version. 24 | 25 | This program is distributed in the hope that it will be useful, 26 | but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 | GNU General Public License for more details. 29 | 30 | You should have rceeived a copy of the GNU General Public License 31 | along with this program; if not, write to the Free Software 32 | 33 | """ 34 | 35 | __author__ = 'Sarah Mount ' 36 | __date__ = 'November 2009' 37 | 38 | from csp.csp import * 39 | from csp.patterns import TokenRing 40 | 41 | 42 | TRIALS = 10000 43 | 44 | 45 | @process 46 | def ringproc(index=0, numnodes=64, tokens=1, inchan=None, outchan=None): 47 | """ 48 | readset = inchan 49 | writeset = outchan 50 | """ 51 | if tokens == 1 and index == 0: 52 | token = 1 53 | outchan.write(token) 54 | for i in range(TRIALS): 55 | token = inchan.read() 56 | token += 1 57 | outchan.write(token) 58 | # Avoid deadlock. 59 | if index == 1: 60 | inchan.read() 61 | 62 | 63 | if __name__ == '__main__': 64 | from optparse import OptionParser 65 | 66 | parser = OptionParser() 67 | 68 | parser.add_option('-t', '--tokens', dest='tokens', 69 | action='store', type="int", 70 | default=1, 71 | help='Number of tokens in token ring') 72 | parser.add_option('-n', '--nodes', dest='nodes', 73 | action='store', type="int", 74 | default=64, 75 | help='Number of nodes in token ring') 76 | parser.add_option('-x', '--experiment', dest='exp', 77 | action='store_true', default=False, 78 | help=('Experimental mode. Run 10 token rings with nodes ' 79 | + '2^1 to 2^10 and print results')) 80 | 81 | (options, args) = parser.parse_args() 82 | 83 | if options.exp: 84 | print('All times measured in microseconds.') 85 | for size in range(2, 10): 86 | try: 87 | print('Token ring with {0} nodes.'.format(size)) 88 | starttime = time.time() 89 | TokenRing(ringproc, 2 ** size, numtoks=options.tokens).start() 90 | elapsed = time.time() - starttime 91 | mu = elapsed * 1000000 / float((TRIALS * (2 ** size))) 92 | print('{0}ms'.format(mu)) 93 | except: 94 | continue 95 | else: 96 | import time 97 | print 'Token ring with {0} nodes and {1} token(s).'.format(options.nodes, options.tokens) 98 | starttime = time.time() 99 | TokenRing(ringproc, options.nodes, numtoks=options.tokens).start() 100 | elapsed = time.time() - starttime 101 | mu = elapsed * 1000000 / float((TRIALS * (2 ** options.nodes))) 102 | print '{0}ms'.format(mu) 103 | -------------------------------------------------------------------------------- /csp/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/csp/__init__.py -------------------------------------------------------------------------------- /csp/cchannels/CChannel.py: -------------------------------------------------------------------------------- 1 | import Channel as chnl 2 | import cPickle 3 | import uuid 4 | from csp.guards import Guard 5 | 6 | class CChannel(Guard): 7 | 8 | def __init__(self): 9 | p = uuid.uuid4().int & 0xffffff 10 | av = uuid.uuid4().int & 0xffffff 11 | tak = uuid.uuid4().int & 0xffffff 12 | shm = uuid.uuid4().int & 0xffffff 13 | 14 | self.channel = chnl.getChannel(p,av,tak,shm) 15 | self.name = uuid.uuid1() 16 | return 17 | 18 | def __del__(self): 19 | chnl.removeChannel(self.channel) 20 | self.channel = None 21 | return 22 | 23 | def put(self,item): 24 | a = cPickle.dumps(item) 25 | chnl.put(self.channel,a); 26 | return 27 | 28 | def get(self): 29 | chnl.get(self.channel,ret) 30 | item = cPickle.loads(ret) 31 | print(item) 32 | return item 33 | 34 | def is_selectable(self): 35 | #print ( "is_selectable has been called" ) 36 | a = chnl.is_selectable(self.channel) 37 | #print ( "is_selectable got ", a ) 38 | if a == 1: 39 | return True 40 | else: 41 | return False; 42 | 43 | def write(self,item): 44 | a = cPickle.dumps(item) 45 | chnl._write(self.channel,a,len(a)); 46 | return 47 | 48 | def read(self): 49 | print("invoked read") 50 | ret = chnl._read(self.channel) 51 | print(ret) 52 | item = cPickle.loads(ret) 53 | print(item) 54 | return item 55 | 56 | def enable(self): 57 | #print("ENABLED CALLED") 58 | chnl.enable(self.channel) 59 | #print("returning from enable") 60 | return 61 | 62 | def disable(self): 63 | chnl.disable(self.channel) 64 | return 65 | 66 | def select(self): 67 | #print("calling _select") 68 | ret = chnl._select(self.channel) 69 | item = cPickle.loads(ret) 70 | print(item) 71 | return item 72 | 73 | def poison(self): 74 | chnl.poison(self.channel); 75 | return 76 | 77 | def getStatus(self): 78 | chnl.getStatus(self.channel) 79 | return 80 | 81 | def checkpoison(self): 82 | chnl.checkpoison() 83 | return 84 | -------------------------------------------------------------------------------- /csp/cchannels/Channel.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #define false 0 12 | #define true (!false) 13 | 14 | typedef struct{ 15 | pthread_mutex_t r_lock; 16 | pthread_mutex_t w_lock; 17 | key_t p_lock_key; 18 | int p_lock; 19 | key_t available_key; 20 | int available; 21 | key_t taken_key; 22 | int taken; 23 | unsigned int is_alting; 24 | unsigned int is_selectable; 25 | unsigned int has_selected; 26 | unsigned int poisoned; 27 | char* item; 28 | key_t sh_mem_name; 29 | //char *shm; 30 | int shmid; 31 | int len; 32 | 33 | }Channel; 34 | 35 | union semun { 36 | int val; 37 | struct semid_ds *buf; 38 | ushort *array; 39 | }; 40 | -------------------------------------------------------------------------------- /csp/cchannels/Channel.i: -------------------------------------------------------------------------------- 1 | /* Channel.i */ 2 | %module Channel 3 | %{ 4 | #include 5 | #include 6 | #include "Channel.h" 7 | 8 | extern int sq(int i); 9 | extern void getStatus(Channel *c); 10 | extern Channel getChannel(long int p,long int av,long int tak,long int shm); 11 | extern void removeChannel(Channel *c); 12 | extern void checkpoison(Channel *c); 13 | extern void put(Channel *c, char *ptr, int len); 14 | extern void get(Channel *c, char *ptr); 15 | extern int is_selectable(Channel *c); 16 | extern void _write(Channel *c, char *ptr,int len); 17 | extern char *_read(Channel *c); 18 | extern void enable(Channel *c); 19 | extern void disable(Channel *c); 20 | extern char *_select(Channel *c); 21 | extern void poison(Channel *c); 22 | 23 | %} 24 | 25 | 26 | extern int sq(int i); 27 | extern void getStatus(Channel *c); 28 | extern Channel getChannel(long int p,long int av,long int tak,long int shm); 29 | extern void removeChannel(Channel *c); 30 | extern void checkpoison(Channel *c); 31 | extern void put(Channel *c, char *ptr, int len); 32 | extern void get(Channel *c, char *ptr); 33 | extern int is_selectable(Channel *c); 34 | extern void _write(Channel *c, char *ptr,int len); 35 | extern char *_read(Channel *c); 36 | extern void enable(Channel *c); 37 | extern void disable(Channel *c); 38 | extern char *_select(Channel *c); 39 | extern void poison(Channel *c); 40 | -------------------------------------------------------------------------------- /csp/cchannels/Channel.py: -------------------------------------------------------------------------------- 1 | # This file was automatically generated by SWIG (http://www.swig.org). 2 | # Version 1.3.40 3 | # 4 | # Do not make changes to this file unless you know what you are doing--modify 5 | # the SWIG interface file instead. 6 | # This file is compatible with both classic and new-style classes. 7 | 8 | from sys import version_info 9 | if version_info >= (2,6,0): 10 | def swig_import_helper(): 11 | from os.path import dirname 12 | import imp 13 | fp = None 14 | try: 15 | fp, pathname, description = imp.find_module('_Channel', [dirname(__file__)]) 16 | except ImportError: 17 | import _Channel 18 | return _Channel 19 | if fp is not None: 20 | try: 21 | _mod = imp.load_module('_Channel', fp, pathname, description) 22 | finally: 23 | fp.close() 24 | return _mod 25 | _Channel = swig_import_helper() 26 | del swig_import_helper 27 | else: 28 | import _Channel 29 | del version_info 30 | try: 31 | _swig_property = property 32 | except NameError: 33 | pass # Python < 2.2 doesn't have 'property'. 34 | def _swig_setattr_nondynamic(self,class_type,name,value,static=1): 35 | if (name == "thisown"): return self.this.own(value) 36 | if (name == "this"): 37 | if type(value).__name__ == 'SwigPyObject': 38 | self.__dict__[name] = value 39 | return 40 | method = class_type.__swig_setmethods__.get(name,None) 41 | if method: return method(self,value) 42 | if (not static) or hasattr(self,name): 43 | self.__dict__[name] = value 44 | else: 45 | raise AttributeError("You cannot add attributes to {0}".format(self)) 46 | 47 | def _swig_setattr(self,class_type,name,value): 48 | return _swig_setattr_nondynamic(self,class_type,name,value,0) 49 | 50 | def _swig_getattr(self,class_type,name): 51 | if (name == "thisown"): return self.this.own() 52 | method = class_type.__swig_getmethods__.get(name,None) 53 | if method: return method(self) 54 | raise AttributeError(name) 55 | 56 | def _swig_repr(self): 57 | try: strthis = "proxy of " + self.this.__repr__() 58 | except: strthis = "" 59 | return "<{0}.{1}; {2} >".format(self.__class__.__module__, self.__class__.__name__, strthis) 60 | 61 | try: 62 | _object = object 63 | _newclass = 1 64 | except AttributeError: 65 | class _object : pass 66 | _newclass = 0 67 | 68 | 69 | 70 | def sq(*args): 71 | return _Channel.sq(*args) 72 | sq = _Channel.sq 73 | 74 | def getStatus(*args): 75 | return _Channel.getStatus(*args) 76 | getStatus = _Channel.getStatus 77 | 78 | def getChannel(*args): 79 | return _Channel.getChannel(*args) 80 | getChannel = _Channel.getChannel 81 | 82 | def removeChannel(*args): 83 | return _Channel.removeChannel(*args) 84 | removeChannel = _Channel.removeChannel 85 | 86 | def checkpoison(*args): 87 | return _Channel.checkpoison(*args) 88 | checkpoison = _Channel.checkpoison 89 | 90 | def put(*args): 91 | return _Channel.put(*args) 92 | put = _Channel.put 93 | 94 | def get(*args): 95 | return _Channel.get(*args) 96 | get = _Channel.get 97 | 98 | def is_selectable(*args): 99 | return _Channel.is_selectable(*args) 100 | is_selectable = _Channel.is_selectable 101 | 102 | def _write(*args): 103 | return _Channel._write(*args) 104 | _write = _Channel._write 105 | 106 | def _read(*args): 107 | return _Channel._read(*args) 108 | _read = _Channel._read 109 | 110 | def enable(*args): 111 | return _Channel.enable(*args) 112 | enable = _Channel.enable 113 | 114 | def disable(*args): 115 | return _Channel.disable(*args) 116 | disable = _Channel.disable 117 | 118 | def _select(*args): 119 | return _Channel._select(*args) 120 | _select = _Channel._select 121 | 122 | def poison(*args): 123 | return _Channel.poison(*args) 124 | poison = _Channel.poison 125 | 126 | 127 | -------------------------------------------------------------------------------- /csp/cchannels/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Generic Makefile for C modules, wrapped in Python by SWIG. 3 | # 4 | # Chanege the variable INTERFACE to your interface files and if you're 5 | # not using a sensible UNIX style platform then change the executables 6 | # and so on too. 7 | # 8 | 9 | 10 | INTERFACE=Channel.i 11 | 12 | PREFIX=/usr 13 | RM=rm 14 | SWIG=swig 15 | SWIGOPT= 16 | CC=gcc 17 | CFLAGS=-O3 -Wall -c 18 | LDSHARED=ld 19 | LDFLAGS=-shared 20 | INCLUDES= 21 | LIBS= 22 | SO=.so 23 | 24 | SRCS=$(wildcard *.c) 25 | ISRCS=$(INTERFACE:.i=_wrap.c) 26 | OBJS=${SRCS:.c=.o} 27 | IOBJS=$(ISRCS:.c=.o) 28 | 29 | TARGET=$(addprefix _, $(INTERFACE:.i=$(SO))) 30 | 31 | # Make sure these locate your Python installation 32 | PYTHON_INCLUDE=-I$(PREFIX)/include/python2.6 33 | 34 | # Clear out old suffices. 35 | .SUFFIXES: 36 | 37 | # List suffices that we are using. 38 | .SUFFIXES: .i .o .c 39 | 40 | .PHONY: clean 41 | 42 | all: $(SRCS) 43 | $(SWIG) -python $(SWIGOPT) $(INTERFACE) 44 | $(CC) -c $(CCSHARED) $(CFLAGS) $(ISRCS) $(SRCS) $(INCLUDE) $(PYTHON_INCLUDE) 45 | $(LDSHARED) $(LDFLAGS) $(OBJS) $(IOBJS) $(LIBS) -o $(TARGET) 46 | @echo Built all files and created $(TARGET) 47 | 48 | clean : 49 | -$(RM) -f *.pyc *.so *.o *_wrap.c *~ 50 | 51 | depend : $(SRCS) 52 | makedepend $(INCLUDES) $^ 53 | 54 | # DO NOT DELETE THIS LINE 55 | -------------------------------------------------------------------------------- /csp/cchannels/tests/commstime.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """CSP Commstime benchmark. 3 | 4 | See F.R.M. Barnes (2006) Compiling CSP. In Proceedings of 5 | Communicating Process Architectures 2006. 6 | 7 | Code adapted from PyCSP by John Markus Bjorndalen, available: 8 | http://www.cs.uit.no/~johnm/code/PyCSP/ 9 | 10 | PyCSP - Communicating Sequential Processes for Python. John Markus 11 | Bjorndalen, Brian Vinter, Otto Anshus. CPA 2007, Surrey, UK, July 12 | 8-11, 2007. IOS Press 2007, ISBN 978-1-58603-767-3, Concurrent 13 | Systems Engineering Series (ISSN 1383-7575). 14 | """ 15 | 16 | from csp.csp import Par, process #, Channel 17 | from csp.builtins import Prefix, Delta2, Succ 18 | 19 | import sys 20 | sys.path.append('../') 21 | from CChannel import CChannel as Channel 22 | del sys 23 | 24 | import time 25 | 26 | 27 | @process 28 | def Consumer(cin): 29 | """Commstime consumer process 30 | 31 | readset = cin 32 | writeset = 33 | """ 34 | N = 5000 35 | ts = time.time 36 | t1 = ts() 37 | cin.read() 38 | t1 = ts() 39 | for i in range(N): 40 | cin.read() 41 | t2 = ts() 42 | dt = t2-t1 43 | tchan = dt / (4 * N) 44 | print("DT = {0}\nTime per ch : {1}/(4*{2}) = {3} s = {4} us".format(dt, dt, N, tchan, tchan * 1000000)) 45 | print("consumer done, poisoning channel") 46 | cin.poison() 47 | 48 | def CommsTimeBM(): 49 | print('Creating channels now...') 50 | # Create channels 51 | a = Channel() 52 | b = Channel() 53 | c = Channel() 54 | d = Channel() 55 | print("Running commstime test") 56 | Par(Prefix(c, a, prefix_item=0), # Initiator 57 | Delta2(a, b, d), # Forwarding to two 58 | Succ(b, c), # Feeding back to prefix 59 | Consumer(d)).start() # Timing process 60 | print('Finished run...') 61 | 62 | 63 | if __name__ == '__main__': 64 | N_BM = 10 65 | for i in xrange(N_BM): 66 | print("----------- run {0}/{1} -------------".format(i+1, N_BM)) 67 | CommsTimeBM() 68 | print("------- Commstime finished ---------") 69 | -------------------------------------------------------------------------------- /csp/cchannels/tests/fulladder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """Python CSP full adder. 4 | 5 | Based on code from PyCSP - Communicating Sequential Processes for 6 | Python. John Markus Bjorndalen, Brian Vinter, Otto Anshus. CPA 2007, 7 | Surrey, UK, July 8-11, 2007. IOS Press 2007, ISBN 978-1-58603-767-3, 8 | Concurrent Systems Engineering Series (ISSN 1383-7575). 9 | 10 | Copyright (C) Sarah Mount, 2009. 11 | 12 | This program is free software; you can redistribute it and/or 13 | modify it under the terms of the GNU General Public License 14 | as published by the Free Software Foundation; either version 2 15 | of the License, or (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU General Public License for more details. 21 | 22 | You should have rceeived a copy of the GNU General Public License 23 | along with this program; if not, write to the Free Software 24 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 25 | """ 26 | 27 | __author__ = 'Sarah Mount ' 28 | __date__ = 'December 2008' 29 | 30 | 31 | from csp.csp import Par, process 32 | 33 | import sys 34 | sys.path.append('../') 35 | from CChannel import CChannel as Channel 36 | del sys 37 | 38 | from csp.builtins import * 39 | 40 | 41 | @process 42 | def Bool1(cout): 43 | """ 44 | readset = 45 | writeset = cout 46 | """ 47 | while True: 48 | cout.write(1) 49 | cout.write(1) 50 | cout.write(0) 51 | cout.write(0) 52 | return 53 | 54 | @process 55 | def Bool2(cout): 56 | """ 57 | readset = 58 | writeset = cout 59 | """ 60 | while True: 61 | cout.write(1) 62 | cout.write(0) 63 | cout.write(1) 64 | cout.write(0) 65 | return 66 | 67 | def fulladder(A_in, B_in, C_in, Sum_in, Carry_in): 68 | """Full adder implementation. 69 | 70 | Based on Bjorndalen, Vinter & Anshus (2007). 71 | """ 72 | Aa = Channel() 73 | Ab = Channel() 74 | Ba = Channel() 75 | Bb = Channel() 76 | Ca = Channel() 77 | Cb = Channel() 78 | i1 = Channel() 79 | i1a = Channel() 80 | i1b = Channel() 81 | i2 = Channel() 82 | i3 = Channel() 83 | 84 | return Par(Delta2(A_in, Aa, Ab), 85 | Delta2(B_in, Ba, Bb), 86 | Delta2(C_in, Ca, Cb), 87 | Delta2(i1, i1a, i1b), 88 | Xor(Aa, Ba, i1), 89 | Xor(i1a, Ca, Sum_in), 90 | And(Ab, Bb, i2), 91 | And(i1b, Cb, i3), 92 | Or(i2, i3, Carry_in)) 93 | 94 | if __name__ == '__main__': 95 | print('\nFull adder implemented in Python CSP\n') 96 | # Inputs to full adder 97 | A = Channel() 98 | B = Channel() 99 | Cin = Channel() 100 | # Outputs of full adder 101 | Carry = Channel() 102 | Sum = Channel() 103 | # Channels for printing to STDOUT 104 | PCarry = Channel() 105 | PSum = Channel() 106 | # Create and start adder 107 | adder = Par(Bool1(A), 108 | Bool2(B), 109 | Zeroes(Cin), 110 | fulladder(A, B, Cin, Sum, Carry), 111 | Sign(Carry, PCarry, 'Carry: '), 112 | Printer(PCarry), 113 | Sign(Sum, PSum, 'Sum: '), 114 | Printer(PSum)) 115 | adder.start() 116 | 117 | -------------------------------------------------------------------------------- /csp/cchannels/tests/patterns.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """Design pattern support for python-csp. 4 | 5 | Copyright (C) Sarah Mount, 2010. 6 | 7 | This program is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU General Public License 9 | as published by the Free Software Foundation; either version 2 10 | of the License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A ParTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have rceeived a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 20 | """ 21 | 22 | 23 | __author__ = 'Sarah Mount ' 24 | __date__ = 'May 2010' 25 | 26 | 27 | from csp.csp import Par 28 | 29 | from CChannel import CChannel as Channel 30 | 31 | __all__ = ['TokenRing'] 32 | 33 | class TokenRing(Par): 34 | def __init__(self, func, size, numtoks=1): 35 | self.chans = [Channel() for channel in xrange(size)] 36 | self.procs = [func(index=i, 37 | tokens=numtoks, 38 | numnodes=size, 39 | inchan=self.chans[i-1], 40 | outchan=self.chans[i]) for i in xrange(size)] 41 | super(TokenRing, self).__init__(*self.procs) 42 | return 43 | 44 | -------------------------------------------------------------------------------- /csp/cchannels/tests/simple.py: -------------------------------------------------------------------------------- 1 | from csp.csp import Par, process 2 | 3 | import sys 4 | sys.path.append('../') 5 | from CChannel import CChannel as Channel 6 | del sys 7 | 8 | 9 | @process 10 | def out(cout): 11 | i = 0 12 | while True: 13 | print ( "PYTHON: About to write " + str ( i ) + "\n" ) 14 | cout.write(i) 15 | print ( "PYTHON: Have written " + str ( i ) + "\n" ) 16 | i = i +1 17 | 18 | 19 | @process 20 | def inn(cin): 21 | while True: 22 | print ( "PYTHON: About to read \n" ) 23 | a = cin.read() 24 | print ( "PYTHON: Read "+ str ( a ) + "\n" ) 25 | 26 | 27 | if __name__ == '__main__': 28 | 29 | c = Channel() 30 | p = Par(out(c),inn(c)) 31 | p.start() 32 | -------------------------------------------------------------------------------- /csp/cchannels/tests/tokenring.py: -------------------------------------------------------------------------------- 1 | #! /bin/env python2.6 2 | 3 | """ 4 | Benchmark based on variable sized ring buffer. 5 | See also PyCSP papers in CPA2009 proceedings. 6 | 7 | Usage: tokenring-processes.py [options] 8 | 9 | Options: 10 | -h, --help show this help message and exit 11 | -t TOKENS, --tokens=TOKENS 12 | Number of tokens in token ring 13 | -n NODES, --nodes=NODES 14 | Number of nodes in token ring 15 | -x, --experiment Experimental mode. Run 10 token rings with nodes 2^1 16 | to 2^10 and print results 17 | 18 | Copyright (C) Sarah Mount, 2009. 19 | 20 | This program is free software; you can redistribute it and/or 21 | modify it under the terms of the GNU General Public License 22 | as published by the Free Software Foundation; either version 2 23 | of the License, or (at your option) any later version. 24 | 25 | This program is distributed in the hope that it will be useful, 26 | but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 | GNU General Public License for more details. 29 | 30 | You should have rceeived a copy of the GNU General Public License 31 | along with this program; if not, write to the Free Software 32 | 33 | """ 34 | 35 | __author__ = 'Sarah Mount ' 36 | __date__ = 'November 2009' 37 | 38 | from csp.csp import process, Par 39 | from patterns import TokenRing 40 | 41 | import sys 42 | sys.path.append('../') 43 | from CChannel import CChannel as Channel 44 | del sys 45 | 46 | import time 47 | 48 | TRIALS = 10000 49 | 50 | 51 | @process 52 | def ringproc(index=0, numnodes=64, tokens=1, inchan=None, outchan=None): 53 | """ 54 | readset = inchan 55 | writeset = outchan 56 | """ 57 | if tokens == 1 and index == 0: 58 | token = 1 59 | outchan.write(token) 60 | for i in xrange(TRIALS): 61 | outchan.write(inchan.read()) 62 | # Avoid deadlock. 63 | if index == 1: 64 | inchan.read() 65 | 66 | 67 | if __name__ == '__main__': 68 | from optparse import OptionParser 69 | 70 | parser = OptionParser() 71 | 72 | parser.add_option('-t', '--tokens', dest='tokens', 73 | action='store', type="int", 74 | default=1, 75 | help='Number of tokens in token ring') 76 | parser.add_option('-n', '--nodes', dest='nodes', 77 | action='store', type="int", 78 | default=64, 79 | help='Number of nodes in token ring') 80 | parser.add_option('-x', '--experiment', dest='exp', 81 | action='store_true', default=False, 82 | help=('Experimental mode. Run 10 token rings with nodes ' 83 | + '2^1 to 2^10 and print results')) 84 | 85 | (options, args) = parser.parse_args() 86 | 87 | if options.exp: 88 | print('All times measured in microseconds.') 89 | for size in xrange(2, 50): 90 | try: 91 | print('Token ring with {0} nodes.'.format(2 ** size)) 92 | starttime = time.time() 93 | TokenRing(ringproc, 2 ** size, numtoks=options.tokens).start() 94 | elapsed = time.time() - starttime 95 | mu = elapsed * 1000000 / float((TRIALS * (2 ** size))) 96 | print('{0}ms'.format(mu)) 97 | except: 98 | continue 99 | else: 100 | TokenRing(ringproc, options.nodes, numtoks=options.tokens).start() 101 | -------------------------------------------------------------------------------- /csp/csp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | If you want to use the python-csp library then this is the file to 5 | import. It attempts to match the best possible implementation of CSP 6 | for your platform. 7 | 8 | If you wish to choose to use the multiprocess (multicore) or threaded 9 | version of the libraries explicitly then set an environment variable 10 | in your opertaing system called "CSP". This should be either set to 11 | "PROCESSES" or "THREADS" depending on what you want to use. 12 | 13 | 14 | Copyright (C) Sarah Mount, 2010. 15 | 16 | This program is free software; you can redistribute it and/or 17 | modify it under the terms of the GNU General Public License 18 | as published by the Free Software Foundation; either version 2 19 | of the License, or (at your option) any later version. 20 | 21 | This program is distributed in the hope that it will be useful, 22 | but WITHOUT ANY WARRANTY; without even the implied warranty of 23 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 | GNU General Public License for more details. 25 | 26 | You should have received a copy of the GNU General Public License 27 | along with this program; if not, write to the Free Software 28 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 29 | """ 30 | 31 | from __future__ import absolute_import 32 | 33 | from contextlib import contextmanager 34 | 35 | import os 36 | import sys 37 | 38 | 39 | ### Names exported by this module 40 | __all__ = ['set_debug', 'CSPProcess', 'CSPServer', 'Alt', 41 | 'Par', 'Seq', 'Guard', 'Channel', 'FileChannel', 42 | 'process', 'forever', 'Skip', 'CSP_IMPLEMENTATION'] 43 | 44 | 45 | __author__ = 'Sarah Mount ' 46 | __date__ = 'July 2010' 47 | 48 | 49 | # FIXME: Simplify this logic. See the thread on "Importing different 50 | # implementations of the library" on the mailing list. 51 | 52 | # If multiprocessing is not available then import threads. 53 | major, minor = sys.version_info[:2] 54 | if (major, minor) < (2, 6): 55 | try: 56 | from .os_thread import * 57 | except: 58 | from .os_process import * 59 | 60 | # If multiprocessing is likely to be available then let the user 61 | # choose which version of the implementation they wish to use. 62 | elif 'CSP' in os.environ: 63 | if os.environ['CSP'].upper() == 'THREADS': 64 | from .os_thread import * 65 | else: 66 | from .os_process import * 67 | 68 | # If no useful information is available then try to import the 69 | # multiprocessing version of the code else catch the resulting 70 | # exception and use the threaded version. 71 | else: 72 | try: 73 | from .os_process import * 74 | except: 75 | from .os_thread import * 76 | 77 | 78 | 79 | class CSP(object): 80 | """Context manager to execute Python functions sequentially or in 81 | parallel, similarly to OCCAM syntax: 82 | 83 | csp = CSP() 84 | with csp.seq: 85 | csp.process(myfunc1, arg1, arg2) 86 | with csp.par: 87 | csp.process(myfunc2, arg1, arg2) 88 | csp.process(myfunc3, arg1, arg2) 89 | csp.start() 90 | # myfunc3 and myfunc4 will be executed in parallel. 91 | # myfunc1 and myfunc2 will be executed sequentially, 92 | # and myfunc3 and myfunc4 will be executed after 93 | # myfunc2 has returned. 94 | """ 95 | 96 | def __init__(self): 97 | self.processes = [] 98 | 99 | @contextmanager 100 | def par(self): 101 | """Context manager to execute functions in parallel. 102 | 103 | csp = CSP() 104 | with csp.seq: 105 | csp.process(myfunc1, arg1, arg2) 106 | csp.process(myfunc2, arg1, arg2) 107 | csp.start() 108 | # myfunc1 and myfunc2 will be executed in parallel. 109 | """ 110 | self.processes.append([]) 111 | yield 112 | proc_list = self.processes.pop() 113 | par = Par(*proc_list) 114 | if len(self.processes) > 0: 115 | self.processes[-1].append(par) 116 | else: 117 | self.processes.append(par) 118 | return 119 | 120 | @contextmanager 121 | def seq(self): 122 | """Context manager to execute functions in sequence. 123 | 124 | csp = CSP() 125 | with csp.seq: 126 | csp.process(myfunc1, arg1, arg2) 127 | csp.process(myfunc2, arg1, arg2) 128 | csp.start() 129 | # myfunc1 and myfunc2 will be executed sequentially. 130 | """ 131 | self.processes.append([]) 132 | yield 133 | proc_list = self.processes.pop() 134 | seq = Seq(*proc_list) 135 | if len(self.processes) > 0: 136 | self.processes[-1].append(seq) 137 | else: 138 | self.processes.append(seq) 139 | return 140 | 141 | def process(self, func, *args, **kwargs): 142 | """Add a process to the current list of proceses. 143 | 144 | Likely, this will be called from inside a context manager, e.g.: 145 | 146 | csp = CSP() 147 | with csp.par: 148 | csp.process(myfunc1, arg1, arg2) 149 | csp.process(myfunc2, arg1, arg2) 150 | csp.start() 151 | """ 152 | self.processes[-1].append(CSPProcess(func, *args, **kwargs)) 153 | return 154 | 155 | def start(self): 156 | """Start all processes in self.processes (in parallel) and run 157 | to completion. 158 | """ 159 | if len(self.processes) == 0: 160 | return 161 | elif len(self.processes) == 1: 162 | self.processes[0].start() 163 | else: 164 | Par(*self.processes).start() 165 | return 166 | -------------------------------------------------------------------------------- /csp/dsp.py: -------------------------------------------------------------------------------- 1 | #!/bin/env python 2 | 3 | """ 4 | Digital signal processing for python-csp. 5 | 6 | Copyright (C) Sarah Mount, 2009. 7 | 8 | This program is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU General Public License 10 | as published by the Free Software Foundation; either version 2 11 | of the License, or (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have rceeived a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | 22 | from __future__ import absolute_import 23 | 24 | from .csp import * 25 | 26 | import math 27 | 28 | # TODO: Use numpy for more sophisticated processes. 29 | 30 | ACCEL_DUE_TO_GRAVITY = 9.80665 31 | 32 | 33 | @forever 34 | def Zip(outchan, inchannels): 35 | """Take data from a number of input channels, and write that 36 | data as a single list to L{outchan}. 37 | """ 38 | while True: 39 | outchan.write([chan.read() for chan in inchannels]) 40 | yield 41 | 42 | 43 | @forever 44 | def Unzip(inchan, outchans): 45 | """Continuously read tuples of data from a single input channel and send 46 | each datum out down its own output channel. 47 | """ 48 | while True: 49 | data = inchan.read() 50 | for i in range(data): 51 | outchans[i].write(data[i]) 52 | yield 53 | 54 | 55 | @forever 56 | def Sin(inchan, outchan): 57 | while True: 58 | outchan.write(math.sin(inchan.read())) 59 | yield 60 | 61 | 62 | @forever 63 | def Cos(inchan, outchan): 64 | while True: 65 | outchan.write(math.cos(inchan.read())) 66 | yield 67 | 68 | 69 | @forever 70 | def Tan(inchan, outchan): 71 | while True: 72 | outchan.write(math.tan(inchan.read())) 73 | yield 74 | 75 | 76 | @forever 77 | def GenerateFloats(outchan): 78 | counter = 0 79 | increment = 0.1 80 | while True: 81 | outchan.write(counter * increment) 82 | counter += 1 83 | yield 84 | 85 | 86 | @forever 87 | def Magnitude(inchan, outchan): 88 | while True: 89 | acceldata = inchan.read() 90 | mag = 0.0 91 | for axis in acceldata: mag += axis ** 2 92 | outchan.write(math.sqrt(mag)) 93 | yield 94 | 95 | 96 | @forever 97 | def Difference(inchan, outchan, window=1): 98 | cache = 0.0 99 | while True: 100 | acceldata = inchan.read() 101 | try: 102 | outchan.write(acceldata - cache) 103 | cache = acceldata 104 | except IndexError: 105 | pass 106 | yield 107 | 108 | 109 | @forever 110 | def Square(inchan, outchan): 111 | while True: 112 | data = inchan.read() 113 | outchan.write(data ** 2) 114 | yield 115 | 116 | 117 | @forever 118 | def Normalise(inchan, outchan, start=0.0, end=100.0): 119 | scale = end - start 120 | while True: 121 | outchan.write(inchan.read() / scale) 122 | yield 123 | 124 | 125 | @forever 126 | def Threshold(thresh, inchan, outchan): 127 | while True: 128 | mag = inchan.read() 129 | if mag >= thresh: 130 | outchan.write(mag) 131 | yield 132 | 133 | -------------------------------------------------------------------------------- /csp/guards.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Builtin guard types. For builtin processes see csp.builtins. 5 | 6 | Copyright (C) Sarah Mount, 2010. 7 | 8 | This program is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU General Public License 10 | as published by the Free Software Foundation; either version 2 11 | of the License, or (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have rceeived a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | 22 | from __future__ import absolute_import 23 | 24 | import os 25 | import multiprocessing 26 | import threading 27 | import time 28 | 29 | from .csp import * 30 | 31 | 32 | __author__ = 'Sarah Mount ' 33 | __date__ = 'May 2010' 34 | 35 | 36 | ### Names exported by this module 37 | __all__ = ['Timer', 'Barrier'] 38 | 39 | class Timer(Guard): 40 | """Guard which only commits to synchronisation when a timer has expired. 41 | 42 | Timer objects are a type of CSP guard, like Channel types and Skip 43 | guards. Timer objects allow code to wait for a specific period of 44 | time before synchronising on a timer event. This can be done in a 45 | number of ways: either by sleeping for a period of time (similar 46 | to time.sleep in the standard library), or by setting the timer to 47 | become selectable (by an Alt object) after a specific period of 48 | time. For example: 49 | 50 | >>> timer = Timer() 51 | >>> timer.sleep(5) # sleep for 5 seconds 52 | >>> 53 | >>> alt = Alt(timer) 54 | >>> timer.set_alarm(3) # become selectable 3 seconds from now 55 | >>> alt.select() # will wait 3 seconds 56 | >>> 57 | """ 58 | 59 | def __init__(self): 60 | super(Timer, self).__init__() 61 | self.now = time.time() 62 | self.name = 'Timer guard created at:' + str(self.now) 63 | self.alarm = None 64 | 65 | def set_alarm(self, timeout): 66 | self.now = time.time() 67 | self.alarm = self.now + timeout 68 | 69 | def is_selectable(self): 70 | self.now = time.time() 71 | if self.alarm is None: 72 | return True 73 | elif self.now < self.alarm: 74 | return False 75 | return True 76 | 77 | def read(self): 78 | """Return current time. 79 | """ 80 | self.now = time.time() 81 | return self.now 82 | 83 | def sleep(self, timeout): 84 | """Put this process to sleep for a number of seconds. 85 | """ 86 | time.sleep(timeout) 87 | 88 | def enable(self): 89 | pass 90 | 91 | def disable(self): 92 | pass 93 | 94 | def select(self): 95 | pass 96 | 97 | 98 | class AbstractBarrier(object): 99 | 100 | def __init__(self, participants=0): 101 | self.participants = participants 102 | self.not_ready = participants 103 | self.lock = None # MUST be overridden in subclass 104 | self.reset(participants) 105 | 106 | def reset(self, participants): 107 | assert participants >= 0 108 | with self.lock: 109 | self.participants = participants 110 | self.not_ready = participants 111 | 112 | def enrol(self): 113 | with self.lock: 114 | self.participants += 1 115 | self.not_ready += 1 116 | 117 | def retire(self): 118 | with self.lock: 119 | self.participants -= 1 120 | self.not_ready -= 1 121 | if self.not_ready == 0: 122 | self.not_ready = self.participants 123 | self.lock.notifyAll() 124 | assert self.not_ready >= 0 125 | 126 | def synchronise(self): 127 | with self.lock: 128 | self.not_ready -= 1 129 | if self.not_ready > 0: 130 | self.lock.wait() 131 | else: 132 | self.not_ready = self.participants 133 | self.lock.notifyAll() 134 | 135 | def synchronise_withN(self, n): 136 | """Only syncrhonise when N participants are enrolled. 137 | """ 138 | with self.lock: 139 | if self.participants != n: 140 | self.lock.wait() 141 | self.not_ready -= 1 142 | if self.not_ready > 0: 143 | self.lock.wait() 144 | else: 145 | self.not_ready = self.participants 146 | self.lock.notifyAll() 147 | 148 | 149 | # TODO: Move these two classes to the modules corresponding to 150 | # their CSP process implementation (i. e. os_process/os_thread). 151 | 152 | class BarrierThreading(AbstractBarrier): 153 | 154 | def __init__(self): 155 | super(BarrierThreading, self).__init__() 156 | self.lock = threading.Condition() 157 | 158 | 159 | class BarrierProcessing(AbstractBarrier): 160 | 161 | def __init__(self): 162 | super(BarrierProcessing, self).__init__() 163 | self.lock = multiprocessing.Condition() 164 | 165 | 166 | # Use os processes unless requested otherwise. 167 | if CSP_IMPLEMENTATION == 'os_thread': 168 | Barrier = BarrierThreading 169 | else: 170 | Barrier = BarrierProcessing 171 | 172 | #Barrier.__doc__ = """ 173 | # 174 | #""" 175 | -------------------------------------------------------------------------------- /csp/lint/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/csp/lint/__init__.py -------------------------------------------------------------------------------- /csp/lint/lint.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Combined linting for python-csp. 5 | 6 | Copyright (C) Sarah Mount, 2010. 7 | 8 | This program is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU General Public License 10 | as published by the Free Software Foundation; either version 2 11 | of the License, or (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have rceeived a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | 22 | import compiler 23 | import csp.lint.channels 24 | import csp.lint.processes 25 | 26 | import exstatic.cspwarnings 27 | 28 | 29 | __all__ = ['run'] 30 | 31 | 32 | checkers = [csp.lint.channels.ChannelChecker, 33 | csp.lint.processes.ProcessChecker] 34 | 35 | 36 | def run(filename, excluded=[]): 37 | exstatic.cspwarnings.reset_errors() 38 | for checker in checkers: 39 | lint = checker(filename) 40 | compiler.walk(compiler.parseFile(filename), 41 | lint, 42 | walker=lint, 43 | verbose=5) 44 | exstatic.cspwarnings.print_errors(excluded=excluded) 45 | return 46 | 47 | if __name__ == '__main__': 48 | import sys 49 | if sys.argv > 1: 50 | run(sys.argv[1]) 51 | sys.exit() 52 | -------------------------------------------------------------------------------- /csp/lint/processes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Check for errors in process definitions. 5 | 6 | Copyright (C) Sarah Mount, 2010. 7 | 8 | This program is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU General Public License 10 | as published by the Free Software Foundation; either version 2 11 | of the License, or (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | 22 | import compiler 23 | import compiler.ast as ast 24 | import compiler.visitor as visitor 25 | 26 | import exstatic.cspwarnings 27 | 28 | 29 | __author__ = 'Sarah Mount ' 30 | __date__ = 'May 2010' 31 | 32 | 33 | __all__ = ['ProcessChecker'] 34 | 35 | class ProcessChecker(visitor.ASTVisitor): 36 | """Check that documented readsets and writesets are correct 37 | w.r.t. code. 38 | """ 39 | 40 | def __init__(self, filename): 41 | visitor.ASTVisitor.__init__(self) 42 | self.filename = filename 43 | self.current_process = '' 44 | self.current_process_lineno = 0 45 | return 46 | 47 | 48 | def is_process(self, decorators): 49 | """Determine whether or not the current function is a CSP 50 | process. 51 | """ 52 | for decorator in decorators: 53 | if (decorator.name == 'process' or decorator.name == 'forever'): 54 | return True 55 | return False 56 | 57 | 58 | def visitFunction(self, node): 59 | """Visit function definition. 60 | """ 61 | 62 | # If this function definition is not a CSP process, ignore it. 63 | if (node.decorators is None or 64 | self.is_process(node.decorators) is None): 65 | return 66 | 67 | # Store useful information about this process. 68 | self.current_process = node.name 69 | self.current_process_lineno = node.lineno 70 | 71 | # 'I001':'Function is a CSP process or server process', 72 | exstatic.cspwarnings.create_error(self.filename, 73 | self.current_process_lineno, 74 | self.current_process, 75 | 'I001') 76 | 77 | # 'W004':'@process or @forever applied to method (rather than function)' 78 | if 'self' in node.argnames: 79 | exstatic.cspwarnings.create_error(self.filename, 80 | self.current_process_lineno, 81 | self.current_process, 82 | 'W004') 83 | 84 | return 85 | 86 | 87 | if __name__ == '__main__': 88 | import sys 89 | 90 | lint = ProcessChecker(sys.argv[1]) 91 | compiler.walk(compiler.parseFile(sys.argv[1]), 92 | lint, 93 | walker=lint, 94 | verbose=5) 95 | 96 | exstatic.cspwarnings.print_errors(excluded=[]) 97 | -------------------------------------------------------------------------------- /csp/patterns.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """Design pattern support for python-csp. 4 | 5 | Copyright (C) Sarah Mount, 2010. 6 | 7 | This program is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU General Public License 9 | as published by the Free Software Foundation; either version 2 10 | of the License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A ParTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have rceeived a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 20 | """ 21 | 22 | 23 | from __future__ import absolute_import 24 | 25 | from .csp import * 26 | 27 | 28 | __author__ = 'Sarah Mount ' 29 | __date__ = 'May 2010' 30 | 31 | 32 | __all__ = ['TokenRing'] 33 | 34 | 35 | class TokenRing(Par): 36 | 37 | def __init__(self, func, size, numtoks=1): 38 | self.chans = [Channel() for channel in range(size)] 39 | self.procs = [func(index=i, 40 | tokens=numtoks, 41 | numnodes=size, 42 | inchan=self.chans[i-1], 43 | outchan=self.chans[i]) for i in range(size)] 44 | super(TokenRing, self).__init__(*self.procs) 45 | 46 | -------------------------------------------------------------------------------- /csp/tracer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/csp/tracer/__init__.py -------------------------------------------------------------------------------- /csp/tracer/cspmodel.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Simple representation of CSP models, with graphviz and FDR2 output. 5 | 6 | Copyright (C) Sarah Mount, 2010. 7 | 8 | This program is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU General Public License 10 | as published by the Free Software Foundation; either version 2 11 | of the License, or (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have rceeived a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | 22 | __author__ = 'Sarah Mount ' 23 | __date__ = '2010-05-16' 24 | 25 | 26 | class CSPModel(object): 27 | 28 | def __init__(self): 29 | return 30 | 31 | def fdr(self): 32 | """Generate a variant of this CSP model to a text file. 33 | Should be suitable for using as an input to the FDR2 tool. 34 | 35 | MUST be overridden in subclasses. 36 | """ 37 | raise Exception('fdr() MUST be overridden in subclasses.') 38 | 39 | def dot(self): 40 | """Generate a variant of this CSP model to a text file. 41 | Should be suitable for using as an input to the graphiz toolset. 42 | 43 | MUST be overridden in subclasses. 44 | """ 45 | raise Exception('fdr() MUST be overridden in subclasses.') 46 | 47 | 48 | 49 | class Process(CSPModel): 50 | 51 | def __init__(self, name): 52 | CSPModel.__init__(self) 53 | self.name = name 54 | 55 | def fdr(self): 56 | # WRONG, this should be a definition 57 | return self.name.upper() 58 | 59 | 60 | class Par(CSPModel): 61 | 62 | def __init__(self, procs): 63 | CSPModel.__init__(self) 64 | self.procs = procs 65 | 66 | def fdr(self): 67 | if len(self.procs) == 0: 68 | return '' 69 | fdr_string = self.procs[0].fdr() 70 | for proc in self.procs[1:]: 71 | fdr_string += ' ||| ' + proc 72 | return fdr_string 73 | 74 | 75 | class Seq(CSPModel): 76 | 77 | def __init__(self, procs): 78 | CSPModel.__init__(self) 79 | self.procs = procs 80 | return 81 | 82 | def fdr(self): 83 | if len(self.procs) == 0: 84 | return '' 85 | fdr_string = self.procs[0].fdr() 86 | for proc in self.procs[1:]: 87 | fdr_string += ' ; ' + proc 88 | return fdr_string 89 | 90 | 91 | class Channel(CSPModel): 92 | 93 | def __init__(self, name): 94 | CSPModel.__init__(self) 95 | self.name = name 96 | return 97 | 98 | def fdr(self): 99 | return 'channel ' + self.name + '\n' 100 | 101 | 102 | # def write_dotfile(filename='procgraph.dot'): 103 | # global nodes 104 | # global arcs 105 | # dot = "graph pythoncsp {\n node [shape=ellipse];" 106 | # for proc in nodes: 107 | # dot += " " + str(proc) + ";" 108 | # dot += "\n" 109 | # for channel in arcs: 110 | # for i in xrange(len(arcs[channel])): 111 | # for j in xrange(i+1, len(arcs[channel])): 112 | # dot += (str(arcs[channel][i]) + " -- " + 113 | # str(arcs[channel][j]) + 114 | # " [ label=" + str(channel) + " ];\n") 115 | # dot += ' label = "\\n\\nCSP Process Relationships\\n";\n' 116 | # dot += " fontsize=20;\n}" 117 | # fh = open(filename) 118 | # fh.write(dot) 119 | # fh.close() 120 | # return 121 | 122 | 123 | # def write_png(infile='procgraph.dot', outfile='procgraph.png'): 124 | # os.system('neato -v -Goverlap=-1 -Gsplines=true -Gsep=.1 -Gstart=-1000 Gepsilon=.0000000001 -Tpng ' + infile + ' -o' + outfile) 125 | 126 | 127 | if __name__ == '__main__': 128 | print ( 'WRITE SOME TESTS' ) 129 | 130 | -------------------------------------------------------------------------------- /docs/doctrees/builtins.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/docs/doctrees/builtins.doctree -------------------------------------------------------------------------------- /docs/doctrees/csp.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/docs/doctrees/csp.doctree -------------------------------------------------------------------------------- /docs/doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/docs/doctrees/environment.pickle -------------------------------------------------------------------------------- /docs/doctrees/guards.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/docs/doctrees/guards.doctree -------------------------------------------------------------------------------- /docs/doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/docs/doctrees/index.doctree -------------------------------------------------------------------------------- /docs/doctrees/mandelbrot.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/docs/doctrees/mandelbrot.doctree -------------------------------------------------------------------------------- /docs/doctrees/patterns.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/docs/doctrees/patterns.doctree -------------------------------------------------------------------------------- /docs/doctrees/tracer.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/docs/doctrees/tracer.doctree -------------------------------------------------------------------------------- /docs/html/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: a8271a5c91c46cfcc096a0b82e63654b 4 | tags: fbb0d17656682115ca4d033fb2f83ba1 5 | -------------------------------------------------------------------------------- /docs/html/_sources/builtins.txt: -------------------------------------------------------------------------------- 1 | Pre-built proceses 2 | ================== 3 | 4 | .. automodule:: csp.builtins 5 | :members: 6 | 7 | .. 8 | 9 | * :ref:`genindex` 10 | * :ref:`modindex` 11 | * :ref:`search` 12 | 13 | -------------------------------------------------------------------------------- /docs/html/_sources/csp.txt: -------------------------------------------------------------------------------- 1 | Core CSP library. 2 | ================= 3 | 4 | .. automodule:: csp.csp 5 | :members: 6 | 7 | .. 8 | 9 | * :ref:`genindex` 10 | * :ref:`modindex` 11 | * :ref:`search` 12 | 13 | -------------------------------------------------------------------------------- /docs/html/_sources/guards.txt: -------------------------------------------------------------------------------- 1 | Prebuilt synchronisation primitives. 2 | ==================================== 3 | 4 | .. automodule:: csp.guards 5 | :members: 6 | 7 | .. 8 | 9 | 10 | * :ref:`genindex` 11 | * :ref:`modindex` 12 | * :ref:`search` 13 | 14 | -------------------------------------------------------------------------------- /docs/html/_sources/index.txt: -------------------------------------------------------------------------------- 1 | .. python-csp documentation master file, created by 2 | sphinx-quickstart on Sat Apr 10 00:03:15 2010. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to python-csp's documentation! 7 | ====================================== 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | csp.rst 15 | builtins.rst 16 | guards.rst 17 | patterns.rst 18 | tracer.rst 19 | mandelbrot.rst 20 | 21 | 22 | .. 23 | 24 | Indices and tables 25 | ================== 26 | 27 | * :ref:`genindex` 28 | * :ref:`modindex` 29 | * :ref:`search` 30 | 31 | -------------------------------------------------------------------------------- /docs/html/_sources/mandelbrot.txt: -------------------------------------------------------------------------------- 1 | Mandelbrot example 2 | ================== 3 | 4 | .. automodule:: mandelbrot 5 | :members: 6 | 7 | .. 8 | 9 | * :ref:`genindex` 10 | * :ref:`modindex` 11 | * :ref:`search` 12 | 13 | -------------------------------------------------------------------------------- /docs/html/_sources/patterns.txt: -------------------------------------------------------------------------------- 1 | Design patterns for automatically wiring process graphs 2 | ======================================================= 3 | 4 | .. automodule:: csp.patterns 5 | :members: 6 | 7 | .. 8 | 9 | 10 | * :ref:`genindex` 11 | * :ref:`modindex` 12 | * :ref:`search` 13 | 14 | -------------------------------------------------------------------------------- /docs/html/_sources/tracer.txt: -------------------------------------------------------------------------------- 1 | Debugging with the tracer module 2 | ================================ 3 | 4 | .. automodule:: csp.tracer 5 | :members: 6 | 7 | .. 8 | 9 | * :ref:`genindex` 10 | * :ref:`modindex` 11 | * :ref:`search` 12 | 13 | -------------------------------------------------------------------------------- /docs/html/_static/default.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Sphinx stylesheet -- default theme 3 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | */ 5 | 6 | @import url("basic.css"); 7 | 8 | /* -- page layout ----------------------------------------------------------- */ 9 | 10 | body { 11 | font-family: sans-serif; 12 | font-size: 100%; 13 | background-color: #11303d; 14 | color: #000; 15 | margin: 0; 16 | padding: 0; 17 | } 18 | 19 | div.document { 20 | background-color: #1c4e63; 21 | } 22 | 23 | div.documentwrapper { 24 | float: left; 25 | width: 100%; 26 | } 27 | 28 | div.bodywrapper { 29 | margin: 0 0 0 230px; 30 | } 31 | 32 | div.body { 33 | background-color: #ffffff; 34 | color: #000000; 35 | padding: 0 20px 30px 20px; 36 | } 37 | 38 | div.footer { 39 | color: #ffffff; 40 | width: 100%; 41 | padding: 9px 0 9px 0; 42 | text-align: center; 43 | font-size: 75%; 44 | } 45 | 46 | div.footer a { 47 | color: #ffffff; 48 | text-decoration: underline; 49 | } 50 | 51 | div.related { 52 | background-color: #133f52; 53 | line-height: 30px; 54 | color: #ffffff; 55 | } 56 | 57 | div.related a { 58 | color: #ffffff; 59 | } 60 | 61 | div.sphinxsidebar { 62 | } 63 | 64 | div.sphinxsidebar h3 { 65 | font-family: 'Trebuchet MS', sans-serif; 66 | color: #ffffff; 67 | font-size: 1.4em; 68 | font-weight: normal; 69 | margin: 0; 70 | padding: 0; 71 | } 72 | 73 | div.sphinxsidebar h3 a { 74 | color: #ffffff; 75 | } 76 | 77 | div.sphinxsidebar h4 { 78 | font-family: 'Trebuchet MS', sans-serif; 79 | color: #ffffff; 80 | font-size: 1.3em; 81 | font-weight: normal; 82 | margin: 5px 0 0 0; 83 | padding: 0; 84 | } 85 | 86 | div.sphinxsidebar p { 87 | color: #ffffff; 88 | } 89 | 90 | div.sphinxsidebar p.topless { 91 | margin: 5px 10px 10px 10px; 92 | } 93 | 94 | div.sphinxsidebar ul { 95 | margin: 10px; 96 | padding: 0; 97 | color: #ffffff; 98 | } 99 | 100 | div.sphinxsidebar a { 101 | color: #98dbcc; 102 | } 103 | 104 | div.sphinxsidebar input { 105 | border: 1px solid #98dbcc; 106 | font-family: sans-serif; 107 | font-size: 1em; 108 | } 109 | 110 | /* -- body styles ----------------------------------------------------------- */ 111 | 112 | a { 113 | color: #355f7c; 114 | text-decoration: none; 115 | } 116 | 117 | a:hover { 118 | text-decoration: underline; 119 | } 120 | 121 | div.body p, div.body dd, div.body li { 122 | text-align: justify; 123 | line-height: 130%; 124 | } 125 | 126 | div.body h1, 127 | div.body h2, 128 | div.body h3, 129 | div.body h4, 130 | div.body h5, 131 | div.body h6 { 132 | font-family: 'Trebuchet MS', sans-serif; 133 | background-color: #f2f2f2; 134 | font-weight: normal; 135 | color: #20435c; 136 | border-bottom: 1px solid #ccc; 137 | margin: 20px -20px 10px -20px; 138 | padding: 3px 0 3px 10px; 139 | } 140 | 141 | div.body h1 { margin-top: 0; font-size: 200%; } 142 | div.body h2 { font-size: 160%; } 143 | div.body h3 { font-size: 140%; } 144 | div.body h4 { font-size: 120%; } 145 | div.body h5 { font-size: 110%; } 146 | div.body h6 { font-size: 100%; } 147 | 148 | a.headerlink { 149 | color: #c60f0f; 150 | font-size: 0.8em; 151 | padding: 0 4px 0 4px; 152 | text-decoration: none; 153 | } 154 | 155 | a.headerlink:hover { 156 | background-color: #c60f0f; 157 | color: white; 158 | } 159 | 160 | div.body p, div.body dd, div.body li { 161 | text-align: justify; 162 | line-height: 130%; 163 | } 164 | 165 | div.admonition p.admonition-title + p { 166 | display: inline; 167 | } 168 | 169 | div.note { 170 | background-color: #eee; 171 | border: 1px solid #ccc; 172 | } 173 | 174 | div.seealso { 175 | background-color: #ffc; 176 | border: 1px solid #ff6; 177 | } 178 | 179 | div.topic { 180 | background-color: #eee; 181 | } 182 | 183 | div.warning { 184 | background-color: #ffe4e4; 185 | border: 1px solid #f66; 186 | } 187 | 188 | p.admonition-title { 189 | display: inline; 190 | } 191 | 192 | p.admonition-title:after { 193 | content: ":"; 194 | } 195 | 196 | pre { 197 | padding: 5px; 198 | background-color: #eeffcc; 199 | color: #333333; 200 | line-height: 120%; 201 | border: 1px solid #ac9; 202 | border-left: none; 203 | border-right: none; 204 | } 205 | 206 | tt { 207 | background-color: #ecf0f3; 208 | padding: 0 1px 0 1px; 209 | font-size: 0.95em; 210 | } 211 | 212 | .warning tt { 213 | background: #efc2c2; 214 | } 215 | 216 | .note tt { 217 | background: #d6d6d6; 218 | } -------------------------------------------------------------------------------- /docs/html/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/docs/html/_static/file.png -------------------------------------------------------------------------------- /docs/html/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/docs/html/_static/minus.png -------------------------------------------------------------------------------- /docs/html/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/docs/html/_static/plus.png -------------------------------------------------------------------------------- /docs/html/_static/pygments.css: -------------------------------------------------------------------------------- 1 | .hll { background-color: #ffffcc } 2 | .c { color: #408090; font-style: italic } /* Comment */ 3 | .err { border: 1px solid #FF0000 } /* Error */ 4 | .k { color: #007020; font-weight: bold } /* Keyword */ 5 | .o { color: #666666 } /* Operator */ 6 | .cm { color: #408090; font-style: italic } /* Comment.Multiline */ 7 | .cp { color: #007020 } /* Comment.Preproc */ 8 | .c1 { color: #408090; font-style: italic } /* Comment.Single */ 9 | .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ 10 | .gd { color: #A00000 } /* Generic.Deleted */ 11 | .ge { font-style: italic } /* Generic.Emph */ 12 | .gr { color: #FF0000 } /* Generic.Error */ 13 | .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 14 | .gi { color: #00A000 } /* Generic.Inserted */ 15 | .go { color: #303030 } /* Generic.Output */ 16 | .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ 17 | .gs { font-weight: bold } /* Generic.Strong */ 18 | .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 19 | .gt { color: #0040D0 } /* Generic.Traceback */ 20 | .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ 21 | .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ 22 | .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ 23 | .kp { color: #007020 } /* Keyword.Pseudo */ 24 | .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ 25 | .kt { color: #902000 } /* Keyword.Type */ 26 | .m { color: #208050 } /* Literal.Number */ 27 | .s { color: #4070a0 } /* Literal.String */ 28 | .na { color: #4070a0 } /* Name.Attribute */ 29 | .nb { color: #007020 } /* Name.Builtin */ 30 | .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ 31 | .no { color: #60add5 } /* Name.Constant */ 32 | .nd { color: #555555; font-weight: bold } /* Name.Decorator */ 33 | .ni { color: #d55537; font-weight: bold } /* Name.Entity */ 34 | .ne { color: #007020 } /* Name.Exception */ 35 | .nf { color: #06287e } /* Name.Function */ 36 | .nl { color: #002070; font-weight: bold } /* Name.Label */ 37 | .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ 38 | .nt { color: #062873; font-weight: bold } /* Name.Tag */ 39 | .nv { color: #bb60d5 } /* Name.Variable */ 40 | .ow { color: #007020; font-weight: bold } /* Operator.Word */ 41 | .w { color: #bbbbbb } /* Text.Whitespace */ 42 | .mf { color: #208050 } /* Literal.Number.Float */ 43 | .mh { color: #208050 } /* Literal.Number.Hex */ 44 | .mi { color: #208050 } /* Literal.Number.Integer */ 45 | .mo { color: #208050 } /* Literal.Number.Oct */ 46 | .sb { color: #4070a0 } /* Literal.String.Backtick */ 47 | .sc { color: #4070a0 } /* Literal.String.Char */ 48 | .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ 49 | .s2 { color: #4070a0 } /* Literal.String.Double */ 50 | .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ 51 | .sh { color: #4070a0 } /* Literal.String.Heredoc */ 52 | .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ 53 | .sx { color: #c65d09 } /* Literal.String.Other */ 54 | .sr { color: #235388 } /* Literal.String.Regex */ 55 | .s1 { color: #4070a0 } /* Literal.String.Single */ 56 | .ss { color: #517918 } /* Literal.String.Symbol */ 57 | .bp { color: #007020 } /* Name.Builtin.Pseudo */ 58 | .vc { color: #bb60d5 } /* Name.Variable.Class */ 59 | .vg { color: #bb60d5 } /* Name.Variable.Global */ 60 | .vi { color: #bb60d5 } /* Name.Variable.Instance */ 61 | .il { color: #208050 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /docs/html/_static/pythoncsp-docs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/docs/html/_static/pythoncsp-docs.png -------------------------------------------------------------------------------- /docs/html/modindex.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | Global Module Index — python-csp v0.1 documentation 9 | 10 | 11 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 40 | 41 |
42 |
43 |
44 |
45 | 46 | 47 |

Global Module Index

48 | C | 49 | M 50 |
51 | 52 | 53 | 54 | 56 | 59 | 60 | 63 | 64 | 67 | 68 | 71 | 72 | 75 | 76 | 79 | 80 | 81 | 84 |
 
C
57 | csp 58 |
    61 | csp.builtins 62 |
    65 | csp.csp 66 |
    69 | csp.guards 70 |
    73 | csp.patterns 74 |
    77 | csp.tracer 78 |
 
M
82 | mandelbrot 83 |
85 | 86 | 87 |
88 |
89 |
90 |
91 |
92 | 95 | 107 | 108 |
109 |
110 |
111 |
112 | 124 | 128 | 129 | -------------------------------------------------------------------------------- /docs/html/objects.inv: -------------------------------------------------------------------------------- 1 | # Sphinx inventory version 1 2 | # Project: python-csp 3 | # Version: 0.1 4 | csp.patterns mod patterns.html 5 | csp.tracer mod tracer.html 6 | csp.guards mod guards.html 7 | csp.builtins mod builtins.html 8 | mandelbrot mod mandelbrot.html 9 | csp.csp mod csp.html 10 | csp.builtins.Id function builtins.html 11 | csp.builtins.Generate function builtins.html 12 | csp.csp.Channel.enable method csp.html 13 | csp.csp.Alt.fair_select method csp.html 14 | csp.builtins.Multiply function builtins.html 15 | csp.csp.Channel.select method csp.html 16 | csp.builtins.Pow function builtins.html 17 | csp.builtins.RShift function builtins.html 18 | csp.builtins.Is_Not function builtins.html 19 | csp.builtins.Land function builtins.html 20 | csp.csp.Channel.is_selectable method csp.html 21 | csp.csp.Guard class csp.html 22 | mandelbrot.MAXITER data mandelbrot.html 23 | csp.csp.process function csp.html 24 | csp.builtins.GenerateFloats function builtins.html 25 | csp.builtins.Prefix function builtins.html 26 | csp.csp.Par class csp.html 27 | csp.builtins.Mux2 function builtins.html 28 | csp.builtins.Delta2 function builtins.html 29 | csp.builtins.Div function builtins.html 30 | csp.csp.Channel.get method csp.html 31 | csp.csp.Skip.is_selectable method csp.html 32 | csp.builtins.Lnand function builtins.html 33 | csp.builtins.Printer function builtins.html 34 | csp.builtins.Splitter function builtins.html 35 | mandelbrot.consume function mandelbrot.html 36 | csp.builtins.Is function builtins.html 37 | csp.builtins.Xor function builtins.html 38 | csp.builtins.Or function builtins.html 39 | csp.csp.Channel.read method csp.html 40 | csp.csp.forever function csp.html 41 | csp.builtins.Lxor function builtins.html 42 | csp.builtins.FloorDiv function builtins.html 43 | csp.csp.CSPProcess.run method csp.html 44 | csp.builtins.Ne function builtins.html 45 | csp.builtins.Geq function builtins.html 46 | csp.csp.Alt.poison method csp.html 47 | csp.csp.Channel class csp.html 48 | csp.csp.Channel.put method csp.html 49 | csp.csp.Par.terminate method csp.html 50 | mandelbrot.main function mandelbrot.html 51 | csp.builtins.Sub function builtins.html 52 | csp.builtins.Mul function builtins.html 53 | csp.csp.Skip.disable method csp.html 54 | csp.builtins.Neg function builtins.html 55 | csp.builtins.Fibonacci function builtins.html 56 | csp.guards.Timer class guards.html 57 | csp.csp.FileChannel.put method csp.html 58 | csp.builtins.And function builtins.html 59 | csp.csp.Alt.select method csp.html 60 | csp.csp.Guard.disable method csp.html 61 | csp.csp.Channel.write method csp.html 62 | csp.csp.Guard.is_selectable method csp.html 63 | csp.builtins.Pairs function builtins.html 64 | csp.builtins.LShift function builtins.html 65 | csp.builtins.Mult function builtins.html 66 | csp.guards.Timer.read method guards.html 67 | csp.csp.Guard.select method csp.html 68 | csp.csp.Guard.enable method csp.html 69 | csp.builtins.Clock function builtins.html 70 | csp.csp.Alt class csp.html 71 | csp.builtins.Lor function builtins.html 72 | csp.builtins.Sin function builtins.html 73 | mandelbrot.mandelbrot function mandelbrot.html 74 | csp.csp.CSPServer.run method csp.html 75 | csp.builtins.Lt function builtins.html 76 | csp.guards.Timer.sleep method guards.html 77 | csp.csp.Skip.enable method csp.html 78 | csp.builtins.Lnor function builtins.html 79 | csp.builtins.Lnot function builtins.html 80 | csp.builtins.FixedDelay function builtins.html 81 | csp.builtins.Succ function builtins.html 82 | mandelbrot.get_colour function mandelbrot.html 83 | csp.builtins.Nor function builtins.html 84 | csp.builtins.Not function builtins.html 85 | csp.csp.CSPServer class csp.html 86 | csp.builtins.Zeroes function builtins.html 87 | csp.builtins.Gt function builtins.html 88 | csp.csp.Alt.pri_select method csp.html 89 | csp.csp.Channel.disable method csp.html 90 | csp.csp.Par.start method csp.html 91 | csp.csp.Skip class csp.html 92 | csp.builtins.Leq function builtins.html 93 | csp.builtins.Pred function builtins.html 94 | csp.csp.FileChannel class csp.html 95 | csp.csp.Seq class csp.html 96 | csp.builtins.Blackhole function builtins.html 97 | csp.builtins.Mod function builtins.html 98 | csp.csp.FileChannel.get method csp.html 99 | csp.csp.Skip.select method csp.html 100 | csp.csp.Guard.poison method csp.html 101 | csp.csp.Seq.start method csp.html 102 | csp.csp.CSPProcess class csp.html 103 | csp.builtins.Sign function builtins.html 104 | csp.builtins.Cos function builtins.html 105 | csp.builtins.Nand function builtins.html 106 | csp.builtins.Eq function builtins.html 107 | csp.csp.Channel.poison method csp.html 108 | csp.builtins.Plus function builtins.html 109 | -------------------------------------------------------------------------------- /docs/html/search.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | Search — python-csp v0.1 documentation 9 | 10 | 11 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 38 | 39 |
40 |
41 |
42 |
43 | 44 |

Search

45 |
46 | 47 |

48 | Please activate JavaScript to enable the search 49 | functionality. 50 |

51 |
52 |

53 | From here you can search these documents. Enter your search 54 | words into the box below and click "search". Note that the search 55 | function will automatically search for all of the words. Pages 56 | containing fewer words won't appear in the result list. 57 |

58 |
59 | 60 | 61 | 62 |
63 | 64 |
65 | 66 |
67 | 68 |
69 |
70 |
71 |
72 |
73 | 76 |
77 |
78 |
79 |
80 | 92 | 93 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /docs/html/tracer.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | Debugging with the tracer module — python-csp v0.1 documentation 9 | 10 | 11 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 45 | 46 |
47 |
48 |
49 |
50 | 51 |
52 |

Debugging with the tracer module

53 | 58 |
59 | 60 | 61 |
62 |
63 |
64 |
65 |
66 | 69 |

Previous topic

70 |

Design patterns for automatically wiring process graphs

72 |

Next topic

73 |

Mandelbrot example

75 |

This Page

76 | 80 | 92 | 93 |
94 |
95 |
96 |
97 | 115 | 119 | 120 | -------------------------------------------------------------------------------- /examples/barber/barber.py: -------------------------------------------------------------------------------- 1 | """ 2 | Solution to the sleeping barber problem in python-csp. 3 | 4 | Copyright (C) Sarah Mount, 2010. 5 | 6 | This program is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU General Public License 8 | as published by the Free Software Foundation; either version 2 9 | of the License, or (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have rceeived a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | """ 19 | 20 | __date__ = 'July 2010' 21 | __author__ = 'Sarah Mount ' 22 | 23 | 24 | from csp.csp import * 25 | from csp.builtins import Printer 26 | from csp.guards import Timer 27 | 28 | from queue import BoundedQueue as Queue 29 | 30 | 31 | @process 32 | def generate_customers(out_chan, printer): 33 | import random 34 | customers = ['Michael Palin', 'John Cleese', 'Terry Jones', 35 | 'Terry Gilliam', 'Graham Chapman'] 36 | while True: 37 | python = random.choice(customers) 38 | printer.write('{0} needs a good shave!'.format(python)) 39 | out_chan.write(python) 40 | 41 | 42 | @process 43 | def barber(door, printer): 44 | import random 45 | timer = Timer() 46 | while True: 47 | printer.write('Barber is sleeping.') 48 | customer = door.read() 49 | print_c.write('The barber has woken to give {0} a shave.'.format(customer)) 50 | timer.sleep(random.random() * 5) 51 | 52 | 53 | @process 54 | def main(max_chairs): 55 | door_in, door_out = Channel(), Channel() 56 | printer = Channel() 57 | Par(generate_customers(door_in, printer), 58 | Queue(door_in, door_out, max_chairs), 59 | barber(door_out, printer)).start() 60 | 61 | 62 | if __name__ == '__main__': 63 | # Start simulation with 5 chairs in waiting room. 64 | main(5).start() 65 | -------------------------------------------------------------------------------- /examples/barber/kbox.occ: -------------------------------------------------------------------------------- 1 | -- (c) Michael Sparks 2 | 3 | PROC box_with_maxsize(CHAN in, out) = 4 | CHAN pass_through, send_next 5 | PAR 6 | VAR head, tail, count, queue[n]: 7 | SEQ 8 | head := 0 9 | tail := 0 10 | count := 0 11 | WHILE TRUE: 12 | ALT 13 | (count < n) & in ? queue[tail] -- Input process - always ready to accept, for a sufficiently large value of n 14 | PAR -- Always accept values from sender up to queue size 15 | tail := (tail + 1) \ n 16 | count := count + 1 17 | (count > 0) & send_next ? ANY -- Pass through process 18 | SEQ -- Send on messages when reciever requests one 19 | pass_through ! queue[head] 20 | PAR 21 | head := (head + 1) \n 22 | count := count - 1 23 | WHILE TRUE -- Actual output process. Always ready to send if there's a value to send 24 | VAR x: -- In place of an output guard. Requests messages when not waiting to send a value 25 | SEQ 26 | send_next ! ANY -- Request next message from pass through process 27 | pass_through ? x -- Read value from pass_through process to send forward 28 | out ! x -- Send to out the value -------------------------------------------------------------------------------- /examples/boids/boidprocs-obstacles.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/examples/boids/boidprocs-obstacles.dia -------------------------------------------------------------------------------- /examples/boids/boidprocs.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/examples/boids/boidprocs.dia -------------------------------------------------------------------------------- /examples/boids/boids-part1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/examples/boids/boids-part1.png -------------------------------------------------------------------------------- /examples/boids/boids-part2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/examples/boids/boids-part2.png -------------------------------------------------------------------------------- /examples/boids/boids-part3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/examples/boids/boids-part3.png -------------------------------------------------------------------------------- /examples/boids/boids-part4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/examples/boids/boids-part4.png -------------------------------------------------------------------------------- /examples/boids/boids-sliders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/examples/boids/boids-sliders.png -------------------------------------------------------------------------------- /examples/boids/part1-classes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/examples/boids/part1-classes.png -------------------------------------------------------------------------------- /examples/boids/part1.py: -------------------------------------------------------------------------------- 1 | """ 2 | Boids simulation using python-csp and pygame. 3 | 4 | Part 1 -- Setting up Pygame. 5 | 6 | Copyright (C) Sarah Mount, 2009. 7 | 8 | This program is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU General Public License 10 | as published by the Free Software Foundation; either version 2 11 | of the License, or (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have rceeived a copy of the GNU General Public License 19 | along with this program; if not, write to the Free Software 20 | """ 21 | 22 | from csp.csp import * 23 | 24 | __author__ = 'Sarah Mount ' 25 | __date__ = 'October 2009' 26 | 27 | 28 | @process 29 | def simulate(poschan, SIZE): 30 | """ 31 | readset = 32 | writeset = poschan 33 | """ 34 | centre = [random.randint(0, SIZE[0]), random.randint(0, SIZE[1])] 35 | while True: 36 | centre = random.randint(0, SIZE[0]), random.randint(0, SIZE[1]) 37 | poschan.write(centre) 38 | return 39 | 40 | 41 | @process 42 | def drawboids(poschans, SIZE): 43 | """ 44 | readset = poschans 45 | writeset = 46 | """ 47 | import pygame 48 | 49 | FGCOL = (137, 192, 210, 100) # Foreground colour. 50 | BGCOL = pygame.Color('black') # Background colour. 51 | FPS = 60 # Maximum frames per second. 52 | CAPTION = 'python-csp example: Boids' 53 | FILENAME = 'boids.png' # Screenshot file. 54 | QUIT = False 55 | 56 | clock = pygame.time.Clock() 57 | dirty, last = [], [] 58 | # chansize = len(poschans) 59 | 60 | pygame.init() 61 | screen = pygame.display.set_mode((SIZE[0], SIZE[1]), 0) 62 | pygame.display.set_caption(CAPTION) 63 | 64 | while not QUIT: 65 | ms_elapsed = clock.tick(FPS) 66 | print(ms_elapsed) 67 | dirty = last 68 | for rect in last: screen.fill(BGCOL, rect) 69 | last = [] 70 | for channel in poschans: 71 | x, y = channel.read() 72 | rect = pygame.draw.circle(screen, FGCOL, (int(x), int(y)), 2, 0) 73 | dirty.append(rect) 74 | last.append(rect) 75 | pygame.display.update(dirty) # Update dirty rects. 76 | for event in pygame.event.get(): # Process events. 77 | if event.type == pygame.QUIT: 78 | QUIT = True 79 | elif event.type == pygame.KEYDOWN and event.key == pygame.K_s: 80 | pygame.image.save(screen, FILENAME) 81 | print('Saving boids in:', FILENAME) 82 | for chan in poschans: chan.poison() 83 | pygame.quit() 84 | return 85 | 86 | 87 | @process 88 | def main(): 89 | NUMBOIDS = 100 # Number of boids in simulation. 90 | SIZE = (800, 600) # Screen size. 91 | # Set up channels for reporting boid positions / velocities. 92 | poschans = [Channel() for i in range(NUMBOIDS)] 93 | # Draw channel for the drawboids process. 94 | # drawchan = Channel() 95 | # Generate a list of all processes in the simulation. 96 | procs = [simulate(poschans[i], SIZE) for i in range(NUMBOIDS)] 97 | procs.append(drawboids(poschans, SIZE)) # Drawing process. 98 | simulation = Par(*procs) # Start simulation. 99 | simulation.start() 100 | return 101 | 102 | 103 | if __name__ == '__main__': 104 | main().start() 105 | -------------------------------------------------------------------------------- /examples/boids/part2-classes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/examples/boids/part2-classes.png -------------------------------------------------------------------------------- /examples/boids/part2.py: -------------------------------------------------------------------------------- 1 | """ 2 | Boids simulation using python-csp and pygame. 3 | 4 | Part 2 -- Adding movement to the boids. 5 | 6 | Copyright (C) Sarah Mount, 2009. 7 | 8 | This program is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU General Public License 10 | as published by the Free Software Foundation; either version 2 11 | of the License, or (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have rceeived a copy of the GNU General Public License 19 | along with this program; if not, write to the Free Software 20 | """ 21 | 22 | from csp.csp import * 23 | 24 | __author__ = 'Sarah Mount ' 25 | __date__ = 'October 2009' 26 | 27 | 28 | @process 29 | def simulate(poschan, SIZE): 30 | """ 31 | readset = 32 | writeset = poschan 33 | """ 34 | centre = [random.randint(0, SIZE[0]), random.randint(0, SIZE[1])] 35 | default_velocity = [random.choice((-1.0, 0.0, 1.0)), 36 | random.choice((-1.0, 0.0, 1.0))] 37 | velocity = default_velocity 38 | while True: 39 | centre = [centre[0] + velocity[0], 40 | centre[1] + velocity[1]] 41 | # Wrap the screen. 42 | if centre[0]<0: centre[0] += SIZE[0] 43 | elif centre[0]>SIZE[0]: centre[0] -= SIZE[0] 44 | if centre[1]<0: centre[1] += SIZE[1] 45 | elif centre[1]>SIZE[1]: centre[1] -= SIZE[1] 46 | # Write to the drawing process. 47 | poschan.write(centre) 48 | return 49 | 50 | 51 | @process 52 | def drawboids(poschans, SIZE): 53 | """ 54 | readset = poschans 55 | writeset = 56 | """ 57 | import pygame 58 | 59 | FGCOL = (137, 192, 210, 100) # Foreground colour. 60 | BGCOL = pygame.Color('black') # Background colour. 61 | FPS = 60 # Maximum frames per second. 62 | CAPTION = 'python-csp example: Boids' 63 | FILENAME = 'boids.png' # Screenshot file. 64 | QUIT = False 65 | 66 | clock = pygame.time.Clock() 67 | dirty, last = [], [] 68 | # chansize = len(poschans) 69 | 70 | pygame.init() 71 | screen = pygame.display.set_mode((SIZE[0], SIZE[1]), 0) 72 | pygame.display.set_caption(CAPTION) 73 | 74 | while not QUIT: 75 | ms_elapsed = clock.tick(FPS) 76 | print(ms_elapsed) 77 | dirty = last 78 | for rect in last: screen.fill(BGCOL, rect) 79 | last = [] 80 | for channel in poschans: 81 | x, y = channel.read() 82 | rect = pygame.draw.circle(screen, FGCOL, (int(x), int(y)), 2, 0) 83 | dirty.append(rect) 84 | last.append(rect) 85 | pygame.display.update(dirty) # Update dirty rects. 86 | for event in pygame.event.get(): # Process events. 87 | if event.type == pygame.QUIT: 88 | QUIT = True 89 | elif event.type == pygame.KEYDOWN and event.key == pygame.K_s: 90 | pygame.image.save(screen, FILENAME) 91 | print('Saving boids in:', FILENAME) 92 | for chan in poschans: chan.poison() 93 | pygame.quit() 94 | return 95 | 96 | 97 | @process 98 | def main(): 99 | NUMBOIDS = 100 # Number of boids in simulation. 100 | SIZE = (800, 600) # Screen size. 101 | # Set up channels for reporting boid positions / velocities. 102 | poschans = [Channel() for i in range(NUMBOIDS)] 103 | # Draw channel for the drawboids process. 104 | # drawchan = Channel() 105 | # Generate a list of all processes in the simulation. 106 | procs = [simulate(poschans[i], SIZE) for i in range(NUMBOIDS)] 107 | procs.append(drawboids(poschans, SIZE)) # Drawing process. 108 | simulation = Par(*procs) # Start simulation. 109 | simulation.start() 110 | return 111 | 112 | 113 | if __name__ == '__main__': 114 | main().start() 115 | -------------------------------------------------------------------------------- /examples/boids/part3-classes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/examples/boids/part3-classes.png -------------------------------------------------------------------------------- /examples/boids/part4-classes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/examples/boids/part4-classes.png -------------------------------------------------------------------------------- /examples/builtins/builtin-example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | 4 | from csp.csp import * 5 | from csp.builtins import Fibonacci, Generate, Multiply, Printer 6 | 7 | 8 | if __name__ == '__main__': 9 | c = [] 10 | c.append(Channel()) 11 | c.append(Channel()) 12 | c.append(Channel()) 13 | 14 | f = Fibonacci(c[0]) 15 | g = Generate(c[1]) 16 | m = Multiply(c[0],c[1],c[2]) 17 | p = Printer(c[2]) 18 | 19 | par = Par(f,g,m,p) 20 | par.start() 21 | 22 | -------------------------------------------------------------------------------- /examples/circuits/fulladder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """Python CSP full adder. 4 | 5 | Based on code from PyCSP - Communicating Sequential Processes for 6 | Python. John Markus Bjorndalen, Brian Vinter, Otto Anshus. CPA 2007, 7 | Surrey, UK, July 8-11, 2007. IOS Press 2007, ISBN 978-1-58603-767-3, 8 | Concurrent Systems Engineering Series (ISSN 1383-7575). 9 | 10 | Copyright (C) Sarah Mount, 2009. 11 | 12 | This program is free software; you can redistribute it and/or 13 | modify it under the terms of the GNU General Public License 14 | as published by the Free Software Foundation; either version 2 15 | of the License, or (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU General Public License for more details. 21 | 22 | You should have rceeived a copy of the GNU General Public License 23 | along with this program; if not, write to the Free Software 24 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 25 | """ 26 | 27 | __author__ = 'Sarah Mount ' 28 | __date__ = 'December 2008' 29 | 30 | 31 | from csp.csp import * 32 | from csp.builtins import * 33 | 34 | @process 35 | def Bool1(cout): 36 | """ 37 | readset = 38 | writeset = cout 39 | """ 40 | while True: 41 | cout.write(1) 42 | cout.write(1) 43 | cout.write(0) 44 | cout.write(0) 45 | return 46 | 47 | @process 48 | def Bool2(cout): 49 | """ 50 | readset = 51 | writeset = cout 52 | """ 53 | while True: 54 | cout.write(1) 55 | cout.write(0) 56 | cout.write(1) 57 | cout.write(0) 58 | return 59 | 60 | def fulladder(A_in, B_in, C_in, Sum_in, Carry_in): 61 | """Full adder implementation. 62 | 63 | Based on Bjorndalen, Vinter & Anshus (2007). 64 | """ 65 | Aa = Channel() 66 | Ab = Channel() 67 | Ba = Channel() 68 | Bb = Channel() 69 | Ca = Channel() 70 | Cb = Channel() 71 | i1 = Channel() 72 | i1a = Channel() 73 | i1b = Channel() 74 | i2 = Channel() 75 | i3 = Channel() 76 | 77 | return Par(Delta2(A_in, Aa, Ab), 78 | Delta2(B_in, Ba, Bb), 79 | Delta2(C_in, Ca, Cb), 80 | Delta2(i1, i1a, i1b), 81 | Xor(Aa, Ba, i1), 82 | Xor(i1a, Ca, Sum_in), 83 | And(Ab, Bb, i2), 84 | And(i1b, Cb, i3), 85 | Or(i2, i3, Carry_in)) 86 | 87 | if __name__ == '__main__': 88 | print('\nFull adder implemented in Python CSP\n') 89 | # Inputs to full adder 90 | A = Channel() 91 | B = Channel() 92 | Cin = Channel() 93 | # Outputs of full adder 94 | Carry = Channel() 95 | Sum = Channel() 96 | # Channels for printing to STDOUT 97 | PCarry = Channel() 98 | PSum = Channel() 99 | # Create and start adder 100 | adder = Par(Bool1(A), 101 | Bool2(B), 102 | Zeroes(Cin), 103 | fulladder(A, B, Cin, Sum, Carry), 104 | Sign(Carry, PCarry, 'Carry: '), 105 | Printer(PCarry), 106 | Sign(Sum, PSum, 'Sum: '), 107 | Printer(PSum)) 108 | adder.start() 109 | 110 | 111 | -------------------------------------------------------------------------------- /examples/matrix/matrix.py: -------------------------------------------------------------------------------- 1 | 2 | #!/usr/bin/env python 3 | 4 | # FIXME: Nowhere near PEP8 compatible :( 5 | 6 | from csp.csp import * 7 | 8 | 9 | def calculateRowColumnProduct(self, A, row, B, col): 10 | product = 0 11 | for i in range(len(A[row])): 12 | product += A[row][i] * B[i][col] 13 | return product 14 | 15 | @process 16 | def ParcalculateRowColumnProduct(cout, A, row, B, col): 17 | """ 18 | readset = 19 | writeset = cout 20 | """ 21 | product = 0 22 | for i in range(len(A[row])): 23 | product += A[row][i] * B[i][col] 24 | cout.write((row,col,product)) 25 | 26 | class Matrix(): 27 | def __init__(self, h, k): 28 | self.matrix = [] 29 | for i in range(h): 30 | row = [] 31 | for j in range(k): 32 | row.append(0) 33 | 34 | self.matrix.append(row) 35 | 36 | def Multiply(self, mb): 37 | b = mb.matrix 38 | a = self.matrix 39 | if len(a[0]) != len(b): 40 | raise Exception() 41 | return 42 | 43 | mat = Matrix(len(a),len(b[0])) 44 | for i in range(len(a)) : 45 | for j in range(len(b[0])): 46 | mat.matrix[i][j] = calculateRowColumnProduct(self,a,i,b,j) 47 | 48 | return mat 49 | 50 | def ParMultiply(self, mb): 51 | b = mb.matrix 52 | a = self.matrix 53 | if len(a[0]) != len(b): 54 | raise Exception() 55 | return 56 | 57 | procs = [] 58 | chnls = [] 59 | mat = Matrix(len(a),len(b[0])) 60 | for i in range(len(a)) : 61 | for j in range(len(b[0])): 62 | ch = Channel() 63 | chnls.append(ch); 64 | procs.append(ParcalculateRowColumnProduct(ch,a,i,b,j)) 65 | 66 | 67 | p = Par(*procs); 68 | p.start(); 69 | 70 | alt = Alt(*chnls) 71 | 72 | for i in range(len(chnls)): 73 | a,b,ans = alt.select() 74 | 75 | mat.matrix[a][b] = ans 76 | alt.poison() 77 | 78 | return mat 79 | 80 | def createID(self): 81 | for i in range(len(self.matrix)) : 82 | for j in range(len(self.matrix[0])): 83 | if i == j: 84 | self.matrix[i][j] = 1 85 | else : 86 | self.matrix[i][j] = 0 87 | 88 | def printMatrix(self): 89 | print(self.matrix) 90 | 91 | 92 | if __name__ == '__main__': 93 | i = Matrix(3,3) 94 | g = Matrix(3,3) 95 | i.createID() 96 | g.createID() 97 | j = i.Multiply(g) 98 | j.printMatrix(); 99 | j = i.ParMultiply(g) 100 | j.printMatrix() 101 | 102 | print("") 103 | -------------------------------------------------------------------------------- /examples/monte_carlo/pi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from csp.csp import * 4 | from math import sqrt 5 | from decimal import Decimal 6 | 7 | 8 | 9 | def genPair(): 10 | return random.random(),random.random() 11 | 12 | g = lambda x: sqrt(1-(x*x)) 13 | 14 | 15 | perProcess = 100000 16 | 17 | workers = 320 18 | 19 | @process 20 | def worker(c): 21 | """ 22 | readset = 23 | writeset = c 24 | """ 25 | count = 0 26 | i = 0 27 | while i < perProcess: 28 | x,y = genPair() 29 | if y<= g(x) : 30 | count = count + 1 31 | i += 1 32 | c.write((Decimal(count))) 33 | return 34 | 35 | @process 36 | def consumer(cins): 37 | """ 38 | readset = cins 39 | writeset = 40 | """ 41 | alt = Alt(*cins) 42 | total = Decimal(0) 43 | for i in range(len(cins)): 44 | t = alt.select() 45 | total += t 46 | 47 | print("Pi aproximation: " + str( Decimal((total/(perProcess*workers))*4) ) ) 48 | 49 | def main(): 50 | Chnls, procs = [],[] 51 | for i in range(workers): 52 | Chnls.append(Channel()) 53 | procs.append(worker(Chnls[i])) 54 | 55 | procs.append(consumer(Chnls)) 56 | p = Par(*procs) 57 | p.start() 58 | return 59 | 60 | if __name__ == '__main__': 61 | getcontext().prec = 19 62 | t0 = time.time() 63 | main() 64 | t1 = time.time() 65 | print("Time Taken: " + str ( t1 - t0 ) ) 66 | -------------------------------------------------------------------------------- /examples/sensors/dsp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Digital signal processing for python-csp. 5 | 6 | Copyright (C) Sarah Mount, 2009. 7 | 8 | This program is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU General Public License 10 | as published by the Free Software Foundation; either version 2 11 | of the License, or (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have rceeived a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | 22 | from csp.csp import * 23 | 24 | import math 25 | 26 | # TODO: Use numpy for more sophisticated processes. 27 | 28 | ACCEL_DUE_TO_GRAVITY = 9.80665 29 | 30 | 31 | @forever 32 | def Zip(outchan, inchannels, _process=None): 33 | """Take data from a number of input channels, and write that 34 | data as a single list to L{outchan}. 35 | """ 36 | while True: 37 | outchan.write([chan.read() for chan in inchannels]) 38 | yield 39 | return 40 | 41 | 42 | @forever 43 | def Unzip(inchan, outchans, _process=None): 44 | """Continuously read tuples of data from a single input channel and send 45 | each datum out down its own output channel. 46 | """ 47 | while True: 48 | data = inchan.read() 49 | for i in range(data): 50 | outchans[i].write(data[i]) 51 | yield 52 | return 53 | 54 | 55 | @forever 56 | def Sin(inchan, outchan, _process=None): 57 | while True: 58 | outchan.write(math.sin(inchan.read())) 59 | yield 60 | return 61 | 62 | 63 | @forever 64 | def Cos(inchan, outchan, _process=None): 65 | while True: 66 | outchan.write(math.cos(inchan.read())) 67 | yield 68 | return 69 | 70 | 71 | @forever 72 | def Tan(inchan, outchan, _process=None): 73 | while True: 74 | outchan.write(math.tan(inchan.read())) 75 | yield 76 | return 77 | 78 | 79 | @forever 80 | def GenerateFloats(outchan, _process=None): 81 | x = 0.0 82 | while True: 83 | outchan.write(x) 84 | x += 0.1 85 | yield 86 | return 87 | 88 | 89 | @forever 90 | def Magnitude(inchan, outchan, _process=None): 91 | while True: 92 | acceldata = inchan.read() 93 | mag = 0.0 94 | for axis in acceldata: mag += axis ** 2 95 | outchan.write(math.sqrt(mag)) 96 | yield 97 | return 98 | 99 | 100 | @forever 101 | def Difference(inchan, outchan, window=1, _process=None): 102 | cache = 0.0 103 | while True: 104 | acceldata = inchan.read() 105 | try: 106 | outchan.write(acceldata - cache) 107 | cache = acceldata 108 | except IndexError: 109 | pass 110 | yield 111 | return 112 | 113 | 114 | @forever 115 | def Square(inchan, outchan, _process=None): 116 | while True: 117 | data = inchan.read() 118 | outchan.write(data ** 2) 119 | yield 120 | return 121 | 122 | 123 | @forever 124 | def Normalise(inchan, outchan, _process=None, start=0.0, end=100.0): 125 | scale = end - start 126 | while True: 127 | outchan.write(inchan.read() / scale) 128 | yield 129 | return 130 | 131 | 132 | @forever 133 | def Threshold(thresh, inchan, outchan, _process=None): 134 | while True: 135 | mag = inchan.read() 136 | if mag >= thresh: 137 | outchan.write(mag) 138 | yield 139 | return 140 | 141 | 142 | -------------------------------------------------------------------------------- /examples/sensors/oak_oscope.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Chart the output of a Toradex Oak accelerometer. 5 | 6 | Copyright (C) Sarah Mount, 2009. 7 | 8 | This program is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU General Public License 10 | as published by the Free Software Foundation; either version 2 11 | of the License, or (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have rceeived a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | 22 | __author__ = 'Sarah Mount ' 23 | __date__ = 'November 2009' 24 | __version__ = '0.2' 25 | 26 | from oscilloscope import Oscilloscope 27 | 28 | def chart_accel(): 29 | """Requires a Toradex Oak G to be attached to a USB port.""" 30 | import dsp 31 | from toradex_csp import Accelerometer 32 | channels = [Channel() for i in range(7)] 33 | par = Par(Accelerometer(channels[0]), 34 | dsp.Unzip(channels[0], (channels[0:3])), 35 | Blackhole(channels[1]), 36 | Blackhole(channels[2]), 37 | dsp.Difference(channels[1], channels[2]), 38 | dsp.Square(channels[2], channels[3]), 39 | Oscilloscope(channels[3])) 40 | par.start() 41 | return 42 | 43 | 44 | if __name__ == '__main__': 45 | chart_accel() 46 | -------------------------------------------------------------------------------- /exstatic/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/exstatic/__init__.py -------------------------------------------------------------------------------- /exstatic/cspwarnings.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Exstatic errors and warnings for CSP. 5 | 6 | TODO: Document this module. 7 | 8 | Copyright (C) Sarah Mount, 2010. 9 | 10 | This program is free software; you can redistribute it and/or 11 | modify it under the terms of the GNU General Public License 12 | as published by the Free Software Foundation; either version 2 13 | of the License, or (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have rceeived a copy of the GNU General Public License 21 | along with this program. If not, see . 22 | """ 23 | 24 | import exstatic.warnings 25 | 26 | __all__ = ['errcodes', 'list_error_codes', 'create_error', 'reset_errors', 27 | 'get_errors', 'print_errors'] 28 | 29 | errcodes = { 30 | # Information. 31 | 'I001':'Function is a CSP process or server process', 32 | # Warnings. 33 | 'W001':'Channel in both readset and writeset.', 34 | 'W002':'No readset given in documentation.', 35 | 'W003':'No writeset given in documentation.', 36 | 'W004':'@process or @forever applied to method (rather than function)', 37 | # Errors. 38 | 'E001':'Process / forever decorator wraps a method, not a function.', 39 | 'E002':'Channel in readset is not a formal parameter to this process.', 40 | 'E003':'Channel in writeset is not a formal parameter to this process.', 41 | 'E004':'Channel appears in documented readset but not read from in function body.', 42 | 'E005':'Channel is read from in function body but does not appear in documented readset', 43 | 'E006':'Channel appears in documented writeset but not written to in function body.', 44 | 'E007':'Channel is written to in function body but does not appear in documented writeset' 45 | } 46 | 47 | 48 | csp_error_list = exstatic.warnings.ExstaticErrorList(errcodes) 49 | 50 | 51 | def list_error_codes(): 52 | """List all available error codes. 53 | """ 54 | sep = '--------------------------------------------------------------------' 55 | print ( sep ) 56 | print ( ' CODE | MESSAGE' ) 57 | codes = list(errcodes.keys()) 58 | codes.sort() 59 | current_type = '' 60 | for key in codes: 61 | if key[0] != current_type: 62 | print ( sep ) 63 | print ( str ( key ) + ': |' + str ( errcodes[key] ) ) 64 | current_type = key[0] 65 | print ( sep ) 66 | return 67 | 68 | 69 | def create_error(filename, lineno, scope, errcode): 70 | """Create a new error and add it to the list. 71 | """ 72 | return csp_error_list.create_error(filename, lineno, scope, errcode) 73 | 74 | 75 | def reset_errors(): 76 | """Empty the current error list of all errors. 77 | """ 78 | csp_error_list.reset_errors() 79 | return 80 | 81 | 82 | def get_errors(excluded=[]): 83 | """Return the list of current errors. 84 | 85 | @return list of current errors. 86 | @type list 87 | """ 88 | return csp_error_list.get_errors(excluded=excluded) 89 | 90 | def print_errors(excluded=[]): 91 | """Print the list of current errors. 92 | """ 93 | csp_error_list.print_errors(excluded=excluded) 94 | return 95 | -------------------------------------------------------------------------------- /exstatic/py2icode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | py2icode.py produces an ICODE representation of a Python file. 5 | 6 | Usage: py2icode.py ? 7 | 8 | should be a python file for processing. The full path is not 9 | needed. is the name of the file which should store the 10 | ICODE translation of . If no name is given STDOUT is used. 11 | """ 12 | 13 | __author__ = 'Sarah Mount ' 14 | __date__ = '2010-05-16' 15 | 16 | 17 | DEBUG = True 18 | 19 | import ast, sys 20 | from pyicode import * 21 | 22 | __all__ = ['Ast2IcodeVisitor'] 23 | 24 | class Ast2IcodeVisitor(ast.NodeTransformer): 25 | """ 26 | AST Visitor which creates an ICODE translation of the AST, stored 27 | in its icode attribute. 28 | """ 29 | def __init__(self): 30 | super(AST2ICODEVisitor, self) 31 | self.icode = '' # BAH 32 | 33 | def vist_Function(self, node): 34 | pass 35 | 36 | 37 | # def default(self, node): 38 | # """Gives debug info in place of unwritten visit methods.""" 39 | # self.generic_visit(node) 40 | # return node 41 | # self.icode += "\nDEBUG: START NODE\n" 42 | # self.icode += '\t__repr__:' + node.__repr__() + '\n' 43 | # self.icode += '\t__dict__:' + str(node.__dict__) + '\n' 44 | # self.icode += "DEBUG: END NODE\n" 45 | 46 | 47 | if __name__ == '__main__': 48 | if DEBUG: print ( 'Debugging: ON. Script arguments:' + str ( sys.argv ) ) 49 | # Determine the input file. 50 | if len(sys.argv) == 1: 51 | print ( 'You must specify a Python file for processing.' ) 52 | sys.exit(1) 53 | else: 54 | i_file = sys.argv[1] 55 | # Determine the output file. Use sys.stdout if none specified. 56 | if len(sys.argv) > 2: 57 | o_file = sys.argv[2] 58 | o_fd = open(sys.argv[2], 'w') 59 | if DEBUG: print ( 'Output file:' + str ( sys.argv[2] ) ) 60 | else: 61 | if DEBUG: print ( 'Using STDOUT for output.' ) 62 | o_file = '' 63 | o_fd = sys.stdout 64 | # This is the important stuff. 65 | infile = open(i_file).read() 66 | tree = compile(infile, '', 'exec')#, ast.PyCF_ONLY_AST) 67 | outtree = AST2ICODEVisitor().visit(tree) 68 | o_fd.write(outtree.xml()) 69 | if not o_file == '': 70 | o_fd.close() 71 | # ...end of important stuff. 72 | 73 | #################################################################### 74 | # SCRATCH SPACE # 75 | #################################################################### 76 | # 77 | # self.icode += "\tSTART CHILD NODES\n" 78 | # for i in node.getChildNodes(): 79 | # self.icode += '\t\t__repr__:' + i.__repr__() + '\n' 80 | # self.icode += '\t\t__dict__:' + str(i.__dict__) + '\n' 81 | # self.dispatch(i) 82 | # self.icode += "\tEND CHILD NODES\n" 83 | 84 | 85 | 86 | ############# SCRATCH 87 | # def visit_Const(self, node): 88 | # self.generic_visit(node) 89 | # return IcodeConst(node.value, lineno=node.lineno) 90 | 91 | # def visit_Assign(self, node): 92 | # print 'ASSIGN' 93 | # for key,val in node.__dict__.items(): 94 | # print key, val 95 | # print 'END' 96 | # self.generic_visit(node) 97 | # return IcodeAssign(node.nodes, node.expr, lineno=node.lineno) 98 | 99 | # def visit_Import(self, node): 100 | # self.generic_visit(node) 101 | # return IcodeImport(node.names) 102 | 103 | 104 | -------------------------------------------------------------------------------- /exstatic/stack.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Generic stack type for Python. 5 | 6 | Copyright (C) Sarah Mount, 2010. 7 | 8 | This program is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU General Public License 10 | as published by the Free Software Foundation; either version 2 11 | of the License, or (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have rceeived a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | 22 | 23 | __all__ = ['Stack'] 24 | 25 | class Stack: 26 | 27 | def __init__(self): 28 | self.__stack = [] 29 | return 30 | 31 | def push(self, value): 32 | self.__stack.append(value) 33 | return 34 | 35 | def pop(self): 36 | assert(len(self.__stack) > 0) 37 | return self.__stack.pop() 38 | 39 | def peek(self): 40 | assert(len(self.__stack) > 0) 41 | return self.__stack[len(self.__stack) - 1] 42 | 43 | def issubset(self, other): 44 | """Determine whether other stack is a subset of this one. 45 | Order matters. 46 | """ 47 | size = min(len(self.__stack), len(other)) 48 | for i in range(size): 49 | if not self.__stack[i] == other[i]: 50 | return False 51 | return True 52 | 53 | def __contains__(self, item): 54 | return item in self.__stack 55 | 56 | def __len__(self): 57 | return len(self.__stack) 58 | 59 | def __getitem__(self, index): 60 | return self.__stack[index] 61 | 62 | def __iter__(self): 63 | return self.__stack.__iter__() 64 | 65 | def __repr__(self): 66 | return self.__stack.__repr__() 67 | 68 | def __str__(self): 69 | return self.__stack.__str__() 70 | 71 | -------------------------------------------------------------------------------- /exstatic/warnings.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Generic warnings and errors for Exstatic. 5 | 6 | TODO: Document this module. 7 | 8 | Copyright (C) Sarah Mount, 2010. 9 | 10 | This program is free software; you can redistribute it and/or 11 | modify it under the terms of the GNU General Public License 12 | as published by the Free Software Foundation; either version 2 13 | of the License, or (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have rceeived a copy of the GNU General Public License 21 | along with this program. If not, see . 22 | """ 23 | 24 | __author__ = 'Sarah Mount ' 25 | __date__ = 'May 2010' 26 | 27 | import os.path 28 | import sys 29 | 30 | severity = {'I':'Information', 'W':'Warning', 'E':'Error'} 31 | 32 | 33 | __all__ = ['severity', 'ExstaticErrorList', 'ExstaticError', 34 | 'ExstaticErrorFactory'] 35 | 36 | 37 | class ExstaticErrorList(object): 38 | 39 | def __init__(self, errcodes): 40 | self.error_factory = ExstaticErrorFactory(errcodes) 41 | self.errors = [] 42 | return 43 | 44 | def create_error(self, filename, lineno, scope, errcode): 45 | error = self.error_factory.create_error(filename, lineno, scope, errcode) 46 | self.errors.append(error) 47 | return 48 | 49 | def get_errors(self, excluded=[]): 50 | """Return a list of the current errors, excluding any in the 51 | excluded set. 52 | """ 53 | errors = [] 54 | for error in self.errors: 55 | if not error.errcode in excluded: 56 | errors.append(error) 57 | return errors 58 | 59 | def print_errors(self, out=sys.stdout, excluded=[]): 60 | """Print a list of the current errors, excluding any in the 61 | excluded set. 62 | """ 63 | for error in self.errors: 64 | if not error.errcode in excluded: 65 | out.write(str(error)) 66 | out.write('\n') 67 | return 68 | 69 | def reset_errors(self): 70 | self.errors = [] 71 | return 72 | 73 | 74 | class ExstaticErrorFactory(object): 75 | 76 | def __init__(self, errcodes): 77 | """ 78 | @param errcodes dictionary of error codes -> explainations 79 | """ 80 | self.errcodes = errcodes 81 | return 82 | 83 | def create_error(self, filename, lineno, scope, errcode): 84 | """Create and return a new error. 85 | """ 86 | obj = ExstaticError(filename, lineno, scope, errcode) 87 | obj.set_explaination(self.errcodes[errcode]) 88 | return obj 89 | 90 | 91 | class ExstaticError(object): 92 | 93 | def __init__(self, filename, lineno, scope, errcode): 94 | """ 95 | @param filename: name of the file in which error occurs 96 | @param lineno: line number on which error occurs 97 | @param scope: scope that the error occurs in (e.g. function name) 98 | @param errcode: name of this particular error 99 | """ 100 | self.filename = os.path.basename(filename) 101 | self.lineno = lineno 102 | self.scope = scope 103 | self.errcode = errcode 104 | self.explaination = '' 105 | return 106 | 107 | def get_severity(self): 108 | """ 109 | @return 'E' for an error and 'W' for a warning. 110 | """ 111 | return severity[self.errcode[0]] 112 | 113 | def set_explaination(self, explain): 114 | self.explaination = explain 115 | return 116 | 117 | def __str__(self): 118 | return '[{0}:{1}] {2} ({3}, {4}): {5}'.format(self.filename, 119 | self.lineno, 120 | self.get_severity(), 121 | self.errcode, 122 | self.scope, 123 | self.explaination) 124 | 125 | -------------------------------------------------------------------------------- /gadget/readme.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /logo/logo-square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/logo/logo-square.png -------------------------------------------------------------------------------- /logo/pythoncsp-docs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/logo/pythoncsp-docs.png -------------------------------------------------------------------------------- /logo/pythoncsp-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/logo/pythoncsp-logo.png -------------------------------------------------------------------------------- /logo/pythoncsp-logo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/logo/pythoncsp-logo.xcf -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | set SPHINXBUILD=sphinx-build 6 | set ALLSPHINXOPTS=-d build/doctrees %SPHINXOPTS% rst 7 | if NOT "%PAPER%" == "" ( 8 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 9 | ) 10 | 11 | if "%1" == "" goto help 12 | 13 | if "%1" == "help" ( 14 | :help 15 | echo.Please use `make ^` where ^ is one of 16 | echo. html to make standalone HTML files 17 | echo. dirhtml to make HTML files named index.html in directories 18 | echo. pickle to make pickle files 19 | echo. json to make JSON files 20 | echo. htmlhelp to make HTML files and a HTML help project 21 | echo. qthelp to make HTML files and a qthelp project 22 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 23 | echo. changes to make an overview over all changed/added/deprecated items 24 | echo. linkcheck to check all external links for integrity 25 | echo. doctest to run all doctests embedded in the documentation if enabled 26 | goto end 27 | ) 28 | 29 | if "%1" == "clean" ( 30 | for /d %%i in (build\*) do rmdir /q /s %%i 31 | del /q /s build\* 32 | goto end 33 | ) 34 | 35 | if "%1" == "html" ( 36 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% build/html 37 | echo. 38 | echo.Build finished. The HTML pages are in build/html. 39 | goto end 40 | ) 41 | 42 | if "%1" == "dirhtml" ( 43 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% build/dirhtml 44 | echo. 45 | echo.Build finished. The HTML pages are in build/dirhtml. 46 | goto end 47 | ) 48 | 49 | if "%1" == "pickle" ( 50 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% build/pickle 51 | echo. 52 | echo.Build finished; now you can process the pickle files. 53 | goto end 54 | ) 55 | 56 | if "%1" == "json" ( 57 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% build/json 58 | echo. 59 | echo.Build finished; now you can process the JSON files. 60 | goto end 61 | ) 62 | 63 | if "%1" == "htmlhelp" ( 64 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% build/htmlhelp 65 | echo. 66 | echo.Build finished; now you can run HTML Help Workshop with the ^ 67 | .hhp project file in build/htmlhelp. 68 | goto end 69 | ) 70 | 71 | if "%1" == "qthelp" ( 72 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% build/qthelp 73 | echo. 74 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 75 | .qhcp project file in build/qthelp, like this: 76 | echo.^> qcollectiongenerator build\qthelp\python-csp.qhcp 77 | echo.To view the help file: 78 | echo.^> assistant -collectionFile build\qthelp\python-csp.ghc 79 | goto end 80 | ) 81 | 82 | if "%1" == "latex" ( 83 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% build/latex 84 | echo. 85 | echo.Build finished; the LaTeX files are in build/latex. 86 | goto end 87 | ) 88 | 89 | if "%1" == "changes" ( 90 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% build/changes 91 | echo. 92 | echo.The overview file is in build/changes. 93 | goto end 94 | ) 95 | 96 | if "%1" == "linkcheck" ( 97 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% build/linkcheck 98 | echo. 99 | echo.Link check complete; look for any errors in the above output ^ 100 | or in build/linkcheck/output.txt. 101 | goto end 102 | ) 103 | 104 | if "%1" == "doctest" ( 105 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% build/doctest 106 | echo. 107 | echo.Testing of doctests in the sources finished, look at the ^ 108 | results in build/doctest/output.txt. 109 | goto end 110 | ) 111 | 112 | :end 113 | -------------------------------------------------------------------------------- /maketags.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | find . -name *.py -print -or -name *.html -print | xargs etags 4 | -------------------------------------------------------------------------------- /rst/Tutorial.wiki: -------------------------------------------------------------------------------- 1 | #summary python-csp tutorial (front page). 2 | #labels Featured,Phase-Support,Tutorial 3 | 4 | 5 | 6 | This page should give you an birds-eye view of CSP and the python-csp 7 | library. The tutorial pages that follow take you through installing 8 | the library and using it in some detail, with several medium sized 9 | example programs (and exercises!). 10 | 11 | = What is CSP? = 12 | 13 | Concurrent and parallel programming are generally seen as "difficult" 14 | tasks. This is partly because most people have a mental model of how 15 | computers work which is fundamentally sequential, and partly because 16 | concurrent programs are susceptible to errors such as race hazards, 17 | deadlocks, and so on. 18 | 19 | CSP stands for Communicating Sequential Processes, which is a 20 | framework for writing concurrent or program via _message 21 | passinge_. The advantage of message passing is that it makes race 22 | hazards impossible and provides a model of concurrency that is much 23 | easier to think about and more fun to program with. 24 | 25 | 26 | = Why CSP for Python? = 27 | 28 | Python currently has some support for threaded concurrency via the 29 | `thread` and `threading` module, support for parallel programming and 30 | the `processing` module. Threads are very low level, difficult to work 31 | with and cannot take advantage of multicore architectures that are now 32 | becoming commonplace. The `processing` module provides good support 33 | for process and thread-safe data structures but neither provide 34 | support for the message passing paradigm of programming and the sorts 35 | of constructs common to CSP style languages (such as OCCAM, OCCAM-pi, 36 | JCSP, C++CSP and so on). python-csp is design to plug this gap and 37 | also to provide an idiomatically _pythonic_ implementation of the 38 | ideas in CSP. 39 | 40 | 41 | == CSP resources == 42 | 43 | * [http://www.usingcsp.com/ CSP book] Hoare's original CSP book 44 | * [http://wotug.org/ WoTUG] The place for Communicating Processes 45 | * [http://books.google.co.uk/books?id=4ygZed-24LsC&printsec=frontcover&dq=communicating+sequential+processes&source=bl&ots=VfQoVDyIXn&sig=xDJ3FwyC82NSJ5J1bCMnkWPsS8M&hl=en&ei=c8K_S-K8HZX20gT618GWCQ&sa=X&oi=book_result&ct=result&resnum=12&ved=0CEYQ6AEwCw#v=onepage&q&f=false 25 years of CSP] 46 | 47 | 48 | == Other concurrency packages for Python == 49 | 50 | * [http://code.google.com/p/pycsp/ PyCSP] is another CSP library for Python, and somewhat similar to python-csp. In the medium term it is intended that PyCSP and python-csp will merge. 51 | * [http://peak.telecommunity.com/DevCenter/Trellis Trellis] reactive programming for Python 52 | * [http://peak.telecommunity.com/DevCenter/TrellisSTM STM] software transactional memory for Python 53 | * [http://www.kamaelia.org/Home.html Kamaelia] message passing concurrency using asynchronous channels 54 | * [http://twistedmatrix.com/trac/ Twisted] event-driven Python programming 55 | * [http://docs.python.org/library/multiprocessing.html Multiprocessing] this is the best support in the current standard library for running forked processes. 56 | 57 | 58 | 59 | = Moving on: a python-csp tutorial = 60 | 61 | The rest of this tutorial assumes that you can already write Python code. If not, read 62 | [http://docs.python.org/tutorial/ The Python Tutorial] before you continue. 63 | 64 | * Beginner: 65 | * TutorialPage0 -- Installing python-csp, tool support 66 | * TutorialPage1 -- Creating and running processes 67 | * [http://code.google.com/p/python-csp/wiki/TutorialPage1#Larger_example:_a_basic_web_server Extended example:] web server 68 | * TutorialPage2 -- Composing processes with Par and Seq 69 | * [http://code.google.com/p/python-csp/wiki/TutorialPage2#A_larger_example:_Word_counts_on_a_whole_directory Extended example:] Parallel word count 70 | * TutorialPage3 -- Communicating between processes with channels 71 | * [http://code.google.com/p/python-csp/wiki/TutorialPage3#A_larger_example:_? Extended example:] Mandelbrot generator 72 | * TutorialPage4 -- Stopping python-csp programs by poisoning channels 73 | * [http://code.google.com/p/python-csp/wiki/TutorialPage4#A_larger_example:_? Extended example:] TODO 74 | * TutorialPage5 -- Choosing between channel reads with Alt 75 | * [http://code.google.com/p/python-csp/wiki/TutorialPage5#A_larger_example:_? Extended example:] TODO 76 | 77 | * Intermediate: 78 | * TutorialPage6 -- Using different channel types 79 | * TutorialPage7 -- Using built-in processes 80 | * [http://code.google.com/p/python-csp/wiki/TutorialPage7#A_larger_example:_? Extended example:] software oscilloscope 81 | * TutorialPage8 -- Design patterns for python-csp programs 82 | * [http://code.google.com/p/python-csp/wiki/TutorialPage8#A_larger_example:_? Extended example:] TODO 83 | 84 | * Advanced: 85 | * TutorialPage9 -- Debugging python-csp programs with extra tool support 86 | * TutorialPage10 -- Reactive (or dataflow) programming with python-csp -------------------------------------------------------------------------------- /rst/TutorialPage0.wiki: -------------------------------------------------------------------------------- 1 | #summary python-csp Tutorial Part 0 2 | #labels Phase-Support,Tutorial 3 | 4 | 5 | 6 | = Downloading and installing python-csp = 7 | 8 | At the moment the only way to obtain python-csp is via the Mercurial 9 | repository, this will change in the next few weeks as we head towards 10 | a full release. Also, python-csp is currently only available on Linux 11 | (although it will likely work for other UNIX variants). 12 | 13 | So, for now to obtain python-csp you need to have 14 | [http://mercurial.selenic.com/ Mercurial] installed, then type this at 15 | the command line to download ("pull" in Mercurial parlance) python-csp 16 | into a new directory called python-csp: 17 | 18 | 19 | {{{ 20 | $ hg clone https://python-csp.googlecode.com/hg/ python-csp 21 | }}} 22 | 23 | Then install python-csp using the usual Python setup protocol: 24 | 25 | {{{ 26 | $ cd python-csp 27 | $ sudo python setup.py install 28 | }}} 29 | 30 | = Tool support = 31 | 32 | "Vanilla" Python comes with an interpreter shell that gives you access to the programming language, built in help, and so on. python-csp comes with a variant of this shell with some additions. To start the shell just type: 33 | 34 | {{{ 35 | $ python-csp 36 | }}} 37 | 38 | at the command line, or, if you are using Gnome, you should have a python-csp entry on your *Applications -> Programming* menu. 39 | 40 | === Command history === 41 | 42 | Unlike the ordinary Python shell, by default the python-csp shell has command history enabled. This means that you can press the "up" or "down" arrows on your keyboard to scroll through the code you have entered into the shell, saving you valuable typing time. 43 | 44 | 45 | === python-csp specific help === 46 | 47 | You can use Python's `help()` function to examine any module, class, function or variable that comes with python-csp, just like you can with any other library. However, the python-csp shell comes with a set of specific documentation that you can access via the `info` command. 48 | 49 | 50 | You can start by typing `info csp` to get general information about the python-csp library, or you can ask for `info` on a specific topic to drill down into the details. Note that `info` is a command and not a function, so you say `info csp` not `info(csp)`. 51 | 52 | Here's an example python-csp shell session: 53 | 54 | {{{ 55 | $ python-csp 56 | 57 | CSP Python (c) 2008. Licensed under the GPL(v2). 58 | Type "info csp" for more information. 59 | Press Ctrl-C to close the CSP channel server. 60 | 61 | >>> info 62 | 63 | *** python-csp: general info *** 64 | 65 | python-csp is an implementation of Hoare's Communicating Sequential 66 | Processes in Python. For specific info on any aspect of CSP, use the 67 | following: 68 | 69 | For info on Skip, type: info skip 70 | For info on channels, type: info channel 71 | For info on Alternative, type: info alt 72 | For info on CSPServer, type: info server 73 | For info on poisoning, type: info poison 74 | For info on built-ins, type: info builtin 75 | For info on Sequence, type: info seq 76 | For info on Timer, type: info timer 77 | For info on Parallel, type: info par 78 | For info on processes, type: info process 79 | 80 | >>> 81 | 82 | }}} 83 | 84 | = Next in the tutorial ... = 85 | 86 | TutorialPage1 -- Creating and running processes -------------------------------------------------------------------------------- /rst/TutorialPage2.wiki: -------------------------------------------------------------------------------- 1 | #summary python-csp Tutorial Part 2 2 | #labels Phase-Support,Tutorial 3 | 4 | 5 | 6 | = Process algebra = 7 | 8 | Just like there are different ways to combine numbers with operators 9 | such as `+`, `-`, `*` and `/`, there are different ways to combine 10 | python-csp processes. Primarily, we can run one process to completion and 11 | 12 | 13 | = Running processes in sequence = 14 | 15 | There are two ways to run processes in sequence. Firstly, given two 16 | (or more) processes you can sequence them with the `>` operator, like this: 17 | 18 | {{{ 19 | >>> @process 20 | ... def foo(n): 21 | ... import time 22 | ... print n 23 | ... time.sleep(0.2) 24 | ... print n + 1 25 | ... time.sleep(0.2) 26 | ... print n + 2 27 | ... 28 | >>> foo(100) > foo(200) > foo(300) 29 | n: 100 30 | n: 101 31 | n: 102 32 | n: 200 33 | n: 201 34 | n: 202 35 | n: 300 36 | n: 301 37 | n: 302 38 | 39 | >>> 40 | >>> 41 | }}} 42 | 43 | Secondly, you can create a `Seq` object which is a sort of CSP process 44 | and start that process manually: 45 | 46 | {{{ 47 | >>> s = Seq(foo(400), foo(500), foo(600)) 48 | >>> s.start() 49 | n: 400 50 | n: 401 51 | n: 402 52 | n: 500 53 | n: 501 54 | n: 502 55 | n: 600 56 | n: 601 57 | n: 602 58 | >>> 59 | }}} 60 | 61 | 62 | 63 | = Parallel processes = 64 | 65 | There are two ways to run processes in parallel. Firstly, given two 66 | (or more) processes you can parallelize them with the `//` operator, like this: 67 | 68 | {{{ 69 | >>> @process 70 | ... def foo(n): 71 | ... import time 72 | ... print n 73 | ... time.sleep(0.2) 74 | ... print n + 1 75 | ... time.sleep(0.2) 76 | ... print n + 2 77 | ... 78 | >>> foo(100) // (foo(200), foo(300)) 79 | n: 100 80 | n: 200 81 | n: 300 82 | n: 101 83 | n: 201 84 | n: 301 85 | n: 102 86 | n: 202 87 | n: 302 88 | 89 | >>> 90 | }}} 91 | 92 | Notice that the // operator is a synthetic sugar that takes a CSPProcess on the left hand side and a sequence of processes on the right hand side. 93 | 94 | Alternatively, you can create a `Par` object which is a sort of CSP 95 | process and start that process manually: 96 | 97 | {{{ 98 | >>> p = Par(foo(100), foo(200), foo(300)) 99 | >>> p.start() 100 | n: 100 101 | n: 200 102 | n: 300 103 | n: 101 104 | n: 201 105 | n: 301 106 | n: 102 107 | n: 202 108 | n: 302 109 | >>> 110 | }}} 111 | 112 | 113 | = Repeated processes = 114 | 115 | If you want to a single process to run to completion many times, you can use the `*` operator: 116 | 117 | {{{ 118 | >>> @process 119 | ... def foo(): 120 | ... print 'hello world!' 121 | ... 122 | >>> foo() * 3 123 | hello world! 124 | hello world! 125 | hello world! 126 | >>> 127 | }}} 128 | 129 | 130 | You can also say 131 | 132 | {{{ 133 | 3 * foo() 134 | }}} 135 | 136 | with the same effect. 137 | 138 | = A larger example: Word counts on a whole directory = 139 | 140 | In this example we will use `Par` to concurrently process all files in 141 | a directory and print out their word counts. We just need two sorts of 142 | processes for this, one which counts all the words in a single file, 143 | and another which finds all the files in a given directory and runs 144 | the word count process on them. The first process is simple: 145 | 146 | {{{ 147 | @process 148 | def word_count(filename): 149 | fd = file(filename) 150 | words = [line.split() for line in fd] 151 | fd.close() 152 | print '%s contains %i words.' % (filename, len(words)) 153 | }}} 154 | 155 | 156 | The second process is a bit more complicated. We want to know about 157 | every file in the given directory, but we don't want to know about 158 | directories and other things that aren't really files, so we need a 159 | bit of logic to do that. After that, we just need to use `Par` to 160 | process all our files in parallel: 161 | 162 | {{{ 163 | @process 164 | def directory_count(path): 165 | import glob 166 | import os.path 167 | import sys 168 | # Test if directory exists 169 | if not os.path.exists(path): 170 | print '%s does not exist. Exiting.' % path 171 | sys.exit(1) 172 | # Get all filenames in directory 173 | paths = glob.glob(path + '/*') 174 | files = [path for path in paths if not os.path.isdir(path) and os.path.isfile(path)] 175 | procs = [word_count(fd) for fd in files] 176 | Par(*procs).start() 177 | }}} 178 | 179 | 180 | This program gives output like this: 181 | 182 | {{{ 183 | $ python tutorial/part02/filecount.py . 184 | ./setup.py contains 37 words. 185 | ./MANIFEST.in contains 6 words. 186 | ./maketags.sh contains 3 words. 187 | ./setup.cfg contains 3 words. 188 | ./LICENSE contains 339 words. 189 | ./ChangeLog contains 40 words. 190 | ./Makefile contains 91 words. 191 | ./make.bat contains 112 words. 192 | ./TAGS contains 954 words. 193 | ./BUCKETS.pdf contains 616 words. 194 | ./README.html contains 92 words. 195 | ./README contains 72 words. 196 | $ 197 | }}} 198 | 199 | This is a rather simplistic example for a couple of reasons. In most 200 | concurrent or parallel programming you really need processes to pass 201 | data between themselves. For example, a more sophisticated version of 202 | our program would have `word_count` processes and pass their word 203 | counts to a separate process which would print everything to the 204 | console. This relies on the operating system to print each line of our 205 | output separately, even though the processes who are printing are 206 | running concurrently and might interfere with each other. We will 207 | learn how to pass messages between processes and improve this code in 208 | TutorialPage3. 209 | 210 | 211 | = Exercises = 212 | 213 | WRITEME! 214 | 215 | 216 | = Next in the tutorial ... = 217 | 218 | TutorialPage3 -- Communicating between processes with channels -------------------------------------------------------------------------------- /rst/TutorialPage4.wiki: -------------------------------------------------------------------------------- 1 | #summary python-csp Tutorial Part 4 2 | #labels Phase-Support,Tutorial 3 | 4 | 5 | 6 | = Poisoning channels and terminating processes = 7 | 8 | A set of communicating processes can be terminated by "poisoning" any 9 | of the channels used by those processes. This can be achieved by 10 | calling the `poison()` method on any channel. For example: 11 | 12 | {{{ 13 | >>> import time 14 | >>> import random 15 | >>> @process 16 | ... def send5(cout): 17 | ... for i in xrange(5): 18 | ... print 'send5 sending:', i 19 | ... cout.write(i) 20 | ... time.sleep(random.random() * 5) 21 | ... return 22 | ... 23 | >>> @process 24 | ... def recv(cin): 25 | ... for i in xrange(5): 26 | ... data = cin.read() 27 | ... print 'recv got:', data 28 | ... time.sleep(random.random() * 5) 29 | ... return 30 | ... 31 | >>> @process 32 | ... def interrupt(chan): 33 | ... time.sleep(random.random() * 7) 34 | ... print 'Poisoning channel:', chan.name 35 | ... chan.poison() 36 | ... return 37 | ... 38 | >>> doomed = Channel() 39 | >>> Par(send5(doomed), recv(doomed), interrupt(doomed)).start() 40 | send5 sending: 0 41 | recv got: 0 42 | send5 sending: 1 43 | recv got: 1 44 | send5 sending: 2 45 | recv got: 2 46 | send5 sending: 3 47 | recv got: 3 48 | Poisoning channel: 5c906e38-5559-11df-8503-002421449824 49 | send5 sending: 4 50 | >>> 51 | }}} 52 | 53 | = A larger example: = 54 | The second example tries to demonstrate the poisoning of all channels that are related to primary channel. In this case merchant is watching what customers are going to send and merchant's wife is watching what customer's children are going to send. 55 | 56 | {{{ 57 | import time 58 | import random 59 | @process 60 | def customer_child(cchildout, n): 61 | for i in xrange(3): 62 | print "Customer's "+str(n)+" child sending "+str(i) 63 | cchildout.write(i) 64 | time.sleep(random.random() * 3) 65 | return 66 | 67 | @process 68 | def customer(cparentout, cchildout, n): 69 | for i in xrange(5): 70 | print 'Customer '+str(n)+" sending "+str(i) 71 | Par(customer_child(cchildout, n)).start() 72 | cparentout.write(i) 73 | time.sleep(random.random() * 5) 74 | return 75 | 76 | @process 77 | def merchant(cin): 78 | for i in xrange(15): 79 | data = cin.read() 80 | print 'Merchant got:', data 81 | time.sleep(random.random() * 5) 82 | return 83 | 84 | @process 85 | def merchantswife(cin): 86 | for i in xrange(15): 87 | data = cin.read() 88 | print "Merchant's wife got: ", data 89 | time.sleep(random.random() * 4) 90 | return 91 | 92 | @process 93 | def terminator(chan): 94 | time.sleep(10) 95 | print 'Terminator is killing channel:', chan.name 96 | chan.poison() 97 | return 98 | 99 | doomed = Channel() 100 | doomed_children = Channel() 101 | Par(customer(doomed, doomed_children, 1),\ 102 | merchant(doomed), \ 103 | merchantswife(doomed_children), \ 104 | customer(doomed, doomed_children, 2), \ 105 | customer(doomed, doomed_children, 3), \ 106 | terminator(doomed)).start() 107 | }}} 108 | = Exercises = 109 | 110 | Writeme! 111 | 112 | = Next in the tutorial ... = 113 | 114 | TutorialPage5 -- Choosing between channel reads with Alt -------------------------------------------------------------------------------- /rst/TutorialPage5.wiki: -------------------------------------------------------------------------------- 1 | #summary python-csp Tutorial Part 5 2 | #labels Phase-Support,Tutorial 3 | 4 | 5 | 6 | = Choosing between channel reads with Alt = 7 | 8 | python-csp process will often have access to several different channels, or other guard types such as timer guards, and will have to choose one of them to read from. For example, in a producer/consumer or worker/farmer model, many producer or worker processes will be writing values to channels and one consumer or farmer process will be aggregating them in some way. It would be inefficient for the consumer or farmer to read from each channel in turn, as some channels might take longer than others. Instead, python-csp provides support for ALTing (or ALTernating), which enables a process to read from the first channel (or timer, or other guard) in a list to become ready. 9 | 10 | == Using the choice operator == 11 | 12 | The simplest way to choose between channels (or other guards) is to use choice operator: `|`, as in the example below: 13 | 14 | {{{ 15 | >>> @process 16 | ... def send_msg(chan, msg): 17 | ... chan.write(msg) 18 | ... 19 | >>> @process 20 | ... def choice(chan1, chan2): 21 | ... # Choice chooses a channel on which to call read() 22 | ... print chan1 | chan2 23 | ... print chan1 | chan2 24 | ... 25 | >>> c1, c2 = Channel(), Channel() 26 | >>> choice(c1, c2) // (send_msg(c1, 'yes'), send_msg(c2, 'no')) 27 | yes 28 | no 29 | 30 | >>> 31 | }}} 32 | 33 | == Alt objects == 34 | 35 | Secondly, you can create an `Alt` object explicitly, and call its `select()` method to perform a channel read on the next available channel. If more than one channel is available to read from, then an available channel is chosen at random (for this reason, ALTing is sometimes called "non-deterministic choice": 36 | 37 | {{{ 38 | >>> @process 39 | ... def send_msg(chan, msg): 40 | ... chan.write(msg) 41 | ... 42 | >>> @process 43 | ... def alt_example(chan1, chan2): 44 | ... alt = Alt(chan1, chan2) 45 | ... print alt.select() 46 | ... print alt.select() 47 | ... 48 | >>> c1, c2 = Channel(), Channel() 49 | >>> Par(send_msg(c1, 'yes'), send_msg(c2, 'no'), alt_example(c1, c2)).start() 50 | yes 51 | no 52 | >>> 53 | }}} 54 | 55 | == Alternatives to the select method == 56 | 57 | In addition to the `select()` method, which chooses an available guard at random, `Alt` provides two similar methods, `fair_select()` and `pri_select()`. `fair_select()` will choose not to select the previously selected guard, unless it is the only guard available. This ensures that no guard will be starved twice in a row. `pri_select()` will select available channels in the order in which they were passed to the `Alt()` constructor, giving a simple implementation of guard priority. 58 | 59 | Lastly, `Alt()` can be used with the repetition operator `*` to create a generator: 60 | 61 | {{{ 62 | >>> @process 63 | ... def send_msg(chan, msg): 64 | ... chan.write(msg) 65 | ... 66 | >>> @process 67 | ... def gen_example(chan1, chan2): 68 | ... gen = Alt(chan1, chan2) * 2 69 | ... print gen.next() 70 | ... print gen.next() 71 | ... 72 | >>> c1, c2 = Channel(), Channel() 73 | >>> Par(send_msg(c1, 'yes'), send_msg(c2, 'no'), gen_example(c1, c2)).start() 74 | yes 75 | no 76 | >>> 77 | }}} 78 | 79 | 80 | = Fixing the Mandelbrot generator = 81 | 82 | In TutorialPage3 we described a producer / consumer architecture for 83 | generating pictures of the Mandelbrot set. There, we used a crude 84 | `for` loop for the consumer process to iterate over input channels and 85 | read from them. We can now improve this code and, usint `Alt`, make 86 | sure that channel reads are serviced when the reads are ready to 87 | complete: 88 | 89 | 90 | {{{ 91 | @process 92 | def consume(size, cins): 93 | # Set-up PyGame. 94 | pixmap = ... # Blit buffer. 95 | gen = len(cins) * Alt(*cins) 96 | for i in range(len(cins)): 97 | xcoord, column = gen.next() 98 | # Update column of blit buffer 99 | pixmap[xcoord] = column 100 | # Update image on screen. 101 | }}} 102 | 103 | 104 | 105 | = A larger example: ? = 106 | 107 | Writeme! 108 | 109 | = Exercises = 110 | 111 | Writeme! 112 | 113 | = Next in the tutorial ... = 114 | 115 | TutorialPage6 -- Using different channel types -------------------------------------------------------------------------------- /rst/TutorialPage7.wiki: -------------------------------------------------------------------------------- 1 | #summary python-csp Tutorial Part 7 2 | #labels Phase-Support,Tutorial 3 | 4 | 5 | 6 | = Builtin guards = 7 | 8 | So far, we have only used channels to `read()` and `write()` from/to 9 | and pass to `Alt` objects. Other objects can be used in these ways 10 | too, and in CSP these sorts of objects are all called _guards_. The 11 | modules `csp.guards` and `csp.builtins` contain a number of basic 12 | guards and processes which can be used as building blocks for larger 13 | programs. These are largely based on a similar library in JCSP called 14 | "plugNplay" and can be useful for quickly bootstraping programs. 15 | 16 | It is best to import the modules and look through their documentation, 17 | but this tutorial page covers a few of the more useful or unusual 18 | builtins with some examples. 19 | 20 | 21 | == Timer == 22 | 23 | Guard which only commits to synchronisation when a timer has 24 | expired. A `Timer` can also be used to _sleep_ a process without 25 | importing the Python `time` module. For example: 26 | 27 | {{{ 28 | from csp.builtins import Timer 29 | from csp.csp import * 30 | 31 | @process 32 | def foobar(): 33 | timer = Timer() 34 | print '1, 2, 3, 4, ...' 35 | timer.sleep(2) # 2 seconds. 36 | print '5' 37 | }}} 38 | 39 | 40 | To use a timer to execute code after a specified amount of time you 41 | need to set it's `alarm` to trigger after a number of seconds and then 42 | pass the timer to an `Alt`. The `Alt` will be able to select the timer 43 | when it's alarm has triggered, like this: 44 | 45 | {{{ 46 | from csp.builtins import Timer 47 | from csp.csp import * 48 | 49 | @process 50 | def foobar(): 51 | timer = Timer() 52 | alt = Alt(timer) 53 | timer.set_alarm(5) 54 | alt.select() # Wait 5 seconds here. 55 | print '5 seconds is up!' 56 | }}} 57 | 58 | 59 | == Skip == 60 | 61 | Guard which will always return `True`. Useful in `Alt`s where the 62 | programmer wants to ensure that `Alt.select` will always synchronise 63 | with at least one guard. 64 | 65 | 66 | = Builtin processes = 67 | 68 | 69 | 70 | 71 | == Documentation for (some) builtins == 72 | 73 | 74 | == Skip == 75 | 76 | As well as being a guard, Skip can be used as a process which does 77 | nothing. Think of it as the CSP equivalent of `None`: 78 | 79 | {{{ 80 | >>> Skip().start() 81 | >>> 82 | }}} 83 | 84 | 85 | === Blackhole === 86 | Read values from `cin` and do nothing with them. 87 | 88 | 89 | === Clock === 90 | Send `None` object down output channel every `resolution` seconds. 91 | 92 | 93 | === Generate === 94 | 95 | Generate successive (+ve) `int`s and write to `cout`. There is a 96 | similar process with the signature `GenerateFloats(outchan, 97 | epsilon=0.1)` which generates `float`s rather than `int`s. The 98 | argument `epsilon` says how far apart each floating point number 99 | should be. So the call `GenerateFloats(outchan, epsilon=0.1)' will 100 | write the numbers 0.1, 0.2, 0.3, ... down the channel `outchan`. 101 | 102 | 103 | === Mux2 === 104 | 105 | Mux2 provides a fair multiplex between two input channels. 106 | 107 | === Printer === 108 | 109 | Print all values read from `cin` to standard out or `out`. 110 | 111 | === Zeroes === 112 | 113 | Writes out a stream of zeroes. 114 | 115 | 116 | = Larger examlple: a basic oscilloscope = 117 | 118 | http://python-csp.googlecode.com/hg/tutorial/part07/Oscilloscope.png 119 | 120 | The full code for the oscilloscope can be found here: http://python-csp.googlecode.com/hg/tutorial/part07/oscilloscope.py . You will also need the traces code, here http://python-csp.googlecode.com/hg/tutorial/part07/traces.py . 121 | 122 | 123 | 124 | = Next in the tutorial ... = 125 | 126 | TutorialPage8 -- Design patterns for python-csp programs -------------------------------------------------------------------------------- /rst/TutorialPage8.wiki: -------------------------------------------------------------------------------- 1 | #summary python-csp Tutorial Part 8 2 | #labels Phase-Support,Tutorial 3 | 4 | 5 | 6 | = Design patterns in python-csp = 7 | 8 | == Client-server pattern == 9 | 10 | === Client-server example === 11 | 12 | 13 | == Token ring pattern == 14 | 15 | === Token ring example === 16 | 17 | == Reactive programming pattern == 18 | 19 | === Reactive programming example === 20 | -------------------------------------------------------------------------------- /rst/builtins.rst: -------------------------------------------------------------------------------- 1 | Pre-built proceses 2 | ================== 3 | 4 | .. automodule:: csp.builtins 5 | :members: 6 | 7 | .. 8 | 9 | * :ref:`genindex` 10 | * :ref:`modindex` 11 | * :ref:`search` 12 | 13 | -------------------------------------------------------------------------------- /rst/csp.rst: -------------------------------------------------------------------------------- 1 | Core CSP library. 2 | ================= 3 | 4 | .. automodule:: csp.csp 5 | :members: 6 | 7 | .. 8 | 9 | * :ref:`genindex` 10 | * :ref:`modindex` 11 | * :ref:`search` 12 | 13 | -------------------------------------------------------------------------------- /rst/guards.rst: -------------------------------------------------------------------------------- 1 | Prebuilt synchronisation primitives. 2 | ==================================== 3 | 4 | .. automodule:: csp.guards 5 | :members: 6 | 7 | .. 8 | 9 | 10 | * :ref:`genindex` 11 | * :ref:`modindex` 12 | * :ref:`search` 13 | 14 | -------------------------------------------------------------------------------- /rst/index.rst: -------------------------------------------------------------------------------- 1 | .. python-csp documentation master file, created by 2 | sphinx-quickstart on Sat Apr 10 00:03:15 2010. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to python-csp's documentation! 7 | ====================================== 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | csp.rst 15 | builtins.rst 16 | guards.rst 17 | patterns.rst 18 | mandelbrot.rst 19 | 20 | 21 | .. 22 | 23 | Indices and tables 24 | ================== 25 | 26 | * :ref:`genindex` 27 | * :ref:`modindex` 28 | * :ref:`search` 29 | 30 | -------------------------------------------------------------------------------- /rst/mandelbrot.rst: -------------------------------------------------------------------------------- 1 | Mandelbrot example 2 | ================== 3 | 4 | .. automodule:: mandelbrot 5 | :members: 6 | 7 | .. 8 | 9 | * :ref:`genindex` 10 | * :ref:`modindex` 11 | * :ref:`search` 12 | 13 | -------------------------------------------------------------------------------- /rst/patterns.rst: -------------------------------------------------------------------------------- 1 | Design patterns for automatically wiring process graphs 2 | ======================================================= 3 | 4 | .. automodule:: csp.patterns 5 | :members: 6 | 7 | .. 8 | 9 | 10 | * :ref:`genindex` 11 | * :ref:`modindex` 12 | * :ref:`search` 13 | 14 | -------------------------------------------------------------------------------- /scripts/cspdb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Debugger for the pyyhon-csp library. 5 | 6 | Copyright (C) Sarah Mount, 2010. 7 | 8 | This program is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU General Public License 10 | as published by the Free Software Foundation; either version 2 11 | of the License, or (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have rceeived a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | 22 | __author__ = 'Sarah Mount ' 23 | __date__ = 'May 2010' 24 | 25 | import sys 26 | 27 | import csp.tracer.tracer as tracer 28 | 29 | from optparse import OptionParser 30 | 31 | parser = OptionParser() 32 | 33 | parser.add_option('-p', '--prog', dest='program', 34 | action='store', 35 | help='Program to be debugged') 36 | 37 | parser.add_option('-a', '--all', dest='all', 38 | action='store_true', 39 | help='Provide all available debugging information') 40 | 41 | parser.add_option('-m', '--model', dest='model', 42 | action='store_true', 43 | help='Provide a CSP_M model of PROGRAM, suitable for use with the FDR2 model checker') 44 | 45 | parser.add_option('-g', '--graph', dest='graph', 46 | action='store_true', 47 | help='Provide (as a PNG) a graph of the processes and guards created by PROGRAM') 48 | 49 | parser.add_option('-t', '--trace', dest='trace', 50 | action='store_true', 51 | help='Provide a Hoare-style CSP trace of PROGRAM') 52 | 53 | parser.add_option('-v', '--vcr', dest='vcr', 54 | action='store_true', 55 | help='Provide a view-centric reasoning trace of PROGRAM') 56 | 57 | parser.add_option('-s', '--struct', dest='struct', 58 | action='store_true', 59 | help='Provide a structural trace of PROGRAM') 60 | 61 | 62 | def create_icode(): 63 | """Create an ICODE model of the given program. 64 | """ 65 | raise NotImplementedError('ICODE models not yet implemented') 66 | 67 | 68 | def create_model(icode): 69 | """Create a CSP_M model of the given program 70 | """ 71 | raise NotImplementedError('CSP_M models not yet implemented') 72 | 73 | 74 | def create_graph(icode): 75 | """Create a process graph of the given program 76 | """ 77 | raise NotImplementedError('Process graphs not yet implemented') 78 | 79 | 80 | def create_trace(icode): 81 | """Create an CSP trace of the given program. 82 | """ 83 | raise NotImplementedError('CSP traces not yet implemented') 84 | 85 | 86 | def create_vcr(icode): 87 | """Create an VCR trace of the given program. 88 | """ 89 | raise NotImplementedError('VCR traces not yet implemented') 90 | 91 | 92 | def create_struct(icode): 93 | """Create a structural trace of the given program. 94 | """ 95 | raise NotImplementedError('ICODE models not yet implemented') 96 | 97 | 98 | if __name__ == '__main__': 99 | (options, args) = parser.parse_args() 100 | 101 | if options.program: 102 | with tracer.csptrace(): 103 | exec(compile(open(options.program).read(), options.program, 'exec')) 104 | else: 105 | parser.print_help() 106 | 107 | if options.all: 108 | icode = create_icode() 109 | create_model(icode) 110 | create_graph(icode) 111 | create_trace(icode) 112 | create_vcr(icode) 113 | create_struct(icode) 114 | sys.exit() 115 | 116 | if options.model: create_model(icode) 117 | if options.graph: create_graph(icode) 118 | if options.trace: create_trace(icode) 119 | if options.vcr: create_vcr(icode) 120 | if options.struct: create_struct(icode) 121 | 122 | -------------------------------------------------------------------------------- /scripts/csplint: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from optparse import OptionParser 4 | 5 | import csp.lint.lint 6 | 7 | import sys 8 | 9 | parser = OptionParser() 10 | 11 | parser.add_option('-l', '--list', dest='listall', 12 | action='store_true', 13 | help='List all error messages and exit') 14 | 15 | parser.add_option('-p', '--prog', dest='program', 16 | action='store', 17 | help='Program to be statically checked') 18 | 19 | parser.add_option('-x', '--exclude', dest='excluded', 20 | action='store', 21 | help='Comma-separated list of error codes to exclude.') 22 | 23 | 24 | if __name__ == '__main__': 25 | import exstatic.cspwarnings 26 | 27 | (options, args) = parser.parse_args() 28 | 29 | if options.listall: 30 | exstatic.cspwarnings.list_error_codes() 31 | sys.exit() 32 | 33 | # Deal with the list of excluded error codes, if used. 34 | ex_list = [] 35 | if options.excluded: 36 | ex_list = options.excluded.strip().split(',') 37 | 38 | if options.program: 39 | csp.lint.lint.run(options.program, excluded=ex_list) 40 | else: 41 | parser.print_help() 42 | 43 | -------------------------------------------------------------------------------- /scripts/python-csp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """Interactive interpreter for python-csp, with online help. 4 | 5 | Features: 6 | * CSP primitives are imported automatically. 7 | * History is saved between sessions in C{~/.csp-console-history}. 8 | * Tab-completion can be used to complete keywords or variables. 9 | 10 | Copyright (C) Sarah Mount, 2009. 11 | 12 | This program is free software; you can redistribute it and/or 13 | modify it under the terms of the GNU General Public License 14 | as published by the Free Software Foundation; either version 2 15 | of the License, or (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU General Public License for more details. 21 | 22 | You should have received a copy of the GNU General Public License 23 | along with this program; if not, write to the Free Software 24 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 25 | """ 26 | 27 | try: 28 | import readline 29 | except ImportError: 30 | print("Module readline not available.") 31 | else: 32 | import rlcompleter 33 | readline.parse_and_bind("tab: complete") 34 | 35 | import atexit 36 | import code 37 | import os 38 | import sys 39 | 40 | 41 | __author__ = 'Sarah Mount ' 42 | __date__ = 'December 2008' 43 | 44 | 45 | class _Printer(object): 46 | """Print documentation in twenty-line chunks. 47 | 48 | Based on a class of the same name from the site.py module. 49 | """ 50 | MAXLINES = 20 51 | def __init__(self, documentation): 52 | self.__lines = documentation.split('\n') 53 | self.__linecnt = len(self.__lines) 54 | 55 | def __call__(self): 56 | prompt = '\n*** Hit Return for more, or q (and Return) to quit: ' 57 | lineno = 0 58 | while True: 59 | try: 60 | for i in range(lineno, lineno + self.MAXLINES): 61 | print(self.__lines[i]) 62 | except IndexError: 63 | break 64 | else: 65 | lineno += self.MAXLINES 66 | key = None 67 | while key not in ('', 'q', 'Q'): 68 | key = input(prompt) 69 | if key == 'q': 70 | break 71 | print() 72 | 73 | 74 | class TabSafeCompleter(rlcompleter.Completer): 75 | """Enable safe use of Tab for either tab completion or nested scope. 76 | """ 77 | def complete(self, text, state): 78 | if text == '': 79 | return ['\t', None][state] 80 | else: 81 | return rlcompleter.Completer.complete(self, text, state) 82 | 83 | 84 | class CSPConsole(code.InteractiveConsole): 85 | """python-csp interactive console with REPL. 86 | 87 | Features: 88 | * CSP channel server is started automatically. 89 | * CSP primitives are imported automatically. 90 | * History is saved between sessions in C{~/.csp-console-history}. 91 | * Tab-completion can be used to complete keywords or variables. 92 | """ 93 | 94 | # From the docs of the readline module. 95 | def __init__(self, locals=None, filename="", 96 | histfile=os.path.expanduser("~/.csp-console-history")): 97 | code.InteractiveConsole.__init__(self) 98 | self.init_history(histfile) 99 | 100 | def init_history(self, histfile): 101 | readline.parse_and_bind("tab: complete") 102 | delims = ' \t\n`!@#$%^&*()-=+[{]}\\|;:,<>?' 103 | readline.set_completer_delims(delims) 104 | readline.set_completer(TabSafeCompleter().complete) 105 | if hasattr(readline, "read_history_file"): 106 | try: 107 | readline.read_history_file(histfile) 108 | except IOError: 109 | pass 110 | atexit.register(self.save_history, histfile) 111 | 112 | def save_history(self, histfile): 113 | readline.write_history_file(histfile) 114 | 115 | def raw_input(self, *args): 116 | return code.InteractiveConsole.raw_input(self, *args) 117 | 118 | 119 | _ban = "\npython-csp (c) 2008. Licensed under the GPL(v2).\n\n" 120 | 121 | 122 | if __name__ == '__main__': 123 | c = CSPConsole(locals=locals()) 124 | # Don't expect the csp types to be available in locals() 125 | c.push('from csp.csp import *') 126 | c.push('from csp.builtins import *') 127 | c.push('from csp.guards import *') 128 | c.interact(banner=_ban) 129 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [egg_info] 2 | tag_build = dev 3 | tag_svn_revision = true 4 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from setuptools import setup, find_packages 4 | 5 | version = '0.1' 6 | 7 | setup(name='python-csp', 8 | version=version, 9 | description="Communicating sequential processes for Python", 10 | long_description="""\ 11 | python-csp adds communicating sequential processes to Python""", 12 | classifiers=["Intended Audience :: Developers", 13 | "License :: OSI Approved :: GNU General Public License (GPL)", 14 | "Programming Language :: Python", 15 | "Topic :: Software Development :: Libraries", 16 | "Topic :: System :: Distributed Computing"], 17 | keywords='concurrency multicore parallel', 18 | author='Sarah Mount', 19 | author_email='s.mount@wlv.ac.uk', 20 | url='http://code.google.com/p/python-csp/', 21 | license='GPL', 22 | packages=find_packages(exclude=['ez_setup', 'examples', 'tests', 23 | 'reactive', 'applications', 'benchmark', 24 | 'jythonsetup', 'logo', 'rst', 'scripts', 25 | 'test', 'tutorial']), 26 | include_package_data=True, 27 | zip_safe=True, 28 | scripts=['scripts/python-csp', 29 | 'scripts/csplint', 30 | 'scripts/cspdb'], 31 | install_requires=[ 32 | # -*- Extra requirements: -*- 33 | ], 34 | entry_points=""" 35 | # -*- Entry points: -*- 36 | """, 37 | ) 38 | -------------------------------------------------------------------------------- /test/test_contexts.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Test the CSP class, found in csp.csp and its context managers. 5 | 6 | TODO: Replace this with proper unit testing. 7 | 8 | Copyright (C) Sarah Mount, 2010. 9 | 10 | This program is free software; you can redistribute it and/or 11 | modify it under the terms of the GNU General Public License 12 | as published by the Free Software Foundation; either version 2 13 | of the License, or (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with this program. If not, see . 22 | """ 23 | 24 | import sys 25 | 26 | sys.path.insert(0, "..") 27 | 28 | from csp.csp import CSP 29 | 30 | 31 | def printme(*args): 32 | print ' '.join(map(lambda x: str(x), args)) 33 | 34 | 35 | def testme1(): 36 | p = CSP() 37 | with p.par(): 38 | p.process(printme, 1, 2, 3, 4, 5) 39 | p.process(printme, 6, 7, 7, 8, 9) 40 | p.process(printme, 2, 3, 6, 3, 2) 41 | p.start() 42 | 43 | 44 | def testme2(): 45 | p = CSP() 46 | with p.seq(): 47 | p.process(printme, 1, 2, 3) 48 | with p.par(): 49 | p.process(printme, 1) 50 | p.process(printme, 2) 51 | p.process(printme, 3) 52 | p.process(printme, 5, 6, 7) 53 | p.start() 54 | 55 | 56 | if __name__ == '__main__': 57 | print 'Test 1' 58 | testme1() 59 | print 'Test 2' 60 | testme2() 61 | 62 | -------------------------------------------------------------------------------- /test/test_forever.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Test the @forever process decorator which creates server processes. 5 | 6 | Copyright (C) Sarah Mount, 2010. 7 | 8 | This program is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU General Public License 10 | as published by the Free Software Foundation; either version 2 11 | of the License, or (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have rceeived a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | 22 | import operator 23 | import os 24 | import sys 25 | 26 | from functools import reduce 27 | 28 | sys.path.insert(0, "..") 29 | 30 | from csp.csp import * 31 | from csp.builtins import Generate, Printer 32 | 33 | 34 | def test_builtins(): 35 | channel, skip = Channel(), Skip() 36 | skip //= Generate(channel), Printer(channel) 37 | 38 | 39 | @forever 40 | def fact(outchan): 41 | """ 42 | readset = flibble, foo 43 | writeset = outchan, foo 44 | """ 45 | n = 1 46 | f = 1 47 | while True: 48 | if n == 1: 49 | outchan.write(1) 50 | else: 51 | f = reduce(operator.mul, list(range(1, n))) 52 | outchan.write(f) 53 | n += 1 54 | yield 55 | 56 | def test_fact(): 57 | channel, skip = Channel(), Skip() 58 | skip //= fact(channel), Printer(channel) 59 | 60 | if __name__ == '__main__': 61 | # test_builtins() 62 | test_fact() 63 | -------------------------------------------------------------------------------- /test/test_tracer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Test the new python-csp tracer. 5 | 6 | Includes regular and server processes and ALTing. 7 | """ 8 | 9 | __author__ = 'Sarah Mount ' 10 | __date__ = 'May 2010' 11 | 12 | import sys 13 | 14 | sys.path.insert(0, "..") 15 | 16 | from csp.csp import * 17 | from csp.guards import Skip 18 | 19 | ch = Channel() 20 | 21 | @process 22 | def client(inchan): 23 | """ 24 | readset = inchan 25 | writeset = 26 | """ 27 | print(inchan.read()) 28 | return 29 | 30 | 31 | @process 32 | def foo(outchan, msg): 33 | """ 34 | readset = 35 | writeset = outchan 36 | """ 37 | outchan.write(msg) 38 | return 39 | 40 | 41 | @process 42 | def alt3(inchan1, inchan2, inchan3): 43 | """ 44 | readset = inchan1, inchan2, inchan3 45 | writeset = 46 | """ 47 | alt = Alt(inchan1, inchan2, inchan3, Skip()) 48 | selects = 0 49 | while selects < 3: 50 | val = alt.select() 51 | if val != 'Skip': 52 | selects += 1 53 | print(val) 54 | return 55 | 56 | 57 | @process 58 | def simple(): 59 | print('SIMPLES') 60 | return 61 | 62 | 63 | @forever 64 | def server(): 65 | while True: 66 | print('server process') 67 | yield 68 | return 69 | 70 | 71 | @forever 72 | def server_write(outchan): 73 | """ 74 | readset = 75 | writeset = outchan 76 | """ 77 | while True: 78 | outchan.write('Hello server') 79 | yield 80 | return 81 | 82 | 83 | @forever 84 | def server_read(inchan): 85 | """ 86 | readset = inchan 87 | writeset = 88 | """ 89 | while True: 90 | print(inchan.read()) 91 | yield 92 | return 93 | 94 | 95 | if __name__ == '__main__': 96 | from csp.tracer.tracer import csptrace 97 | with csptrace(): 98 | chan, skip = Channel(), Skip() 99 | skip //= foo(chan, 'hello world!'), client(chan) 100 | Par(foo(chan, 1243), client(chan)).start() 101 | chan1, chan2, chan3 = Channel(), Channel(), Channel() 102 | Par(foo(chan1, 1), 103 | foo(chan2, 2), 104 | foo(chan3, 3), 105 | alt3(chan1, chan2, chan3)).start() 106 | simple().start() 107 | server().start() 108 | chan_s, skip = Channel(), Skip() 109 | skip //= server_read(chan_s), server_write(chan_s) 110 | 111 | -------------------------------------------------------------------------------- /test/testpar.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | 5 | sys.path.insert(0, "..") 6 | 7 | from csp.csp import * 8 | from csp.builtins import Generate, Plus, Printer 9 | 10 | in1, in2, out = Channel(), Channel(), Channel() 11 | 12 | @process 13 | def foo(): 14 | # Previously deadlocked 15 | Skip() // (Generate(in1), Generate(in2), Plus(in1, in2, out), Printer(out)) 16 | 17 | 18 | # Infinite stream of ints (OK) 19 | #p = Skip() 20 | #p //= [Generate(out), Printer(out)] 21 | 22 | @process 23 | def bar(): 24 | # Infinite stream of even ints (OK) 25 | Par(Generate(in1), Generate(in2), Plus(in1, in2, out), Printer(out)).start() 26 | 27 | 28 | #PAR //= [Generate(in1), Generate(in2), Plus(in1, in2, out), Printer(out)] 29 | 30 | if __name__ == '__main__': 31 | Generate(out) // (Printer(out),) 32 | # 33 | # bar().start() 34 | # foo().start() 35 | -------------------------------------------------------------------------------- /test/testrep.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | sys.path.insert(0, "..") 4 | 5 | from csp.csp import * 6 | from csp.guards import Timer 7 | 8 | @process 9 | def hello(): 10 | t = Timer() 11 | for i in range(5): 12 | print i 13 | t.sleep(1) 14 | 15 | if __name__ == '__main__': 16 | hello() * 3 17 | 2 * hello() 18 | -------------------------------------------------------------------------------- /test/testsock.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | HOST = socket.gethostbyname(socket.gethostname()) 4 | 5 | PORT = 8887 6 | data = 'flibble' 7 | 8 | # sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 9 | 10 | # # Connect to server and send data 11 | # sock.connect((HOST, PORT)) 12 | # sock.send(data + "\n") 13 | 14 | # # Receive data from the server and shut down 15 | # received = sock.recv(1024) 16 | # sock.close() 17 | 18 | 19 | 20 | # SOCK_DGRAM is the socket type to use for UDP sockets 21 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 22 | sock.sendto(data + "\n", (HOST, PORT)) 23 | received = sock.recv(1024) 24 | 25 | print("Sent: {0}".format(data)) 26 | print("Received: {0}".format(received)) 27 | -------------------------------------------------------------------------------- /test/winder_bug/pi_python_python-csp_multiple_nested_deep.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- mode:python; coding:utf-8; -*- 3 | 4 | # Calculation of Pi using quadrature. Using the python-csp package by Sarah Mount. 5 | # 6 | # Copyright © 2009-10 Russel Winder 7 | 8 | import time 9 | import multiprocessing 10 | 11 | import sys 12 | sys.path.insert(0, "../..") 13 | 14 | from csp.csp import * 15 | 16 | def execute ( processCount ) : 17 | n = 10#0000000 # 100 times fewer due to speed issues. 18 | delta = 1.0 / n 19 | startTime = time.time ( ) 20 | slice = n / processCount 21 | channels = [ ] 22 | @process 23 | def accumulator ( ) : 24 | """ 25 | readset = channel 26 | writeset = 27 | """ 28 | pi = 4.0 * sum ( [ channel.read ( ) for channel in channels ] ) * delta 29 | elapseTime = time.time ( ) - startTime 30 | print ( "==== Python CSP Multiple NestedDeep pi = " + str ( pi ) ) 31 | print ( "==== Python CSP Multiple NestedDeep iteration count = " + str ( n ) ) 32 | print ( "==== Python CSP Multiple NestedDeep elapse = " + str ( elapseTime ) ) 33 | print ( "==== Python CSP Multiple NestedDeep process count = " + str ( processCount ) ) 34 | print ( "==== Python CSP Multiple NestedDeep processor count = " + str ( multiprocessing.cpu_count ( ) ) ) 35 | processes = [ ] 36 | for i in range ( 0 , processCount ) : 37 | channel = Channel ( ) 38 | channels.append ( channel ) 39 | @process 40 | def calculator ( channel ) : 41 | """ 42 | readset = 43 | writeset = channel 44 | """ 45 | sum = 0.0 46 | for j in range ( 1 + i * slice , ( i + 1 ) * slice ) : 47 | x = ( j - 0.5 ) * delta 48 | sum += 1.0 / ( 1.0 + x * x ) 49 | channel.write ( sum ) 50 | processes.append ( calculator (channels[i] ) ) 51 | processes.append ( accumulator ( ) ) 52 | Par ( *processes ).start ( ) 53 | 54 | if __name__ == '__main__' : 55 | import gc 56 | gc.set_debug(True) 57 | execute ( 1 ) 58 | print ( ) 59 | execute ( 2 ) 60 | print ( ) 61 | execute ( 8 ) 62 | print ( ) 63 | execute ( 32 ) 64 | 65 | -------------------------------------------------------------------------------- /test/winder_bug/pi_python_python-csp_multiple_nested_shallow.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- mode:python; coding:utf-8; -*- 3 | 4 | # Calculation of Pi using quadrature. Using the python-csp package by Sarah Mount. 5 | # 6 | # Copyright © 2009-10 Russel Winder 7 | 8 | import time 9 | import multiprocessing 10 | 11 | import sys 12 | sys.path.insert(0, "../..") 13 | 14 | from csp.csp import * 15 | 16 | def execute ( processCount ) : 17 | n = 100000000 # 100 times fewer due to speed issues. 18 | delta = 1.0 / n 19 | startTime = time.time ( ) 20 | sliceSize = n / processCount 21 | channels = [ ] 22 | @process 23 | def calculator ( channel , id ) : 24 | """ 25 | readset = 26 | writeset = channel 27 | """ 28 | sum = 0.0 29 | for i in range ( 1 + id * sliceSize , ( id + 1 ) * sliceSize + 1 ) : 30 | x = ( i - 0.5 ) * delta 31 | sum += 1.0 / ( 1.0 + x * x ) 32 | channel.write ( sum ) 33 | @process 34 | def accumulator ( ) : 35 | """ 36 | readset = channel 37 | writeset = 38 | """ 39 | pi = 4.0 * sum ( [ channel.read ( ) for channel in channels ] ) * delta 40 | elapseTime = time.time ( ) - startTime 41 | print ( "==== Python CSP Multiple NestedShallow pi = " + str ( pi ) ) 42 | print ( "==== Python CSP Multiple NestedShallow iteration count = " + str ( n ) ) 43 | print ( "==== Python CSP Multiple NestedShallow elapse = " + str ( elapseTime ) ) 44 | print ( "==== Python CSP Multiple NestedShallow process count = " + str ( processCount ) ) 45 | print ( "==== Python CSP Multiple NestedShallow processor count = " + str ( multiprocessing.cpu_count ( ) ) ) 46 | processes = [ ] 47 | for i in range ( 0 , processCount ) : 48 | channel = Channel ( ) 49 | channels.append ( channel ) 50 | processes.append ( calculator ( channel , i ) ) 51 | processes.append ( accumulator ( ) ) 52 | Par ( *processes ).start ( ) 53 | 54 | if __name__ == '__main__' : 55 | execute ( 1 ) 56 | print ( ) 57 | execute ( 2 ) 58 | print ( ) 59 | execute ( 8 ) 60 | print ( ) 61 | execute ( 32 ) 62 | -------------------------------------------------------------------------------- /test/winder_bug/pi_python_python-csp_multiple_separate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- mode:python; coding:utf-8; -*- 3 | 4 | # Calculation of Pi using quadrature. Using the python-csp package by Sarah Mount. 5 | # 6 | # Copyright © 2009-10 Russel Winder 7 | 8 | import time 9 | import multiprocessing 10 | 11 | import sys 12 | sys.path.insert(0, "../..") 13 | 14 | from csp.csp import * 15 | 16 | @process 17 | def calculator ( channel , id , sliceSize , delta ) : 18 | """ 19 | readset = 20 | writeset = channel 21 | """ 22 | sum = 0.0 23 | for i in range ( 1 + id * sliceSize , ( id + 1 ) * sliceSize + 1 ) : 24 | x = ( i - 0.5 ) * delta 25 | sum += 1.0 / ( 1.0 + x * x ) 26 | channel.write ( sum ) 27 | 28 | @process 29 | def accumulator ( channels , n , delta , startTime , processCount ) : 30 | """ 31 | readset = channels 32 | writeset = 33 | """ 34 | pi = 4.0 * sum ( [ channel.read ( ) for channel in channels ] ) * delta 35 | elapseTime = time.time ( ) - startTime 36 | print ( "==== Python CSP Multiple pi = " + str ( pi ) ) 37 | print ( "==== Python CSP Multiple iteration count = " + str ( n ) ) 38 | print ( "==== Python CSP Multiple elapse = " + str ( elapseTime ) ) 39 | print ( "==== Python CSP Multiple process count = " + str ( processCount ) ) 40 | print ( "==== Python CSP Multiple processor count = " + str ( multiprocessing.cpu_count ( ) ) ) 41 | 42 | def execute ( processCount ) : 43 | n = 100000000 # 10 times fewer due to speed issues. 44 | delta = 1.0 / n 45 | startTime = time.time ( ) 46 | sliceSize = n / processCount 47 | channels = [ ] 48 | processes = [ ] 49 | for i in range ( 0 , processCount ) : 50 | channel = Channel ( ) 51 | channels.append ( channel ) 52 | processes.append ( calculator ( channel , i , sliceSize , delta ) ) 53 | processes.append ( accumulator ( channels , n , delta , startTime , processCount ) ) 54 | Par ( *processes ).start ( ) 55 | 56 | if __name__ == '__main__' : 57 | execute ( 1 ) 58 | print ( ) 59 | execute ( 2 ) 60 | print ( ) 61 | execute ( 8 ) 62 | print ( ) 63 | execute ( 32 ) 64 | -------------------------------------------------------------------------------- /test/winder_bug/pi_python_python-csp_single_nested_deep.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- mode:python; coding:utf-8; -*- 3 | 4 | # Calculation of Pi using quadrature. Using the python-csp package by Sarah Mount. 5 | # 6 | # Copyright © 2009-10 Russel Winder 7 | 8 | import time 9 | import multiprocessing 10 | 11 | import sys 12 | sys.path.insert(0, "../..") 13 | 14 | from csp.csp import * 15 | 16 | def execute ( processCount ) : 17 | n = 10000000 # 100 times fewer due to speed issues. 18 | delta = 1.0 / n 19 | startTime = time.time ( ) 20 | slice = n / processCount 21 | channel = Channel ( ) 22 | @process 23 | def accumulator ( ) : 24 | """ 25 | readset = channel 26 | writeset = 27 | """ 28 | pi = 4.0 * sum ( [ channel.read ( ) for i in range ( 0 , processCount ) ] ) * delta 29 | elapseTime = time.time ( ) - startTime 30 | print ( "==== Python CSP Single NestedDeep pi = " + str ( pi ) ) 31 | print ( "==== Python CSP Single NestedDeep iteration count = " + str ( n ) ) 32 | print ( "==== Python CSP Single NestedDeep elapse = " + str ( elapseTime ) ) 33 | print ( "==== Python CSP Single NestedDeep process count = " + str ( processCount ) ) 34 | print ( "==== Python CSP Single NestedDeep processor count = " + str ( multiprocessing.cpu_count ( ) ) ) 35 | processes = [ ] 36 | for i in range ( 0 , processCount ) : 37 | @process 38 | def calculator ( ) : 39 | """ 40 | readset = 41 | writeset = channel 42 | """ 43 | sum = 0.0 44 | for j in range ( 1 + i * slice , ( i + 1 ) * slice ) : 45 | x = ( j - 0.5 ) * delta 46 | sum += 1.0 / ( 1.0 + x * x ) 47 | channel.write ( sum ) 48 | processes.append ( calculator ( ) ) 49 | processes.append ( accumulator ( ) ) 50 | Par ( *processes ).start ( ) 51 | 52 | if __name__ == '__main__' : 53 | execute ( 1 ) 54 | print ( ) 55 | execute ( 2 ) 56 | print ( ) 57 | execute ( 8 ) 58 | print ( ) 59 | execute ( 32 ) 60 | -------------------------------------------------------------------------------- /test/winder_bug/pi_python_python-csp_single_nested_shallow.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- mode:python; coding:utf-8; -*- 3 | 4 | # Calculation of Pi using quadrature. Using the python-csp package by Sarah Mount. 5 | # 6 | # Copyright © 2009-10 Russel Winder 7 | 8 | import time 9 | import multiprocessing 10 | 11 | import sys 12 | sys.path.insert(0, "../..") 13 | 14 | from csp.csp import * 15 | 16 | def execute ( processCount ) : 17 | n = 10000000 # 100 times fewer due to speed issues. 18 | delta = 1.0 / n 19 | startTime = time.time ( ) 20 | sliceSize = n / processCount 21 | channel = Channel ( ) 22 | @process 23 | def calculator ( id ) : 24 | """ 25 | readset = 26 | writeset = channel 27 | """ 28 | sum = 0.0 29 | for i in range ( 1 + id * sliceSize , ( id + 1 ) * sliceSize + 1 ) : 30 | x = ( i - 0.5 ) * delta 31 | sum += 1.0 / ( 1.0 + x * x ) 32 | channel.write ( sum ) 33 | @process 34 | def accumulator ( ) : 35 | """ 36 | readset = channel 37 | writeset = 38 | """ 39 | pi = 4.0 * sum ( [ channel.read ( ) for i in range ( 0 , processCount ) ] ) * delta 40 | elapseTime = time.time ( ) - startTime 41 | print ( "==== Python CSP Single NestedShallow pi = " + str ( pi ) ) 42 | print ( "==== Python CSP Single NestedShallow iteration count = " + str ( n ) ) 43 | print ( "==== Python CSP Single NestedShallow elapse = " + str ( elapseTime ) ) 44 | print ( "==== Python CSP Single NestedShallow process count = " + str ( processCount ) ) 45 | print ( "==== Python CSP Single NestedShallow processor count = " + str ( multiprocessing.cpu_count ( ) ) ) 46 | processes = [ ] 47 | for i in range ( 0 , processCount ) : processes.append ( calculator ( i ) ) 48 | processes.append ( accumulator ( ) ) 49 | Par ( *processes ).start ( ) 50 | 51 | if __name__ == '__main__' : 52 | execute ( 1 ) 53 | print ( ) 54 | execute ( 2 ) 55 | print ( ) 56 | execute ( 8 ) 57 | print ( ) 58 | execute ( 32 ) 59 | -------------------------------------------------------------------------------- /test/winder_bug/pi_python_python-csp_single_separate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- mode:python; coding:utf-8; -*- 3 | 4 | # Calculation of Pi using quadrature. Using the python-csp package by Sarah Mount. 5 | # 6 | # Copyright © 2009-10 Russel Winder 7 | 8 | import time 9 | import multiprocessing 10 | 11 | import sys 12 | sys.path.insert(0, "../..") 13 | 14 | from csp.csp import * 15 | 16 | @process 17 | def calculator ( channel , id , sliceSize , delta ) : 18 | """ 19 | readset = 20 | writeset = channel 21 | """ 22 | sum = 0.0 23 | for i in range ( 1 + id * sliceSize , ( id + 1 ) * sliceSize + 1 ) : 24 | x = ( i - 0.5 ) * delta 25 | sum += 1.0 / ( 1.0 + x * x ) 26 | channel.write ( sum ) 27 | 28 | @process 29 | def accumulator ( channel , n , delta , startTime , processCount ) : 30 | """ 31 | readset = channel 32 | writeset = 33 | """ 34 | pi = 4.0 * sum ( [ channel.read ( ) for i in range ( 0 , processCount ) ] ) * delta 35 | elapseTime = time.time ( ) - startTime 36 | print ( "==== Python CSP Single pi = " + str ( pi ) ) 37 | print ( "==== Python CSP Single iteration count = " + str ( n ) ) 38 | print ( "==== Python CSP Single elapse = " + str ( elapseTime ) ) 39 | print ( "==== Python CSP Single process count = " + str ( processCount ) ) 40 | print ( "==== Python CSP Single processor count = " + str ( multiprocessing.cpu_count ( ) ) ) 41 | 42 | def execute ( processCount ) : 43 | n = 100000000 # 10 times fewer due to speed issues. 44 | delta = 1.0 / n 45 | startTime = time.time ( ) 46 | sliceSize = n / processCount 47 | channel = Channel ( ) 48 | processes = [ ] 49 | for i in range ( 0 , processCount ) : processes.append ( calculator ( channel , i , sliceSize , delta ) ) 50 | processes.append ( accumulator ( channel , n , delta , startTime , processCount ) ) 51 | Par ( *processes ).start ( ) 52 | 53 | if __name__ == '__main__' : 54 | execute ( 1 ) 55 | print ( ) 56 | execute ( 2 ) 57 | print ( ) 58 | execute ( 8 ) 59 | print ( ) 60 | execute ( 32 ) 61 | -------------------------------------------------------------------------------- /tutorial/README: -------------------------------------------------------------------------------- 1 | 2 | Please find documentation on 3 | http://code.google.com/p/python-csp/w/list 4 | 5 | Dependencies: 6 | * Numpy 7 | * pygame (imageext for saving plots) 8 | -------------------------------------------------------------------------------- /tutorial/part01/webserver.py: -------------------------------------------------------------------------------- 1 | # Example program from Part 01 of the python-csp tutorial 2 | 3 | # Copyright (C) Sarah Mount, 2010. 4 | 5 | # This program is free software; you can redistribute it and/or 6 | # modify it under the terms of the GNU General Public License 7 | # as published by the Free Software Foundation; either version 2 8 | # of the License, or (at your option) any later version. 9 | 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have rceeived a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | import socket 19 | import time 20 | 21 | from csp.csp import * 22 | 23 | 24 | def response(code, reason, page): 25 | """Construct and return a single HTTP response. 26 | 27 | FIXME: Should read and return files from disk, not a static page. 28 | FIXME: Should handle other MIME types. 29 | """ 30 | html = """ 31 | 32 | %i %s 33 | 34 | %s 35 |
36 |

Date: %s

37 | 38 | 39 | """ % (code, reason, page, time.ctime()) 40 | template = """HTTP/1.0 %i %s 41 | Content-Type: text/html 42 | Content-Length: %i 43 | 44 | 45 | %s 46 | """ % (code, reason, len(html), html) 47 | return template 48 | 49 | 50 | @process 51 | def server(host, port): 52 | """Simple CSP based web server. 53 | """ 54 | print('Running tutorial web-server on port {0}...'.format(port)) 55 | print('Interrupt with CTRL-C') 56 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 57 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 58 | sock.bind((host, port)) 59 | sock.listen(5) 60 | while True: 61 | conn_sock, conn_addr = sock.accept() 62 | request = conn_sock.recv(4096).strip() 63 | if request.startswith('GET'): 64 | handler_ok(request, conn_sock).start() 65 | else: 66 | handler_not_found(request, conn_sock).start() 67 | 68 | 69 | @process 70 | def handler_ok(request, conn_sock): 71 | """Handle a single HTTP 200 OK request. 72 | """ 73 | page = '

My python-csp web server!

' 74 | page += '

You asked for:

%s

' % request 75 | conn_sock.send(response(200, 'OK', page)) 76 | conn_sock.shutdown(socket.SHUT_RDWR) 77 | conn_sock.close() 78 | return 79 | 80 | 81 | @process 82 | def handler_not_found(request, conn_sock): 83 | """Handle a single HTTP 404 Not Found request. 84 | """ 85 | page = '

Cannot find your file

' 86 | page += '

You asked for:

%s

' % request 87 | conn_sock.send(response(404, 'Not Found', page)) 88 | conn_sock.shutdown(socket.SHUT_RDWR) 89 | conn_sock.close() 90 | return 91 | 92 | 93 | if __name__ == '__main__': 94 | host = '' 95 | port = 8888 96 | server(host, port).start() 97 | 98 | -------------------------------------------------------------------------------- /tutorial/part02/filecount.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Count the words in every file in a given directory. 5 | 6 | Copyright (C) Sarah Mount, 2010. 7 | 8 | This program is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU General Public License 10 | as published by the Free Software Foundation; either version 2 11 | of the License, or (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have rceeived a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | """ 21 | 22 | 23 | from csp.csp import * 24 | 25 | 26 | __author__ = 'Sarah Mount ' 27 | __date__ = 'July 2010' 28 | 29 | 30 | @process 31 | def word_count(filename): 32 | fd = file(filename) 33 | words = [line.split() for line in fd] 34 | fd.close() 35 | print '%s contains %i words.' % (filename, len(words)) 36 | 37 | 38 | @process 39 | def directory_count(path): 40 | import glob 41 | import os.path 42 | import sys 43 | # Test if directory exists 44 | if not os.path.exists(path): 45 | print '%s does not exist. Exiting.' % path 46 | sys.exit(1) 47 | # Get all filenames in directory 48 | paths = glob.glob(path + '/*') 49 | files = [path for path in paths if not os.path.isdir(path) and os.path.isfile(path)] 50 | procs = [word_count(fd) for fd in files] 51 | Par(*procs).start() 52 | 53 | 54 | if __name__ == '__main__': 55 | import sys 56 | if sys.argv <= 1: 57 | print 'You need to provide this script with a directory path. Exiting.' 58 | sys.exit(1) 59 | else: 60 | directory_count(sys.argv[1]).start() 61 | 62 | -------------------------------------------------------------------------------- /tutorial/part04/shop.py: -------------------------------------------------------------------------------- 1 | from csp.csp import * 2 | import random, time 3 | 4 | @process 5 | def customer_child(cchildout, n): 6 | for i in xrange(3): 7 | print "Customer's "+str(n)+" child sending "+str(i) 8 | cchildout.write(i) 9 | time.sleep(random.random() * 3) 10 | return 11 | 12 | @process 13 | def customer(cparentout, cchildout, n): 14 | for i in xrange(5): 15 | #print 'customer ', n, ' sending: customer '+str(i) 16 | print 'Customer '+str(n)+" sending "+str(i) 17 | Par(customer_child(cchildout, n)).start() 18 | cparentout.write(i) 19 | time.sleep(random.random() * 5) 20 | return 21 | 22 | @process 23 | def merchant(cin): 24 | for i in xrange(15): 25 | data = cin.read() 26 | print 'Merchant got:', data 27 | time.sleep(random.random() * 5) 28 | return 29 | 30 | @process 31 | def merchantswife(cin): 32 | for i in xrange(15): 33 | data = cin.read() 34 | print "Merchant's wife got: ", data 35 | time.sleep(random.random() * 4) 36 | return 37 | 38 | @process 39 | def terminator(chan): 40 | time.sleep(10) 41 | print 'Terminator is killing channel:', chan.name 42 | chan.poison() 43 | return 44 | 45 | doomed = Channel() 46 | doomed_children = Channel() 47 | Par(customer(doomed, doomed_children, 1), merchant(doomed), merchantswife(doomed_children), customer(doomed, doomed_children, 2), customer(doomed, doomed_children, 3), terminator(doomed)).start() 48 | #send5(doomed) // (recv(doomed), send52(doomed), interrupt(doomed)) 49 | -------------------------------------------------------------------------------- /tutorial/part07/Oscilloscope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/tutorial/part07/Oscilloscope.png -------------------------------------------------------------------------------- /tutorial/part07/oscilloscope.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Simple oscilloscope traces for python-csp. 5 | Requires Pygame. 6 | 7 | Features: 8 | * Press 's' to save an oscilloscope trace as a PNG. 9 | * Press UP and DOWN to scale the input more / less. 10 | 11 | Copyright (C) Sarah Mount, 2009. 12 | 13 | This program is free software; you can redistribute it and/or 14 | modify it under the terms of the GNU General Public License 15 | as published by the Free Software Foundation; either version 2 16 | of the License, or (at your option) any later version. 17 | 18 | This program is distributed in the hope that it will be useful, 19 | but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | GNU General Public License for more details. 22 | 23 | You should have rceeived a copy of the GNU General Public License 24 | along with this program. If not, see . 25 | """ 26 | 27 | 28 | from csp.csp import * 29 | 30 | import copy 31 | import numpy 32 | import pygame 33 | 34 | 35 | __author__ = 'Sarah Mount ' 36 | __date__ = 'November 2009' 37 | __version__ = '0.2' 38 | 39 | 40 | @forever 41 | def Oscilloscope(inchan, scale=80.0, _process=None): 42 | # Constants 43 | WIDTH, HEIGHT = 512, 256 44 | TRACE, GREY = (80, 255, 100), (110, 110, 110) 45 | caption = 'Oscilloscope' 46 | filename = caption + '.png' 47 | # Open window 48 | pygame.init() 49 | screen = pygame.display.set_mode((WIDTH, HEIGHT), 0) 50 | pygame.display.set_caption(caption) 51 | # Create a blank chart with vertical ticks, etc 52 | blank = numpy.zeros((WIDTH, HEIGHT, 3), dtype=numpy.int8) 53 | # Draw x-axis 54 | xaxis = HEIGHT // 2 55 | blank[::, xaxis] = GREY 56 | # Draw vertical ticks 57 | vticks = [-100, -50, +50, +100] 58 | for vtick in vticks: blank[::5, xaxis + vtick] = GREY # Horizontals 59 | blank[::50, ::5] = GREY # Verticals 60 | # Draw the 'blank' screen. 61 | pygame.surfarray.blit_array(screen, blank) # Blit the screen buffer 62 | pygame.display.flip() # Flip the double buffer 63 | # ydata stores data for the trace. 64 | ydata = [0.0 for i in range(WIDTH)] # assert len(ydata) <= WIDTH 65 | QUIT = False 66 | while not QUIT: 67 | pixels = copy.copy(blank) 68 | ydata.append(inchan.read() * scale) 69 | ydata.pop(0) 70 | for x in range(WIDTH): 71 | try: pixels[x][xaxis - int(ydata[x])] = TRACE 72 | except: pass 73 | pygame.surfarray.blit_array(screen, pixels) # Blit the screen buffer 74 | pygame.display.flip() # Flip the double buffer 75 | #pygame.display.update(0, xaxis-100, WIDTH, 201) # Flip the double buffer 76 | del pixels # Use constant space. 77 | for event in pygame.event.get(): 78 | if event.type == pygame.QUIT \ 79 | or event.type == pygame.KEYDOWN and event.key == pygame.K_q: 80 | QUIT = True 81 | elif event.type == pygame.KEYDOWN and event.key == pygame.K_s: 82 | pygame.image.save(screen, filename) 83 | print('Saving oscope image in: ' + str ( filename ) ) 84 | elif event.type == pygame.KEYDOWN and event.key == pygame.K_UP: 85 | scale += 10.0 86 | print('Oscilloscope scaling by %f' % scale) 87 | elif event.type == pygame.KEYDOWN and event.key == pygame.K_DOWN: 88 | if scale - 10.0 > 0.0: scale -= 10.0 89 | print('Oscilloscope scaling by %f' % scale) 90 | yield 91 | inchan.poison() 92 | pygame.display.quit() 93 | return 94 | 95 | 96 | if __name__ == '__main__': 97 | print('For this tutorial run traces.py') 98 | -------------------------------------------------------------------------------- /tutorial/part07/traces.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # 4 | # Example oscilloscope traces. 5 | # 6 | 7 | import sys 8 | from csp.csp import * 9 | from csp.builtins import Sin, Cos, GenerateFloats, Mux2, Delta2 10 | from oscilloscope import Oscilloscope 11 | 12 | 13 | @forever 14 | def Random(outchan): 15 | """Random process. 16 | 17 | Generates random data and writes it to outchan. 18 | """ 19 | import random 20 | while True: 21 | outchan.write(random.random()) 22 | yield 23 | return 24 | 25 | 26 | def trace_random(): 27 | """Test the Oscilloscope with random data. 28 | """ 29 | channel = Channel() 30 | par = Par(Random(channel), Oscilloscope(channel)) 31 | par.start() 32 | return 33 | 34 | 35 | def trace_sin(): 36 | """Plot a sine wave on the oscilloscope. 37 | """ 38 | channels = Channel(), Channel() 39 | par = Par(GenerateFloats(channels[0]), 40 | Sin(channels[0], channels[1]), 41 | Oscilloscope(channels[1])) 42 | par.start() 43 | return 44 | 45 | 46 | def trace_cos(): 47 | """Plot a cosine wave on the oscilloscope. 48 | """ 49 | channels = Channel(), Channel() 50 | par = Par(GenerateFloats(channels[0]), 51 | Cos(channels[0], channels[1]), 52 | Oscilloscope(channels[1])) 53 | par.start() 54 | return 55 | 56 | 57 | def trace_mux(): 58 | """Plot sine and cosine waves on the oscilloscope. 59 | """ 60 | channels = [Channel() for i in range(6)] 61 | par = Par(GenerateFloats(channels[0]), 62 | Delta2(channels[0], channels[1], channels[2]), 63 | Cos(channels[1], channels[3]), 64 | Sin(channels[2], channels[4]), 65 | Mux2(channels[3], channels[4], channels[5]), 66 | Oscilloscope(channels[5])) 67 | par.start() 68 | return 69 | 70 | EXAMPLES = {} 71 | for name, func in globals().items(): 72 | if name.startswith('trace_'): 73 | EXAMPLES[name[6:]] = func 74 | 75 | if __name__ == '__main__': 76 | if len(sys.argv) != 2: 77 | print('Syntax: python {0} {1}'.format(sys.argv[0], 78 | ' | '.join(EXAMPLES.keys()))) 79 | for name, func in EXAMPLES.items(): 80 | print(' {0:<9} {1}'.format(name, func.func_doc.strip())) 81 | elif sys.argv[1] not in EXAMPLES: 82 | print('Unknown example {0}'.format(sys.argv[1])) 83 | else: 84 | print('Use cursor up/down for scaling, s for save and q for quit') 85 | EXAMPLES[sys.argv[1]]() 86 | 87 | -------------------------------------------------------------------------------- /tutorial/part08/Queue.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/tutorial/part08/Queue.dia -------------------------------------------------------------------------------- /tutorial/part08/Queue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/futurecore/python-csp/1f96b76de1531ecf6bf1759641eadb08266ff7e7/tutorial/part08/Queue.png --------------------------------------------------------------------------------