├── .github ├── pull_request_template.md └── workflows │ ├── python-package.yml │ └── python-publish.yml ├── .gitignore ├── .upload_env.template ├── Harmony.g4 ├── HarmonyOnWindows.pdf ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.md ├── antlr-4.9.3-complete.jar ├── code ├── 2pc.hny ├── Diners.hny ├── DinersAvoid.hny ├── DinersCV.hny ├── DinersCV2.hny ├── Peterson.hny ├── PetersonBroken.hny ├── PetersonInductive.hny ├── PetersonMethod.hny ├── RWqtest.hny ├── Up.hny ├── UpEnter.hny ├── UpLock.hny ├── Upf.hny ├── Upr.hny ├── abd.hny ├── abdtest.hny ├── abp.hny ├── abptest.hny ├── actor.hny ├── actortest.hny ├── atm.hny ├── atomicinc.hny ├── baddblwait.hny ├── bank.hny ├── bank1.hny ├── bank1safe.hny ├── bank2.hny ├── bank2bad.hny ├── bank3.hny ├── bank4.hny ├── barber.hny ├── barrier.hny ├── barrier1.hny ├── barrier_broken.hny ├── barrier_cv.hny ├── barrier_demo.hny ├── barrier_double.hny ├── barrier_once.hny ├── barrier_test.hny ├── barrier_test1.hny ├── barrier_test2.hny ├── bosco.hny ├── bosco2.hny ├── boundedbuffer.hny ├── boundedbuffer_hoare.hny ├── boundedbuffer_test1.hny ├── bsort.hny ├── byzbosco.hny ├── chain.hny ├── chain1.hny ├── chain2.hny ├── chainaction.hny ├── chainaction1.hny ├── chainaction2.hny ├── chainrepl.hny ├── clock.hny ├── consensus.hny ├── counter.hny ├── cs.hny ├── csbarebones.hny ├── csonebit.hny ├── csonebitmulti.hny ├── disk.hny ├── farmer.hny ├── file.hny ├── file_btest.hny ├── file_crash.hny ├── file_crash_inode.hny ├── file_inode.hny ├── gpu.hny ├── hanoi.hny ├── hanoi2.hny ├── harmony.html ├── hello1.hny ├── hello2.hny ├── hello3.hny ├── hello4.hny ├── hello5.hny ├── hello6.hny ├── hello7.hny ├── hello8.hny ├── hello9.hny ├── hoare.hny ├── hw.hny ├── knight.hny ├── ky.hny ├── ky2.hny ├── leader.hny ├── lock.hny ├── lock_demo.hny ├── lock_susp.hny ├── lock_tas.hny ├── lock_test1.hny ├── lock_test2.hny ├── lock_test3.hny ├── lock_ticket.hny ├── lossy.hny ├── magic.hny ├── memory.hny ├── mersenne.hny ├── mesa.hny ├── multitest.hny ├── naiveFlags.hny ├── naiveLock.hny ├── naiveTurn.hny ├── needhamschroeder.hny ├── olb.hny ├── olb_btest.hny ├── olb_locks.hny ├── olb_test1.hny ├── paxos.hny ├── paxos3.hny ├── primes.hny ├── prog1.hny ├── prog2.hny ├── prog3.hny ├── prog4.hny ├── prog4enter.hny ├── prog4lock.hny ├── prog5.hny ├── qbarrier.hny ├── qsort.hny ├── qsorttest.hny ├── queue.hny ├── queue_MS.hny ├── queue_block.hny ├── queue_block_cv.hny ├── queue_broken1.hny ├── queue_broken2.hny ├── queue_btest1.hny ├── queue_btest2.hny ├── queue_cas.hny ├── queue_direct.hny ├── queue_fix.hny ├── queue_lin.hny ├── queue_lock.hny ├── queue_nonatom.hny ├── queue_nonatom_seq.hny ├── queue_test1.hny ├── queue_test2.hny ├── queue_test3.hny ├── queue_test4.hny ├── queue_test5.hny ├── queue_test6.hny ├── queue_test_lin.hny ├── queue_test_seq.hny ├── register.hny ├── rollercoaster.hny ├── rsm.hny ├── rsmspec.hny ├── rwlock.hny ├── rwlock_btest.hny ├── rwlock_btest2.hny ├── rwlock_busy.hny ├── rwlock_cheat.hny ├── rwlock_cv.hny ├── rwlock_cv_fair.hny ├── rwlock_sbs.hny ├── rwlock_sbs_fair.hny ├── rwlock_test1.hny ├── setobj.hny ├── setobj_btest.hny ├── setobj_linkedlist.hny ├── setobj_test1.hny ├── spinlock.hny ├── stack.hny ├── stack1.hny ├── stack2.hny ├── stack3.hny ├── stack4.hny ├── stacktest.hny ├── trap.hny ├── trap2.hny ├── trap3.hny ├── trap4.hny ├── trap5.hny ├── trap6.hny ├── triangle.hny ├── wal.hny └── xy.hny ├── compiler_integration_test.py ├── compose.pdf ├── diners.py ├── distributions ├── harmony-0.9.zip ├── harmony-1.0.zip ├── harmony-1.1.zip └── makedistr ├── doc-images ├── adding-new-path.png ├── find-c++-build-tools.png ├── first-pane.png ├── hover-new.png ├── press-install-c++-build-tools.png └── simple-graph-example.png ├── docs └── GrammarParser.md ├── h2py ├── harmony ├── harmony.bat ├── harmony_model_checker ├── charm │ ├── charm.c │ ├── charm.h │ ├── code.c │ ├── code.h │ ├── dfa.c │ ├── dfa.h │ ├── dot.c │ ├── dot.h │ ├── fastrange.h │ ├── global.c │ ├── global.h │ ├── gnfa.c │ ├── gnfa.h │ ├── graph.c │ ├── graph.h │ ├── hashdict.c │ ├── hashdict.h │ ├── hashtab.h │ ├── head.h │ ├── iface │ ├── iface.obs │ │ ├── hashset.c │ │ ├── hashset.h │ │ ├── iface.c │ │ ├── iface.h │ │ ├── iface_graph.c │ │ ├── iface_graph.h │ │ ├── minheap.c │ │ ├── minheap.h │ │ ├── queue.c │ │ ├── queue.h │ │ ├── stack.c │ │ └── stack.h │ ├── ipi │ │ └── ipi.c │ ├── json.c │ ├── json.h │ ├── ops.c │ ├── ops.h │ ├── prefetcher.h │ ├── python_ext │ │ └── ext.c │ ├── sdict.c │ ├── sdict.h │ ├── spawn.h │ ├── strbuf.c │ ├── strbuf.h │ ├── thread.c │ ├── thread.h │ ├── value.c │ └── value.h ├── compile.py ├── config.py ├── dfacmp.py ├── exception.py ├── h2py │ ├── H2PyEnv.py │ ├── H2PyExprVisitor.py │ ├── H2PyStmtVisitor.py │ ├── h2py.py │ ├── h2py_runtime │ │ └── __init__.py │ └── util.py ├── harmony │ ├── AbstractASTVisitor.py │ ├── DumpASTVisitor.py │ ├── __init__.py │ ├── ast.py │ ├── bag_util.py │ ├── behavior.py │ ├── brief.py │ ├── charm.css │ ├── charm.js │ ├── code.py │ ├── genhtml.py │ ├── harmony.py │ ├── jsonstring.py │ ├── ops.py │ ├── scope.py │ ├── state.py │ ├── summarize.py │ ├── summary.py │ ├── tex.py │ ├── value.py │ └── verbose.py ├── iface.py ├── main.py ├── modules │ ├── __init__.py │ ├── action.hny │ ├── alloc.hny │ ├── bags.hny │ ├── hoare.hny │ ├── lists.hny │ ├── sets.hny │ ├── synch.hny │ ├── synchBusy.hny │ ├── synchImprecise.hny │ ├── synchS.hny │ └── thread.hny ├── parser │ ├── HarmonyErrorListener.py │ ├── HarmonyLexer.py │ ├── HarmonyParser.py │ ├── HarmonyVisitor.py │ ├── __init__.py │ ├── antlr_rule_visitor.py │ └── custom_denter.py └── util │ ├── __init__.py │ └── logger.py ├── heval ├── heval.py ├── install-test-pkg ├── manifest ├── nworkers.py ├── pyproject.toml ├── python ├── Up.py ├── UpMany.py ├── inc.py ├── incmany.py └── qtestpar.py ├── requirements.txt ├── runall.py ├── runall.scr ├── setup.py ├── test ├── Bakery.hny ├── Dekker.hny ├── DinersCVwrong.hny ├── DinersOrdered.hny ├── DinersVar.hny ├── EM.hny ├── InfLoop.hny ├── Lock.hny ├── NotLiveSym.hny ├── NotSaveSym.hny ├── PCbinsem.hny ├── PCcv.hny ├── PClock.hny ├── PetersonBadProof.hny ├── PetersonBroken.hny ├── PetersonOO.hny ├── RWbadlock.hny ├── RWhoare.hny ├── Sema.hny ├── Stop.hny ├── Szymanski.hny ├── Turn.hny ├── anonbosco.hny ├── anonbosco2.hny ├── anonbosco3.hny ├── barber.hny ├── barriertest.hny ├── benor.hny ├── bosco.hny ├── bound.hny ├── bound_chk1.hny ├── bound_chk2.hny ├── busywait.hny ├── byzbosco.hny ├── ctriangle.hny ├── dijkstra.hny ├── extqtest.hny ├── extqueue.hny ├── lst.hny ├── msort.hny ├── mutex.hny ├── pascal.hny ├── paxos.hny ├── poolmesa.hny ├── poolsbs.hny ├── pooltest.hny ├── qsort.hny ├── queue.hny ├── rdwr.hny ├── sorttest.hny ├── teahouse.hny └── test.hny ├── tests ├── __init__.py ├── resources │ └── h2py │ │ ├── addr_1.hny │ │ ├── addr_1.py │ │ ├── addr_2.hny │ │ ├── addr_2.py │ │ ├── addr_3.hny │ │ ├── addr_3.py │ │ ├── apply_1.hny │ │ ├── apply_1.py │ │ ├── binops.hny │ │ ├── binops.py │ │ ├── choose_1.hny │ │ ├── choose_1.py │ │ ├── dict.hny │ │ ├── dict.py │ │ ├── dict_assign.hny │ │ ├── dict_assign.py │ │ ├── func_1.hny │ │ ├── func_1.py │ │ ├── h2py_name_conflict.hny │ │ ├── h2py_name_conflict.py │ │ ├── h2py_name_conflict_2.hny │ │ ├── h2py_name_conflict_2.py │ │ ├── h2py_runtime │ │ ├── if_1.hny │ │ ├── if_1.py │ │ ├── if_elif_else.hny │ │ ├── if_elif_else.py │ │ ├── if_else.hny │ │ ├── if_else.py │ │ ├── imports.hny │ │ ├── imports.py │ │ ├── local_assign.hny │ │ ├── local_assign.py │ │ ├── local_assign_assert.hny │ │ ├── local_assign_assert.py │ │ ├── print.hny │ │ ├── print.py │ │ ├── ptr_apply_1.hny │ │ ├── ptr_apply_1.py │ │ ├── ptr_assign_1.hny │ │ ├── ptr_assign_1.py │ │ ├── ptr_assign_2.hny │ │ ├── ptr_assign_2.py │ │ ├── ptr_assign_3.hny │ │ ├── ptr_assign_3.py │ │ ├── ptr_assign_4.hny │ │ ├── ptr_assign_4.py │ │ ├── tuple_assign.hny │ │ ├── tuple_assign.py │ │ ├── var_1.hny │ │ ├── var_1.py │ │ ├── var_2.hny │ │ ├── var_2.py │ │ ├── while_1.hny │ │ └── while_1.py ├── test_h2py.py └── test_h2py_runtime.py └── webinstall /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ## Overview 7 | 8 | 9 | 10 | 11 | 12 | ## Changes Made 13 | 14 | 15 | 16 | 17 | 18 | ## Test Coverage 19 | 20 | 21 | 22 | 23 | 24 | ## Next Steps (delete if not applicable) 25 | 26 | 27 | 28 | 29 | 30 | ## Related PRs or Issues (delete if not applicable) 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /.github/workflows/python-package.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python 3 | 4 | name: Python package 5 | 6 | on: 7 | push: 8 | branches: [ "master" ] 9 | pull_request: 10 | branches: [ "master" ] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | python-version: ["3.8", "3.9", "3.10", "3.11"] 19 | steps: 20 | - uses: actions/checkout@v3 21 | - name: Set up Python ${{ matrix.python-version }} 22 | uses: actions/setup-python@v3 23 | with: 24 | python-version: ${{ matrix.python-version }} 25 | - name: Install dependencies and build Harmony 26 | run: | 27 | python -m pip install --upgrade pip 28 | make 29 | - name: Test with runall.scr 30 | run: | 31 | ./runall.scr 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.interp 2 | *.tokens 3 | __pycache__ 4 | charm.exe 5 | env/ 6 | src/harmony/buildversion 7 | .antlr 8 | *.hco 9 | *.htm 10 | *.hvm 11 | *.dump 12 | *.so 13 | *.pyd 14 | .idea 15 | .vscode 16 | build 17 | 18 | *.egg-info 19 | package_buildversion 20 | 21 | dist/ 22 | compiler_integration_results/ 23 | compiler_integration_results.md 24 | 25 | mypy-report/ 26 | 27 | *.aux 28 | *.glo 29 | *.idx 30 | *.log 31 | *.toc 32 | *.ist 33 | *.acn 34 | *.acr 35 | *.alg 36 | *.bbl 37 | *.blg 38 | *.dvi 39 | *.glg 40 | *.gls 41 | *.ilg 42 | *.ind 43 | *.lof 44 | *.lot 45 | *.maf 46 | *.mtc 47 | *.mtc1 48 | *.out 49 | *.synctex.gz 50 | *.fdb_latexmk 51 | *.fls 52 | paper/paper.pdf 53 | book/paper.pdf 54 | book/pp.tex 55 | 56 | # Auto-generated by Makefile's [gen] target 57 | harmony_model_checker/__init__.py 58 | 59 | code/*.hvb 60 | code/*.gv 61 | code/*.png 62 | code/*.hvb 63 | diff.png 64 | queue4.hfa 65 | rw.hfa 66 | .upload_env 67 | -------------------------------------------------------------------------------- /.upload_env.template: -------------------------------------------------------------------------------- 1 | # This file is a template for .upload_env 2 | export TWINE_USERNAME=#TODO 3 | TEST_TWINE_PASSWORD=#TODO 4 | RELEASE_TWINE_PASSWORD=#TODO 5 | 6 | if [[ $1 == "testing" ]]; then 7 | export TWINE_PASSWORD=$TEST_TWINE_PASSWORD 8 | elif [[ $1 == "release" ]]; then 9 | export TWINE_PASSWORD=$RELEASE_TWINE_PASSWORD 10 | else 11 | echo "Missing [target_repo] argument" 12 | exit 1 13 | fi 14 | -------------------------------------------------------------------------------- /HarmonyOnWindows.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harmonylang/harmony/d06ac438fe7bd79539915cb67819728be5b7d803/HarmonyOnWindows.pdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2020, 2021, 2022 Robbert van Renesse 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of the copyright holder nor the names of its 15 | contributors may be used to endorse or promote products derived 16 | from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 | COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include harmony_model_checker/modules/*.hny 2 | include harmony_model_checker/charm/*.h 3 | include harmony_model_checker/charm/*.c 4 | include harmony_model_checker/charm/python_ext/ext.c 5 | include harmony_model_checker/charm/iface/*.c 6 | include harmony_model_checker/charm/iface/*.h 7 | include harmony_model_checker/harmony/charm.js 8 | include harmony_model_checker/harmony/charm.css 9 | -------------------------------------------------------------------------------- /antlr-4.9.3-complete.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harmonylang/harmony/d06ac438fe7bd79539915cb67819728be5b7d803/antlr-4.9.3-complete.jar -------------------------------------------------------------------------------- /code/Diners.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | 3 | const N = 5 4 | 5 | forks = [Lock(),] * N 6 | 7 | def diner(which): 8 | let left, right = (which, (which + 1) % N): 9 | while choose({ False, True }): 10 | acquire(?forks[left]) 11 | acquire(?forks[right]) 12 | # dine 13 | release(?forks[left]) 14 | release(?forks[right]) 15 | # think 16 | 17 | for i in {0..N-1}: 18 | spawn diner(i) 19 | -------------------------------------------------------------------------------- /code/DinersAvoid.hny: -------------------------------------------------------------------------------- 1 | from synch import * 2 | 3 | const N = 5 4 | 5 | forks = [Lock(),] * N 6 | sema = Semaphore(N - 1) # can be procured up to N-1 times 7 | 8 | def diner(which): 9 | let left, right = (which, (which + 1) % N): 10 | while choose({ False, True }): 11 | P(?sema) # procure counting semaphore 12 | acquire(?forks[left]) 13 | acquire(?forks[right]) 14 | # dine 15 | release(?forks[left]) 16 | release(?forks[right]) 17 | V(?sema) # vacate counting semaphore 18 | # think 19 | 20 | for i in {0..N-1}: 21 | spawn diner(i) 22 | -------------------------------------------------------------------------------- /code/DinersCV.hny: -------------------------------------------------------------------------------- 1 | from synch import * 2 | 3 | const N = 5 4 | 5 | mutex = Lock() 6 | forks = [False,] * N 7 | conds = [Condition(),] * N 8 | 9 | def diner(which): 10 | let left, right = (which, (which + 1) % N): 11 | while choose({ False, True }): 12 | acquire(?mutex) 13 | while forks[left] or forks[right]: 14 | wait(?conds[which], ?mutex) 15 | forks[left] = forks[right] = True 16 | release(?mutex) 17 | # dine 18 | acquire(?mutex) 19 | forks[left] = forks[right] = False 20 | notify(?conds[(which - 1) % N]) 21 | notify(?conds[(which + 1) % N]) 22 | release(?mutex) 23 | # think 24 | 25 | for i in {0..N-1}: 26 | spawn diner(i) 27 | -------------------------------------------------------------------------------- /code/DinersCV2.hny: -------------------------------------------------------------------------------- 1 | import synch 2 | 3 | const N = 5 4 | 5 | mutex = synch.Lock() 6 | forks = [False,] * N 7 | conds = [synch.Condition(),] * N 8 | 9 | def diner(which): 10 | let left, right = (which, (which + 1) % N): 11 | while choose({ False, True }): 12 | synch.acquire(?mutex) 13 | while forks[left] or forks[right]: 14 | if forks[left]: 15 | synch.wait(?conds[left], ?mutex) 16 | if forks[right]: 17 | synch.wait(?conds[right], ?mutex) 18 | assert not (forks[left] or forks[right]) 19 | forks[left] = forks[right] = True 20 | synch.release(?mutex) 21 | # dine 22 | synch.acquire(?mutex) 23 | forks[left] = forks[right] = False 24 | synch.notify(?conds[left]) 25 | synch.notify(?conds[right]) 26 | synch.release(?mutex) 27 | # think 28 | 29 | for i in {0..N-1}: 30 | spawn diner(i) 31 | -------------------------------------------------------------------------------- /code/Peterson.hny: -------------------------------------------------------------------------------- 1 | in_cs = 0 2 | invariant in_cs in { 0, 1 } 3 | 4 | sequential flags, turn 5 | flags = [ False, False ] 6 | turn = choose({0, 1}) 7 | 8 | def thread(self): 9 | while choose({ False, True }): 10 | # Enter critical section 11 | flags[self] = True 12 | turn = 1 - self 13 | await (not flags[1 - self]) or (turn == self) 14 | 15 | atomically in_cs += 1 16 | # Critical section 17 | atomically in_cs -= 1 18 | 19 | # Leave critical section 20 | flags[self] = False 21 | 22 | spawn thread(0) 23 | spawn thread(1) 24 | -------------------------------------------------------------------------------- /code/PetersonBroken.hny: -------------------------------------------------------------------------------- 1 | in_cs = 0 2 | invariant in_cs in { 0, 1 } 3 | 4 | sequential flags, turn 5 | flags = [ False, False ] 6 | turn = choose({0, 1}) 7 | 8 | def thread(self): 9 | while choose({ False, True }): 10 | # Enter critical section 11 | turn = 1 - self 12 | flags[self] = True 13 | await (not flags[1 - self]) or (turn == self) 14 | 15 | atomically in_cs += 1 16 | # Critical section 17 | atomically in_cs -= 1 18 | 19 | # Leave critical section 20 | flags[self] = False 21 | 22 | spawn thread(0) 23 | spawn thread(1) 24 | -------------------------------------------------------------------------------- /code/PetersonInductive.hny: -------------------------------------------------------------------------------- 1 | at_gate = 0 2 | 3 | sequential flags, turn 4 | flags = [ False, False ] 5 | turn = choose({0, 1}) 6 | 7 | def thread(self): 8 | while choose({ False, True }): 9 | # Enter critical section 10 | flags[self] = True 11 | atomically at_gate += 1 12 | atomically at_gate -= 1 13 | await (not flags[1 - self]) or (turn == self) 14 | 15 | # Critical section 16 | assert (not flags[1 - self]) or (turn == self) or (at_gate == 1) 17 | 18 | # Leave critical section 19 | flags[self] = False 20 | 21 | spawn thread(0) 22 | spawn thread(1) 23 | -------------------------------------------------------------------------------- /code/PetersonMethod.hny: -------------------------------------------------------------------------------- 1 | def Peterson_enter(pm, pid): 2 | pm->flags[pid] = True 3 | pm->turn = 1 - pid 4 | await (not pm->flags[1 - pid]) or (pm->turn == pid) 5 | 6 | def Peterson_exit(pm, pid): 7 | pm->flags[pid] = False 8 | 9 | def Peterson_mutex() returns result: 10 | result = { .turn: choose({0, 1}), .flags: [ False, False ] } 11 | 12 | #### The code above can go into its own Harmony module #### 13 | 14 | in_cs = 0 15 | invariant in_cs in { 0, 1 } 16 | 17 | sequential mutex 18 | mutex = Peterson_mutex() 19 | 20 | def thread(self): 21 | while choose({ False, True }): 22 | Peterson_enter(?mutex, self) 23 | 24 | atomically in_cs += 1 25 | # Critical section 26 | atomically in_cs -= 1 27 | 28 | Peterson_exit(?mutex, self) 29 | 30 | spawn thread(0) 31 | spawn thread(1) 32 | -------------------------------------------------------------------------------- /code/RWqtest.hny: -------------------------------------------------------------------------------- 1 | import RWqueue 2 | 3 | const NTHREADS = 3 4 | 5 | def process(self): 6 | while choose({ False, True }): 7 | if choose({ .read, .write }) == .read: 8 | acquire_rlock(?semas[self]) 9 | rcs: assert countLabel(wcs) == 0 10 | release_rlock() 11 | else: # .write 12 | acquire_wlock(?semas[self]) 13 | wcs: assert (countLabel(wcs) == 1) and (countLabel(rcs) == 0) 14 | release_wlock() 15 | 16 | semas = [ Semaphore(0) for i in {0..NTHREADS-1} ] 17 | for i in {0..NTHREADS-1}: 18 | spawn process(i) 19 | -------------------------------------------------------------------------------- /code/Up.hny: -------------------------------------------------------------------------------- 1 | count = 0 2 | done = [ False, False ] 3 | 4 | def incrementer(self): 5 | count = count + 1 6 | done[self] = True 7 | await done[1 - self] 8 | assert count == 2 9 | 10 | spawn incrementer(0) 11 | spawn incrementer(1) 12 | -------------------------------------------------------------------------------- /code/UpEnter.hny: -------------------------------------------------------------------------------- 1 | count = 0 2 | 3 | entered = done = [ False, False ] 4 | 5 | def incrementer(self): 6 | entered[self] = True 7 | if entered[1 - self]: # if the other thread has already started 8 | await done[1 - self] # wait until it is done 9 | count = count + 1 10 | done[self] = True 11 | await done[1 - self] 12 | assert count == 2 13 | 14 | spawn incrementer(0) 15 | spawn incrementer(1) 16 | -------------------------------------------------------------------------------- /code/UpLock.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | 3 | sequential done 4 | 5 | count = 0 6 | countlock = Lock() 7 | done = [ False, False ] 8 | 9 | def thread(self): 10 | acquire(?countlock) 11 | count = count + 1 12 | release(?countlock) 13 | done[self] = True 14 | await done[1 - self] 15 | assert count == 2 16 | 17 | spawn thread(0) 18 | spawn thread(1) 19 | -------------------------------------------------------------------------------- /code/Upf.hny: -------------------------------------------------------------------------------- 1 | count = 0 2 | 3 | finally count == 2 4 | 5 | def incrementer(): 6 | count = count + 1 7 | 8 | spawn incrementer() 9 | spawn incrementer() 10 | -------------------------------------------------------------------------------- /code/Upr.hny: -------------------------------------------------------------------------------- 1 | count = 0 2 | done = [ False, False ] 3 | 4 | def incrementer(self): 5 | var register = count # load shared variable count into a private register 6 | register += 1 # increment the register 7 | count = register # store its value into variable count 8 | done[self] = True 9 | await done[1 - self] 10 | assert count == 2 11 | 12 | spawn incrementer(0) 13 | spawn incrementer(1) 14 | -------------------------------------------------------------------------------- /code/abd.hny: -------------------------------------------------------------------------------- 1 | import bags 2 | 3 | const F = 1 4 | const N = (2 * F) + 1 5 | 6 | network = bags.empty() 7 | 8 | def send(m): atomically network = bags.add(network, m) 9 | 10 | def server(): 11 | var t, v, received = (0, None), None, {} 12 | while True: 13 | atomically when exists m in { k for k in keys network - received 14 | where k.type in {"read", "write"} }: 15 | received |= { m } 16 | if (m.type == "write") and (m.value[0] > t): 17 | t, v = m.value 18 | send({ .type: .response, .dst: m.src, .value: (t, v) }) 19 | 20 | def init(): 21 | for i in { 1 .. N }: spawn eternal server() 22 | 23 | def receive(uid, phase) returns quorums: 24 | let msgs = { m:c for m:c in network 25 | where (m.type == .response) and (m.dst == (uid, phase)) }: 26 | quorums = bags.combinations(msgs, N - F) 27 | 28 | def read(uid) returns contents: 29 | send({ .type: "read", .src: (uid, 1) }) 30 | atomically when exists msgs in receive(uid, 1): 31 | let (t, v) = max(m.value for m in keys msgs): 32 | send({ .type: "write", .src: (uid, 2), .value: (t, v) }) 33 | contents = v 34 | atomically when exists msgs in receive(uid, 2): 35 | pass 36 | 37 | def write(uid, v): 38 | send({ .type: "read", .src: (uid, 1) }) 39 | atomically when exists msgs in receive(uid, 1): 40 | let (t, _) = max(m.value for m in keys msgs) 41 | let nt = (t[0] + 1, uid): 42 | send({ .type: "write", .src: (uid, 2), .value: (nt, v) }) 43 | atomically when exists msgs in receive(uid, 2): 44 | pass 45 | -------------------------------------------------------------------------------- /code/abdtest.hny: -------------------------------------------------------------------------------- 1 | import register 2 | 3 | const NREADERS = 2 4 | const NWRITERS = 1 5 | 6 | def reader(i): 7 | print(i, "reads") 8 | let v = register.read(i): 9 | print(i, "read", v) 10 | 11 | def writer(i): 12 | print(i, "writes") 13 | register.write(i, i) 14 | print(i, "wrote") 15 | 16 | register.init() 17 | for i in { 1 .. NREADERS }: 18 | spawn reader(i) 19 | for i in { 1 .. NWRITERS }: 20 | spawn writer(-i) 21 | -------------------------------------------------------------------------------- /code/abp.hny: -------------------------------------------------------------------------------- 1 | def net_send(pchan, msg): 2 | atomically: 3 | !pchan = msg if choose({ False, True }) else () 4 | 5 | def net_recv(pchan) returns msg: 6 | atomically: 7 | msg = !pchan 8 | !pchan = () 9 | 10 | def app_send(net, seq, payload): 11 | !seq = 1 - !seq 12 | let m = { .seq: !seq, .payload: payload }: 13 | var blocked = True 14 | while blocked: 15 | net_send(?net->s_chan, m) 16 | let response = net_recv(?net->r_chan): 17 | blocked = (response == ()) or (response.ack != !seq) 18 | 19 | def app_recv(net, seq) returns payload: 20 | !seq = 1 - !seq 21 | var blocked = True 22 | while blocked: 23 | let m = net_recv(?net->s_chan): 24 | if m != (): 25 | net_send(?net->r_chan, { .ack: m.seq }) 26 | if m.seq == !seq: 27 | payload = m.payload 28 | blocked = False 29 | -------------------------------------------------------------------------------- /code/abptest.hny: -------------------------------------------------------------------------------- 1 | import abp 2 | 3 | const NMSGS = 10 4 | 5 | invariant s_seq in { 0, 1 } 6 | invariant r_seq in { 0, 1 } 7 | 8 | network = { .s_chan: (), .r_chan: () } 9 | s_seq = r_seq = 0 10 | 11 | def sender(): 12 | for i in {1..NMSGS}: 13 | abp.app_send(?network, ?s_seq, i) 14 | 15 | def receiver(): 16 | var i = 1 17 | while True: 18 | let payload = abp.app_recv(?network, ?r_seq): 19 | assert payload == i 20 | i += 1 21 | 22 | spawn sender() 23 | spawn eternal receiver() 24 | -------------------------------------------------------------------------------- /code/actor.hny: -------------------------------------------------------------------------------- 1 | import synch 2 | 3 | def pc_actor(q, _nrequests): 4 | var nrequests = _nrequests 5 | var requests, balance = {}, 0 6 | while nrequests > 0: 7 | let req = synch.get(q): 8 | if req.type == .produce: 9 | if balance >= 0: 10 | requests |= { req } 11 | else: 12 | let r = choose(requests): 13 | assert r.type == .consume 14 | synch.put(r.queue, req.item) 15 | requests -= { r } 16 | balance += 1 17 | else: 18 | assert req.type == .consume 19 | if balance <= 0: 20 | requests |= { req } 21 | else: 22 | let r = choose(requests): 23 | assert r.type == .produce 24 | synch.put(req.queue, r.item) 25 | requests -= { r } 26 | balance -= 1 27 | nrequests -= 1 28 | 29 | def init(q, n): 30 | spawn pc_actor(q, n) 31 | -------------------------------------------------------------------------------- /code/actortest.hny: -------------------------------------------------------------------------------- 1 | import synch 2 | import actor 3 | 4 | const NITEMS = 3 5 | 6 | pc_queue = synch.Queue() 7 | queues = [synch.Queue(),] * NITEMS 8 | 9 | def produce(q, item): 10 | synch.put(?pc_queue, { .type: .produce, .item: item }) 11 | 12 | def consume(q1, q2): 13 | synch.put(q1, { .type: .consume, .queue: q2 }) 14 | result = synch.get(q2) 15 | 16 | actor.init(?pc_queue, 2 * NITEMS) 17 | for i in {0..NITEMS-1}: 18 | spawn produce(?pc_queue, i) 19 | spawn consume(?pc_queue, ?queues[i]) 20 | -------------------------------------------------------------------------------- /code/atm.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | 3 | const N_ACCOUNTS = 2 4 | const N_CUSTOMERS = 2 5 | const N_ATMS = 2 6 | const MAX_BALANCE = 1 7 | 8 | accounts = [ { .lock: Lock(), .balance: choose({0..MAX_BALANCE})} 9 | for i in {1..N_ACCOUNTS} ] 10 | 11 | invariant min(accounts[acct].balance for acct in {0..N_ACCOUNTS-1}) >= 0 12 | 13 | def atm_check_balance(acct) returns balance: # return the balance on acct 14 | acquire(?accounts[acct].lock) 15 | balance = accounts[acct].balance 16 | release(?accounts[acct].lock) 17 | 18 | def atm_withdraw(acct, amount) returns success: # withdraw amount from acct 19 | assert amount >= 0 20 | acquire(?accounts[acct].lock) 21 | accounts[acct].balance -= amount 22 | release(?accounts[acct].lock) 23 | success = True 24 | 25 | def customer(atm, acct, amount): 26 | assert amount >= 0 27 | let bal = atm_check_balance(acct): 28 | if amount <= bal: 29 | atm_withdraw(acct, amount) 30 | 31 | for i in {1..N_ATMS}: 32 | spawn customer(i, choose({0..N_ACCOUNTS-1}), 33 | choose({0..MAX_BALANCE})) 34 | -------------------------------------------------------------------------------- /code/atomicinc.hny: -------------------------------------------------------------------------------- 1 | def atomic_inc(ptr): 2 | atomically !ptr += 1 3 | 4 | count = 0 5 | atomic_inc(?count) 6 | -------------------------------------------------------------------------------- /code/baddblwait.hny: -------------------------------------------------------------------------------- 1 | while forks[left]: 2 | synch.wait(?conds[left], ?mutex) 3 | while forks[right]: 4 | synch.wait(?conds[right], ?mutex) 5 | -------------------------------------------------------------------------------- /code/bank.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | 3 | const MAX_BALANCE = 2 4 | const N_ACCOUNTS = 2 5 | const N_THREADS = 2 6 | 7 | accounts = [ { .lock: Lock(), .balance: choose({0..MAX_BALANCE})} 8 | for i in {1..N_ACCOUNTS} ] 9 | 10 | def transfer(a1, a2, amount) returns success: 11 | acquire(?accounts[a1].lock) 12 | if amount <= accounts[a1].balance: 13 | accounts[a1].balance -= amount 14 | acquire(?accounts[a2].lock) 15 | accounts[a2].balance += amount 16 | release(?accounts[a2].lock) 17 | success = True 18 | else: 19 | success = False 20 | release(?accounts[a1].lock) 21 | 22 | def thread(): 23 | let a1 = choose({0..N_ACCOUNTS-1}) 24 | let a2 = choose({0..N_ACCOUNTS-1} - { a1 }): 25 | transfer(a1, a2, choose({1..MAX_BALANCE})) 26 | 27 | for i in {1..N_THREADS}: 28 | spawn thread() 29 | -------------------------------------------------------------------------------- /code/bank1.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | 3 | def Account(balance) returns account: 4 | account = { .lock: Lock(), .balance: balance } 5 | 6 | accounts = [ Account(3), Account(7) ] 7 | 8 | def transfer(a1, a2, amount): 9 | acquire(?accounts[a1].lock) 10 | if amount <= accounts[a1].balance: 11 | accounts[a1].balance -= amount 12 | acquire(?accounts[a2].lock) 13 | accounts[a2].balance += amount 14 | release(?accounts[a2].lock) 15 | release(?accounts[a1].lock) 16 | 17 | spawn transfer(0, 1, 1) 18 | spawn transfer(1, 0, 2) 19 | -------------------------------------------------------------------------------- /code/bank1safe.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | 3 | def Account(balance) returns account: 4 | account = { .lock: Lock(), .balance: balance } 5 | 6 | active = {} 7 | accounts = [ Account(3), Account(7) ] 8 | 9 | def transfer(a1, a2, amount): 10 | atomically when ({ a1, a2 } & active) == {}: 11 | active |= { a1, a2 } 12 | 13 | acquire(?accounts[a1].lock) 14 | if amount <= accounts[a1].balance: 15 | accounts[a1].balance -= amount 16 | acquire(?accounts[a2].lock) 17 | accounts[a2].balance += amount 18 | release(?accounts[a2].lock) 19 | release(?accounts[a1].lock) 20 | 21 | atomically: 22 | active -= { a1, a2 } 23 | 24 | spawn transfer(0, 1, 1) 25 | spawn transfer(1, 0, 2) 26 | -------------------------------------------------------------------------------- /code/bank2.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | 3 | def Account(balance) returns account: 4 | account = { .lock: Lock(), .balance: balance } 5 | 6 | accounts = [ Account(3), Account(7) ] 7 | 8 | def transfer(a1, a2, amount): 9 | acquire(?accounts[a1].lock) 10 | if amount <= accounts[a1].balance: 11 | accounts[a1].balance -= amount 12 | release(?accounts[a1].lock) 13 | acquire(?accounts[a2].lock) 14 | accounts[a2].balance += amount 15 | release(?accounts[a2].lock) 16 | else: 17 | release(?accounts[a1].lock) 18 | 19 | spawn transfer(0, 1, 1) 20 | spawn transfer(1, 0, 2) 21 | -------------------------------------------------------------------------------- /code/bank2bad.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | 3 | def Account(balance) returns account: 4 | account = { .lock: Lock(), .balance: balance } 5 | 6 | accounts = [ Account(3), Account(7) ] 7 | 8 | invariant all(a.balance >= 0 for a in accounts) 9 | 10 | def transfer(a1, a2, amount): 11 | acquire(?accounts[a1].lock) 12 | var funds_available = amount <= accounts[a1].balance 13 | release(?accounts[a1].lock) 14 | if funds_available: 15 | acquire(?accounts[a1].lock) 16 | accounts[a1].balance -= amount 17 | release(?accounts[a1].lock) 18 | acquire(?accounts[a2].lock) 19 | accounts[a2].balance += amount 20 | release(?accounts[a2].lock) 21 | 22 | spawn transfer(0, 1, 2) 23 | spawn transfer(0, 1, 2) 24 | -------------------------------------------------------------------------------- /code/bank3.hny: -------------------------------------------------------------------------------- 1 | def Lock() returns lock: 2 | lock = False 3 | 4 | def acquire2(lk1, lk2): 5 | atomically when not (!lk1 or !lk2): 6 | !lk1 = !lk2 = True 7 | 8 | def release(lk): 9 | atomically !lk = False 10 | 11 | def Account(balance) returns account: 12 | account = { .lock: Lock(), .balance: balance } 13 | 14 | accounts = [ Account(3), Account(7) ] 15 | 16 | def transfer(a1, a2, amount): 17 | acquire2(?accounts[a1].lock, ?accounts[a2].lock) 18 | if amount <= accounts[a1].balance: 19 | accounts[a1].balance -= amount 20 | accounts[a2].balance += amount 21 | release(?accounts[a1].lock) 22 | release(?accounts[a2].lock) 23 | 24 | spawn transfer(0, 1, 1) 25 | spawn transfer(1, 0, 2) 26 | -------------------------------------------------------------------------------- /code/bank4.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | 3 | def Account(balance) returns account: 4 | account = { .lock: Lock(), .balance: balance } 5 | 6 | accounts = [ Account(3), Account(7) ] 7 | 8 | def transfer(a1, a2, amount): 9 | acquire(?accounts[min(a1, a2)].lock) 10 | acquire(?accounts[max(a1, a2)].lock) 11 | if amount <= accounts[a1].balance: 12 | accounts[a1].balance -= amount 13 | accounts[a2].balance += amount 14 | release(?accounts[a1].lock) 15 | release(?accounts[a2].lock) 16 | 17 | spawn transfer(0, 1, 1) 18 | spawn transfer(1, 0, 2) 19 | -------------------------------------------------------------------------------- /code/barber.hny: -------------------------------------------------------------------------------- 1 | from synch import * 2 | 3 | const NSEATS = 2 4 | const NCUSTOMERS = 3 5 | const NBARBERS = 2 6 | 7 | mutex = Lock() 8 | customer_cond = Condition() 9 | barber_cond = Condition() 10 | customers_waiting = {} 11 | customers_ready = {} 12 | 13 | def barber(self): 14 | while True: 15 | # Wait for a customer 16 | acquire(?mutex) 17 | while customers_waiting == {}: 18 | wait(?barber_cond, ?mutex) 19 | var c = choose customers_waiting 20 | customers_waiting -= { c } 21 | release(?mutex) 22 | 23 | cut: pass # Cut the hair of customer c. 24 | 25 | # Cut is done. Tell customer to go. 26 | acquire(?mutex) 27 | customers_ready |= { c } 28 | notify_all(?customer_cond) 29 | release(?mutex) 30 | 31 | def customer(id): 32 | while choose { False, True }: # while alive 33 | acquire(?mutex) 34 | if len customers_waiting < NSEATS: 35 | # Take seat and wake up a barber 36 | customers_waiting |= { id } 37 | notify(?barber_cond) 38 | 39 | # Wait for some barber to cut my hair 40 | while id not in customers_ready: 41 | wait(?customer_cond, ?mutex) 42 | customers_ready -= { id } 43 | release(?mutex) 44 | 45 | for _ in {1..NBARBERS}: 46 | spawn eternal barber() 47 | for i in {1..NCUSTOMERS}: 48 | spawn customer(i) 49 | -------------------------------------------------------------------------------- /code/barrier.hny: -------------------------------------------------------------------------------- 1 | def Barrier(required) returns barrier: 2 | barrier = { .required: required, .n: 0, .color: 0 } 3 | 4 | def bwait(b): 5 | var color = None 6 | atomically: 7 | color = b->color 8 | b->n += 1 9 | if b->n == b->required: 10 | b->color ^= 1 11 | b->n = 0 12 | atomically await b->color != color 13 | -------------------------------------------------------------------------------- /code/barrier1.hny: -------------------------------------------------------------------------------- 1 | from synch import Queue, put, get 2 | 3 | const NROUNDS = 3 4 | const NTHREADS = 3 5 | 6 | queues = [ Queue(), ] * NTHREADS 7 | 8 | def barrier_enter(self): 9 | for i in {0..NTHREADS-1} where i != self: 10 | put(?queues[i], i) 11 | for i in {1..NTHREADS-1}: 12 | get(?queues[self]) 13 | 14 | def barrier_exit(self): 15 | pass 16 | 17 | sequential round, done 18 | 19 | round = [None,] * NTHREADS 20 | done = [False,] * NTHREADS 21 | 22 | # check that all non-None values in round are the same 23 | def check(): 24 | result = True 25 | var x = None 26 | for i in {0..NTHREADS-1}: 27 | if result and (round[i] != None): 28 | if x != None: 29 | result = round[i] == x 30 | x = round[i] 31 | 32 | round = [None,] * NTHREADS 33 | done = [False,] * NTHREADS 34 | 35 | def process(self): 36 | for r in {0..NROUNDS-1}: 37 | barrier_enter(self) 38 | round[self] = r 39 | assert check() 40 | round[self] = None 41 | barrier_exit(self) 42 | done[self] = True 43 | 44 | def main(): 45 | await all(done) 46 | 47 | for i in {0..NTHREADS-1}: 48 | spawn process(i) 49 | 50 | spawn main() 51 | -------------------------------------------------------------------------------- /code/barrier_broken.hny: -------------------------------------------------------------------------------- 1 | def Barrier(required) returns barrier: 2 | barrier = { .required: required, .n: 0 } 3 | 4 | def bwait(b): 5 | atomically: 6 | b->n += 1 7 | if b->n == b->required: 8 | b->n = 0 9 | atomically await b->n == 0 10 | -------------------------------------------------------------------------------- /code/barrier_cv.hny: -------------------------------------------------------------------------------- 1 | from synch import * 2 | 3 | def Barrier(required) returns barrier: 4 | barrier = { 5 | .mutex: Lock(), .cond: Condition(), 6 | .required: required, .n: 0, .color: 0 7 | } 8 | 9 | def bwait(b): 10 | acquire(?b->mutex) 11 | b->n += 1 12 | if b->n == b->required: 13 | b->color ^= 1 14 | b->n = 0 15 | notify_all(?b->cond) 16 | else: 17 | let color = b->color: 18 | while b->color == color: 19 | wait(?b->cond, ?b->mutex) 20 | release(?b->mutex) 21 | -------------------------------------------------------------------------------- /code/barrier_demo.hny: -------------------------------------------------------------------------------- 1 | import barrier 2 | 3 | const NWORKERS = 2 4 | 5 | vec1 = [ 1, 2, 3, 4 ] 6 | vec2 = [ 5, 6, 7, 8 ] 7 | barr = barrier.Barrier(NWORKERS) 8 | output = [ 0, ] * NWORKERS 9 | 10 | def split(self, v) returns x: 11 | x = (self * len(v)) / NWORKERS 12 | 13 | def dotproduct(self, v1, v2): 14 | assert len(v1) == len(v2) 15 | var total = 0 16 | for i in { split(self, v1) .. split(self + 1, v1) - 1}: 17 | total += v1[i] * v2[i] 18 | output[self] = total 19 | barrier.bwait(?barr) 20 | print sum(output) 21 | 22 | for i in { 0 .. NWORKERS - 1 }: 23 | spawn dotproduct(i, vec1, vec2) 24 | -------------------------------------------------------------------------------- /code/barrier_double.hny: -------------------------------------------------------------------------------- 1 | def Barrier(required) returns barrier: 2 | barrier = { .required: required, .n: [0, 0] } 3 | 4 | def turnstile(b, i): 5 | atomically: 6 | b->n[i] += 1 7 | if b->n[i] == b->required: 8 | b->n[1 - i] = 0 9 | atomically await b->n[i] == b->required 10 | 11 | def bwait(b): 12 | turnstile(b, 0) 13 | turnstile(b, 1) 14 | -------------------------------------------------------------------------------- /code/barrier_once.hny: -------------------------------------------------------------------------------- 1 | def Barrier(required) returns barrier: 2 | barrier = { .required: required, .n: 0 } 3 | 4 | def bwait(b): 5 | atomically b->n += 1 6 | atomically await b->n == b->required 7 | -------------------------------------------------------------------------------- /code/barrier_test.hny: -------------------------------------------------------------------------------- 1 | import barrier 2 | 3 | const NTHREADS = 3 4 | const NROUNDS = 4 5 | 6 | barr = barrier.Barrier(NTHREADS) 7 | before = after = [0,] * NTHREADS 8 | 9 | invariant min(before) >= max(after) 10 | 11 | def thread(self): 12 | for _ in { 1 .. NROUNDS }: 13 | before[self] += 1 14 | barrier.bwait(?barr) 15 | after[self] += 1 16 | 17 | for i in { 0 .. NTHREADS - 1 }: 18 | spawn thread(i) 19 | -------------------------------------------------------------------------------- /code/barrier_test1.hny: -------------------------------------------------------------------------------- 1 | import barrier 2 | 3 | const NTHREADS = 3 4 | const NROUNDS = 4 5 | 6 | barr = barrier.Barrier(NTHREADS) 7 | round = [0,] * NTHREADS 8 | in_b = [False,] * NTHREADS 9 | 10 | invariant all((in_b[i] and in_b[j]) => (round[i] == round[j]) 11 | for i in { 0 .. NTHREADS - 1 } for j in { 0 .. NTHREADS - 1 }) 12 | 13 | def thread(self): 14 | for r in {0..NROUNDS-1}: 15 | round[self] += 1 16 | barrier.bwait(?barr) 17 | in_b[self] = True 18 | pass 19 | in_b[self] = False 20 | 21 | for i in {0..NTHREADS-1}: 22 | spawn thread(i) 23 | -------------------------------------------------------------------------------- /code/barrier_test2.hny: -------------------------------------------------------------------------------- 1 | import barrier 2 | 3 | const NTHREADS = 3 4 | const NROUNDS = 4 5 | 6 | barr = barrier.Barrier(NTHREADS) 7 | round = [0,] * NTHREADS 8 | phase = 0 9 | 10 | def thread(self): 11 | for r in {0..NROUNDS-1}: 12 | round[self] += 1 13 | if self == 0: # coordinator prepares 14 | phase += 1 15 | barrier.bwait(?barr) # enter parallel work 16 | assert round[self] == phase 17 | barrier.bwait(?barr) # exit parallel work 18 | 19 | for i in {0..NTHREADS-1}: 20 | spawn thread(i) 21 | -------------------------------------------------------------------------------- /code/bosco.hny: -------------------------------------------------------------------------------- 1 | import bags 2 | 3 | const F = 1 4 | const N = (3 * F) + 1 5 | const NROUNDS = 3 6 | 7 | proposals = [ choose({0, 1}) for i in {0..N-1} ] 8 | network = bags.empty() 9 | 10 | def broadcast(msg): 11 | atomically network = bags.add(network, msg) 12 | 13 | def receive(round, k) returns quorum: 14 | let msgs = { e:c for (r,e):c in network where r == round }: 15 | quorum = bags.combinations(msgs, k) 16 | 17 | def processor(proposal): 18 | var estimate, decided = proposal, False 19 | broadcast(0, estimate) 20 | for round in {0..NROUNDS-1}: 21 | atomically when exists quorum in receive(round, N - F): 22 | let count = [ bags.multiplicity(quorum, i) for i in { 0..1 } ]: 23 | assert count[0] != count[1] 24 | estimate = 0 if count[0] > count[1] else 1 25 | if count[estimate] == (N - F): 26 | if not decided: 27 | print estimate 28 | decided = True 29 | assert estimate in proposals # check validity 30 | broadcast(round + 1, estimate) 31 | 32 | print proposals 33 | for i in {0..N-1}: 34 | spawn processor(proposals[i]) 35 | -------------------------------------------------------------------------------- /code/bosco2.hny: -------------------------------------------------------------------------------- 1 | import bags 2 | 3 | const F = 1 4 | const N = (3 * F) + 1 5 | const NROUNDS = 3 6 | 7 | let n_zeroes = choose { 0 .. N / 2 }: 8 | proposals = ([0,] * n_zeroes) + ([1,] * (N - n_zeroes)) 9 | network = bags.empty() 10 | 11 | def broadcast(msg): 12 | atomically network = bags.add(network, msg) 13 | 14 | def receive(round) returns quorum: 15 | let msgs = { e:c for (r,e):c in network where r == round }: 16 | quorum = {} if bags.size(msgs) < N else { msgs } 17 | 18 | def processor(proposal): 19 | var estimate, decided = proposal, False 20 | broadcast(0, estimate) 21 | for round in {0..NROUNDS-1}: 22 | atomically when exists msgs in receive(round): 23 | let choices = bags.combinations(msgs, N - F) 24 | let quorum = choose(choices) 25 | let count = [ bags.multiplicity(quorum, i) for i in { 0..1 } ]: 26 | assert count[0] != count[1] 27 | estimate = 0 if count[0] > count[1] else 1 28 | if count[estimate] == (N - F): 29 | if not decided: 30 | print estimate 31 | decided = True 32 | assert estimate in proposals # validity 33 | broadcast(round + 1, estimate) 34 | 35 | print proposals 36 | for i in {0..N-1}: 37 | spawn processor(proposals[i]) 38 | -------------------------------------------------------------------------------- /code/boundedbuffer.hny: -------------------------------------------------------------------------------- 1 | def BoundedBuffer(size) returns buffer: 2 | buffer = { .buffer: [], .size: size } 3 | 4 | def put(bb, v): 5 | atomically when len(bb->buffer) < bb->size: 6 | bb->buffer += [v,] 7 | 8 | def get(bb) returns next: 9 | atomically when bb->buffer != []: 10 | next = bb->buffer[0] 11 | del bb->buffer[0] 12 | -------------------------------------------------------------------------------- /code/boundedbuffer_hoare.hny: -------------------------------------------------------------------------------- 1 | import hoare 2 | 3 | def BoundedBuffer(size) returns buffer: 4 | buffer = { 5 | .mon: hoare.Monitor(), 6 | .prod: hoare.Condition(), .cons: hoare.Condition(), 7 | .buf: { x:() for x in {1..size} }, 8 | .head: 1, .tail: 1, 9 | .count: 0, .size: size 10 | } 11 | 12 | def Queue() returns empty: 13 | empty = BoundedBuffer(4) 14 | 15 | def put(bb, item): 16 | hoare.enter(?bb->mon) 17 | if bb->count == bb->size: 18 | hoare.wait(?bb->prod, ?bb->mon) 19 | bb->buf[bb->tail] = item 20 | bb->tail = (bb->tail % bb->size) + 1 21 | bb->count += 1 22 | hoare.signal(?bb->cons, ?bb->mon) 23 | hoare.exit(?bb->mon) 24 | 25 | def get(bb) returns next: 26 | hoare.enter(?bb->mon) 27 | if bb->count == 0: 28 | hoare.wait(?bb->cons, ?bb->mon) 29 | next = bb->buf[bb->head] 30 | bb->head = (bb->head % bb->size) + 1 31 | bb->count -= 1 32 | hoare.signal(?bb->prod, ?bb->mon) 33 | hoare.exit(?bb->mon) 34 | -------------------------------------------------------------------------------- /code/boundedbuffer_test1.hny: -------------------------------------------------------------------------------- 1 | import boundedbuffer 2 | 3 | def producer(bb, v): 4 | boundedbuffer.put(bb, v) 5 | 6 | def consumer(bb): 7 | let v = boundedbuffer.get(bb): 8 | assert v in { 1, 2 } 9 | 10 | testbb = boundedbuffer.BoundedBuffer(1) 11 | spawn producer(?testbb, 1) 12 | spawn producer(?testbb, 2) 13 | spawn consumer(?testbb) 14 | spawn consumer(?testbb) 15 | -------------------------------------------------------------------------------- /code/bsort.hny: -------------------------------------------------------------------------------- 1 | from barrier import * 2 | 3 | const N = 5 # size of list to be sorted 4 | 5 | thelist = [ choose { 1 .. N } for i in { 1 .. N } ] 6 | 7 | finally all(thelist[i-1] <= thelist[i] for i in { 1 .. N - 1 }) 8 | 9 | const NTHREADS = N / 2 10 | bar = Barrier(NTHREADS) 11 | count = [0,] * NTHREADS # to detect termination 12 | 13 | def sorter(self, i): 14 | var unsorted = True 15 | while unsorted: 16 | let old_count = count: 17 | bwait(?bar) # wait until all have assigned old_count 18 | 19 | # Even phase 20 | if thelist[i - 1] > thelist[i]: 21 | thelist[i - 1], thelist[i] = thelist[i], thelist[i - 1] 22 | count[self] += 1 23 | 24 | bwait(?bar) # wait until all have finished even phase 25 | 26 | # Odd phase 27 | if i < N - 1 and thelist[i] > thelist[i + 1]: 28 | thelist[i], thelist[i + 1] = thelist[i + 1], thelist[i] 29 | count[self] += 1 30 | 31 | bwait(?bar) # wait until all have finished odd phase 32 | 33 | # Sorted iff nobody swapped anything 34 | unsorted = count != old_count 35 | 36 | for k in { 0 .. NTHREADS - 1}: 37 | spawn sorter(k, 2*k + 1) 38 | -------------------------------------------------------------------------------- /code/byzbosco.hny: -------------------------------------------------------------------------------- 1 | import bags 2 | 3 | const F = 1 4 | const N = (5 * F) + 1 5 | const NROUNDS = 2 6 | 7 | network = bags.empty() 8 | decisions = {} 9 | 10 | def broadcast(msg): 11 | atomically network = bags.add(network, msg) 12 | 13 | def receive(round, k): 14 | let msgs = { e:c for (r,e):c in network where r == round }: 15 | result = bags.combinations(msgs, k) 16 | 17 | def process(_proposal): 18 | var proposal = _proposal 19 | broadcast(0, proposal) 20 | for round in {0..NROUNDS-1}: 21 | atomically when exists quorum in receive(round, N - F): 22 | let count = [ bags.multiplicity(quorum, i) for i in { 0..1 } ]: 23 | assert count[0] != count[1] 24 | proposal = 0 if count[0] > count[1] else 1 25 | if count[proposal] == (N - F): 26 | decisions |= { proposal } 27 | assert len(decisions) <= 1 28 | broadcast(round + 1, proposal) 29 | 30 | def adversary(): 31 | broadcast(0, 0) 32 | broadcast(0, 1) 33 | for round in {0..NROUNDS-1}: 34 | atomically when exists quorum in receive(round, N - F): 35 | broadcast(round + 1, 0) 36 | broadcast(round + 1, 1) 37 | 38 | for i in {1..N - F}: 39 | spawn process(choose({ 0, 1 })) 40 | for i in {1..F}: 41 | spawn adversary() 42 | -------------------------------------------------------------------------------- /code/chain1.hny: -------------------------------------------------------------------------------- 1 | const NREPLICAS = 3 # number of replicas 2 | const NOPS = 2 # number of operations (or clients) 3 | 4 | network = {} # the network is a set of messages 5 | 6 | def send(self, dst, msg): # send msg to replica dst 7 | atomically network |= { (dst, (self, msg)) } 8 | 9 | def broadcast(self, msg): # broadcast msg to all 10 | atomically for dst in {1..NREPLICAS}: 11 | network |= { (dst, (self, msg)) } 12 | 13 | def receive(self) returns msgs: # return messages for me 14 | msgs = { payload for (dst, payload) in network where (dst == self) } 15 | 16 | def crash(self): # server 'self' is crashing 17 | broadcast(self, "crash") # notify all other replicas 18 | stop() 19 | 20 | def is_prefix(hist1, hist2) returns result: # hist1 is a strict prefix of hist2 21 | result = (len(hist1) < len(hist2)) and 22 | all(hist1[i] == hist2[i] for i in {0..len(hist1)-1}) 23 | -------------------------------------------------------------------------------- /code/chainaction1.hny: -------------------------------------------------------------------------------- 1 | import lists, action 2 | 3 | const NREPLICAS = 3 4 | const NOPS = 2 5 | 6 | # Global state 7 | let immortal = choose {1..NREPLICAS}: 8 | replicas = { p: { .immortal: immortal == p, .crashed: False, 9 | .requests: {}, .hist: [], .config: {1..NREPLICAS}, 10 | .received: {}, .delivered: 0 } for p in {1..NREPLICAS} } 11 | clients = { c: { .sent_request: False } for c in {1..NOPS} } 12 | 13 | const is_head = lambda(p): p == min(replicas[p].config) end 14 | const is_tail = lambda(p): p == max(replicas[p].config) end 15 | 16 | def is_successor(self, p) returns result: 17 | let succ = { q for q in replicas[self].config where q > self }: 18 | result = False if succ == {} else (p == min(succ)) 19 | 20 | def do_sendOperation(c): 21 | print(c) 22 | clients[c].sent_request = True 23 | for p in {1..NREPLICAS}: 24 | replicas[p].requests |= { c } 25 | 26 | const sendOperation = lambda(): { ?do_sendOperation(c) 27 | for c in {1..NOPS} where not clients[c].sent_request } end 28 | 29 | def do_gotOperation(self, op): 30 | replicas[self].hist += [op,] 31 | 32 | const gotOperation = lambda(): { ?do_gotOperation(p, op) 33 | for p in {1..NREPLICAS} 34 | where not replicas[p].crashed and is_head(p) 35 | for op in replicas[p].requests 36 | where op not in replicas[p].hist } end 37 | 38 | def do_sendHist(self, p): 39 | replicas[p].received |= { replicas[self].hist } 40 | -------------------------------------------------------------------------------- /code/chainaction2.hny: -------------------------------------------------------------------------------- 1 | const sendHist = lambda(): { ?do_sendHist(p, q) 2 | for p in {1..NREPLICAS} 3 | where not replicas[p].crashed 4 | for q in {1..NREPLICAS} 5 | where is_successor(p, q) and (replicas[p].hist not in replicas[q].received) 6 | } end 7 | 8 | def do_gotHist(self, hist): 9 | replicas[self].hist = hist 10 | 11 | const gotHist = lambda(): { ?do_gotHist(p, hist) 12 | for p in {1..NREPLICAS} where not replicas[p].crashed 13 | for hist in replicas[p].received where (len(replicas[p].hist) < len(hist)) 14 | and lists.startswith(hist, replicas[p].hist) } end 15 | 16 | def do_deliver(self): 17 | print(self, replicas[self].hist[replicas[self].delivered]) 18 | replicas[self].delivered += 1 19 | 20 | const deliver = lambda(): { ?do_deliver(p) 21 | for p in {1..NREPLICAS} where not replicas[p].crashed and 22 | is_tail(p) and (len(replicas[p].hist) > replicas[p].delivered) } end 23 | 24 | def do_crash(self): 25 | replicas[self].crashed = True 26 | 27 | const crash = lambda(): { ?do_crash(p) 28 | for p in {1..NREPLICAS} 29 | where not replicas[p].crashed and not replicas[p].immortal } end 30 | 31 | def do_detect(self, p): 32 | replicas[self].config -= { p } 33 | 34 | const detect = lambda(): { ?do_detect(p, q) 35 | for p in {1..NREPLICAS} where not replicas[p].crashed 36 | for q in {1..NREPLICAS} where replicas[q].crashed and 37 | (q in replicas[p].config) } end 38 | 39 | action.explore({sendOperation, gotOperation, sendHist, 40 | gotHist, deliver, crash, detect}) 41 | -------------------------------------------------------------------------------- /code/clock.hny: -------------------------------------------------------------------------------- 1 | const FIFO = False 2 | 3 | def CLOCK(n) returns result: 4 | result = { .entries: [None,] * n, .recent: {}, .hand: 0, .misses: 0 } 5 | 6 | def ref(clock, x): 7 | if x not in clock->entries: 8 | while clock->entries[clock->hand] in clock->recent: 9 | clock->recent -= {clock->entries[clock->hand]} 10 | clock->hand = (clock->hand + 1) % len(clock->entries) 11 | clock->entries[clock->hand] = x 12 | clock->hand = (clock->hand + 1) % len(clock->entries) 13 | clock->misses += 1 14 | if not FIFO: 15 | clock->recent |= {x} 16 | 17 | clock3, clock4, refs = CLOCK(3), CLOCK(4), [] 18 | 19 | const VALUES = { 1..5 } 20 | 21 | var last = {} 22 | for i in {1..100}: 23 | let x = i if i < 5 else choose(VALUES - last): 24 | refs = refs + [x,] 25 | ref(?clock3, x); ref(?clock4, x) 26 | assert(clock4.misses <= clock3.misses) 27 | last = {x} 28 | -------------------------------------------------------------------------------- /code/consensus.hny: -------------------------------------------------------------------------------- 1 | const N = 4 2 | 3 | proposals = [ choose({0, 1}) for i in {0..N-1} ] 4 | decision = choose { x for x in proposals } 5 | 6 | def processor(proposal): 7 | if choose { False, True }: 8 | print decision 9 | 10 | print proposals 11 | for i in {0..N-1}: 12 | spawn processor(proposals[i]) 13 | -------------------------------------------------------------------------------- /code/counter.hny: -------------------------------------------------------------------------------- 1 | import synch 2 | 3 | const NCLIENTS = 3 4 | 5 | server_queue = synch.Queue() 6 | 7 | def server(): 8 | var counter = 0 9 | while True: 10 | let q = synch.get(?server_queue): # await request 11 | synch.put(q, counter) # send response 12 | counter += 1 13 | 14 | def client(client_queue): 15 | synch.put(?server_queue, client_queue) # send request 16 | let response = synch.get(client_queue): # await response 17 | print(response) 18 | 19 | spawn eternal server() 20 | 21 | alice_queue = synch.Queue() 22 | spawn client(?alice_queue) 23 | bob_queue = synch.Queue() 24 | spawn client(?bob_queue) 25 | charlie_queue = synch.Queue() 26 | spawn client(?charlie_queue) 27 | -------------------------------------------------------------------------------- /code/cs.hny: -------------------------------------------------------------------------------- 1 | # number of threads in the critical section 2 | in_cs = 0 3 | invariant in_cs in { 0, 1 } 4 | 5 | def thread(): 6 | while choose { False, True }: 7 | # Enter critical section 8 | atomically in_cs += 1 9 | 10 | # Critical section is here 11 | pass 12 | 13 | # Exit critical section 14 | atomically in_cs -= 1 15 | 16 | spawn thread() 17 | spawn thread() 18 | -------------------------------------------------------------------------------- /code/csbarebones.hny: -------------------------------------------------------------------------------- 1 | def thread(): 2 | while True: 3 | # Critical section is here 4 | pass 5 | 6 | spawn thread() 7 | spawn thread() 8 | -------------------------------------------------------------------------------- /code/csonebit.hny: -------------------------------------------------------------------------------- 1 | in_cs = 0 2 | invariant in_cs in { 0, 1 } 3 | 4 | sequential flags 5 | flags = [ False, False ] 6 | 7 | def thread(self): 8 | while choose({ False, True }): 9 | # Enter critical section 10 | flags[self] = True 11 | while flags[1 - self]: 12 | flags[self] = False 13 | flags[self] = True 14 | 15 | atomically in_cs += 1 16 | # Critical section 17 | atomically in_cs -= 1 18 | 19 | # Leave critical section 20 | flags[self] = False 21 | 22 | spawn thread(0) 23 | spawn thread(1) 24 | -------------------------------------------------------------------------------- /code/csonebitmulti.hny: -------------------------------------------------------------------------------- 1 | in_cs = 0 2 | invariant in_cs in { 0, 1 } 3 | 4 | const N = 5 5 | 6 | sequential flags 7 | flags = [ False, ] * N 8 | 9 | def thread(self): 10 | while choose({ False, True }): 11 | # Enter critical section 12 | flags[self] = True 13 | while any(flags[i] for i in { 0 .. N - 1 } where i != self): 14 | flags[self] = False 15 | flags[self] = True 16 | 17 | atomically in_cs += 1 18 | # Critical section 19 | atomically in_cs -= 1 20 | 21 | # Leave critical section 22 | flags[self] = False 23 | 24 | for i in { 0 .. N - 1 }: 25 | spawn thread(i) 26 | -------------------------------------------------------------------------------- /code/disk.hny: -------------------------------------------------------------------------------- 1 | from alloc import malloc 2 | 3 | def new(n_blocks) returns disk: 4 | disk = malloc([ None, ] * n_blocks) 5 | 6 | 7 | def getsize(disk) returns size: 8 | size = len !disk 9 | 10 | def read(disk, bno) returns contents: 11 | contents = (!disk)[bno] 12 | 13 | def write(disk, bno, block): 14 | (!disk)[bno] = block 15 | -------------------------------------------------------------------------------- /code/farmer.hny: -------------------------------------------------------------------------------- 1 | sides = [ { "goat", "cabbage", "wolf" }, {} ] 2 | farmer = 0 3 | 4 | def bad(side) returns judgment: 5 | judgment = ({ "goat", "cabbage" } <= side) or ({ "goat", "wolf" } <= side) 6 | 7 | while sides[0] != {}: 8 | let good = { x for x in (sides[farmer] | {"nothing"}) where not bad(sides[farmer] - {x}) } 9 | let x = choose good: 10 | print(str(farmer) + " -> " + str(1 - farmer) + ": " + x) 11 | if x != "nothing": 12 | sides[farmer] -= { x } 13 | sides[1 - farmer] |= { x } 14 | farmer = 1 - farmer 15 | -------------------------------------------------------------------------------- /code/file.hny: -------------------------------------------------------------------------------- 1 | from alloc import malloc 2 | 3 | def File(n_files) returns fs: 4 | fs = malloc([ [], ] * n_files) 5 | 6 | def read(fs, ino, offset) returns result: 7 | atomically result = (!fs)[ino][offset] if 0 <= offset < len (!fs)[ino] else None 8 | 9 | def write(fs, ino, offset, data) returns result: 10 | atomically: 11 | let n = len (!fs)[ino]: 12 | if 0 <= offset <= n: 13 | (!fs)[ino][offset] = data 14 | else: 15 | (!fs)[ino] += ([ None, ] * (offset - n)) + [data,] 16 | result = "ok" 17 | 18 | def delete(fs, ino) returns result: 19 | atomically: 20 | (!fs)[ino] = [] 21 | result = "ok" 22 | -------------------------------------------------------------------------------- /code/file_btest.hny: -------------------------------------------------------------------------------- 1 | from file import * 2 | 3 | const N_FILES = 2 4 | const MAX_FILE_SIZE = 2 5 | 6 | const N_READ = 1 7 | const N_WRITE = 1 8 | const N_DELETE = 1 9 | 10 | system = File(N_FILES) 11 | 12 | def read_test(i): 13 | let ino = choose { 0 .. N_FILES - 1 } 14 | let offset = choose { 0 .. MAX_FILE_SIZE - 1 }: 15 | print(i, "read", ino, offset) 16 | let data = read(system, ino, offset): 17 | print(i, "read done", ino, offset, data) 18 | 19 | def write_test(i): 20 | let ino = choose { 0 .. N_FILES - 1 } 21 | let offset = choose { 0 .. MAX_FILE_SIZE - 1 }: 22 | print(i, "write", ino, offset) 23 | write(system, ino, offset, i) 24 | print(i, "write done", ino, offset) 25 | 26 | def delete_test(i): 27 | let ino = choose { 0 .. N_FILES - 1 }: 28 | print(i, "delete", ino) 29 | delete(system, ino) 30 | print(i, "delete done", ino) 31 | 32 | for i in { 1 .. N_READ }: 33 | spawn read_test(i) 34 | for i in { 1 .. N_WRITE }: 35 | spawn write_test(i) 36 | for i in { 1 .. N_DELETE }: 37 | spawn delete_test(i) 38 | -------------------------------------------------------------------------------- /code/file_crash.hny: -------------------------------------------------------------------------------- 1 | from alloc import malloc 2 | 3 | def File(n_files) returns fs: 4 | fs = malloc([ [], ] * n_files) 5 | 6 | def read(fs, ino, offset) returns result: 7 | atomically result = choose { ("ok", (!fs)[ino][offset] if 0 <= offset < len (!fs)[ino] else None), "crash" } 8 | 9 | def write(fs, ino, offset, data) returns result: 10 | atomically: 11 | if choose { False, True }: 12 | let n = len (!fs)[ino]: 13 | if 0 <= offset <= n: 14 | (!fs)[ino][offset] = data 15 | else: 16 | (!fs)[ino] += ([ None, ] * (offset - n)) + [data,] 17 | result = choose { "ok", "crash" } 18 | else: 19 | result = "crash" 20 | 21 | 22 | def delete(fs, ino) returns result:: 23 | atomically: 24 | if choose { False, True }: 25 | (!fs)[ino] = [] 26 | result = choose { "ok", "crash" } 27 | else: 28 | result = "crash" 29 | -------------------------------------------------------------------------------- /code/gpu.hny: -------------------------------------------------------------------------------- 1 | const N = 10 2 | 3 | availGPUs = {1..N} 4 | 5 | def gpuAlloc() returns gpu: 6 | gpu = choose(availGPUs) 7 | availGPUs -= { result } 8 | 9 | def gpuRelease(gpu): 10 | availGPUs |= { gpu } 11 | -------------------------------------------------------------------------------- /code/hanoi.hny: -------------------------------------------------------------------------------- 1 | current = [ [1, 2, 3], [], [] ] 2 | 3 | while current[2] != [1, 2, 3]: 4 | let moves = { (s, d) for s in {0..2} for d in {0..2} 5 | where current[s] != [] 6 | where (current[d] == []) or (current[s][0] < current[d][0]) } 7 | let (src,dst) = choose moves: 8 | print str(src) + " -> " + str(dst) 9 | current[dst] = [current[src][0],] + current[dst] 10 | del current[src][0] 11 | -------------------------------------------------------------------------------- /code/hanoi2.hny: -------------------------------------------------------------------------------- 1 | def towers(n, src, dst, other): 2 | if n > 0: 3 | towers(n - 1, src, other, dst) 4 | print str(src) + " -> " + str(dst) 5 | towers(n - 1, other, dst, src) 6 | 7 | towers(3, 1, 2, 3) 8 | -------------------------------------------------------------------------------- /code/hello1.hny: -------------------------------------------------------------------------------- 1 | print "hello world" 2 | -------------------------------------------------------------------------------- /code/hello2.hny: -------------------------------------------------------------------------------- 1 | def handler(): 2 | print "interrupt" 3 | def thread(): 4 | trap handler() 5 | print "hello world" 6 | spawn thread() 7 | -------------------------------------------------------------------------------- /code/hello3.hny: -------------------------------------------------------------------------------- 1 | print choose { "hello", "world" } 2 | -------------------------------------------------------------------------------- /code/hello4.hny: -------------------------------------------------------------------------------- 1 | while choose { False, True }: 2 | print "hello world" 3 | -------------------------------------------------------------------------------- /code/hello5.hny: -------------------------------------------------------------------------------- 1 | def p(s): 2 | print s 3 | 4 | p("hello") 5 | p("world") 6 | -------------------------------------------------------------------------------- /code/hello6.hny: -------------------------------------------------------------------------------- 1 | def p(s): 2 | print s 3 | 4 | spawn p("hello") 5 | spawn p("world") 6 | -------------------------------------------------------------------------------- /code/hello7.hny: -------------------------------------------------------------------------------- 1 | def hello(name): 2 | print "hello" 3 | print name 4 | 5 | spawn hello("Lesley") 6 | spawn hello("Robbert") 7 | -------------------------------------------------------------------------------- /code/hello8.hny: -------------------------------------------------------------------------------- 1 | def hello(name): 2 | atomically: 3 | print "hello" 4 | print name 5 | 6 | spawn hello("Lesley") 7 | spawn hello("Robbert") 8 | -------------------------------------------------------------------------------- /code/hello9.hny: -------------------------------------------------------------------------------- 1 | x = False 2 | def f(): 3 | print "hello" 4 | atomically: x = True 5 | def g(): 6 | atomically when x: print "world" 7 | spawn f(); spawn g() 8 | -------------------------------------------------------------------------------- /code/hoare.hny: -------------------------------------------------------------------------------- 1 | import synch 2 | 3 | def Monitor() returns monitor: 4 | monitor = synch.Lock() 5 | 6 | def enter(mon): 7 | synch.acquire(mon) 8 | 9 | def exit(mon): 10 | synch.release(mon) 11 | 12 | def Condition() returns condition: 13 | condition = { .sema: synch.BinSema(True), .count: 0 } 14 | 15 | def wait(cond, mon): 16 | cond->count += 1 17 | exit(mon) 18 | synch.acquire(?cond->sema) 19 | cond->count -= 1 20 | 21 | def signal(cond, mon): 22 | if cond->count > 0: 23 | synch.release(?cond->sema) 24 | enter(mon) 25 | -------------------------------------------------------------------------------- /code/hw.hny: -------------------------------------------------------------------------------- 1 | const MAX_ITEMS = 3 2 | 3 | sequential back, items 4 | back = 0 5 | items = [None,] * MAX_ITEMS 6 | 7 | def inc(pcnt) returns prior: 8 | atomically: 9 | prior = !pcnt 10 | !pcnt += 1 11 | 12 | def exch(pv) returns prior: 13 | atomically: 14 | prior = !pv 15 | !pv = None 16 | 17 | def produce(item): 18 | items[inc(?back)] = item 19 | 20 | def consume() returns next: 21 | next = None 22 | while next == None: 23 | var i = 0 24 | while (i < back) and (next == None): 25 | next = exch(?items[i]) 26 | i += 1 27 | 28 | for i in {1..MAX_ITEMS}: 29 | spawn produce(i) 30 | for i in {1..choose({0..MAX_ITEMS})}: 31 | spawn consume() 32 | -------------------------------------------------------------------------------- /code/ky.hny: -------------------------------------------------------------------------------- 1 | # Knuth-Yao fair dice algorithm 2 | 3 | x = 0 4 | while x < 11: 5 | coin = choose { False, True } 6 | if x == 0: 7 | x = 1 if coin else 2 8 | elif x == 1: 9 | x = 3 if coin else 4 10 | elif x == 2: 11 | x = 5 if coin else 6 12 | elif x == 3: 13 | x = 1 if coin else 11 14 | elif x == 4: 15 | x = 12 if coin else 13 16 | elif x == 5: 17 | x = 14 if coin else 15 18 | elif x == 6: 19 | x = 16 if coin else 2 20 | 21 | print x 22 | -------------------------------------------------------------------------------- /code/ky2.hny: -------------------------------------------------------------------------------- 1 | # Knuth-Yao fair dice algorithm 2 | 3 | transitions = {0:(1,2),1:(3,4),2:(5,6),3:(1,11),4:(12,13),5:(14,15),6:(16,2)} 4 | 5 | x = 0 6 | while x < 11: 7 | x = transitions[x][choose { 0, 1 }] 8 | -------------------------------------------------------------------------------- /code/leader.hny: -------------------------------------------------------------------------------- 1 | const NIDS = 5 # number of identifiers 2 | 3 | network = {} # the network is a set of messages 4 | leader = 0 # used for checking correctness 5 | 6 | def send(msg): 7 | atomically network |= { msg } 8 | 9 | def receive(self) returns msg: 10 | msg = { (id, found) for (dst, id, found) in network where dst == self } 11 | 12 | def processor(self, succ): 13 | send(succ, self, False) 14 | var working = True 15 | while working: 16 | atomically when exists (id, found) in receive(self): 17 | if id == self: 18 | assert self == leader 19 | send(succ, id, True) 20 | elif id > self: 21 | assert self != leader 22 | send(succ, id, found) 23 | if found: 24 | working = False 25 | 26 | var ids, nprocs, procs = { 1 .. NIDS }, choose({ 1 .. NIDS }), [] 27 | for i in { 0 .. nprocs - 1 }: 28 | let next = choose(ids): 29 | ids -= { next } 30 | procs += [ next, ] 31 | if next > leader: 32 | leader = next 33 | for i in { 0 .. nprocs - 1 }: 34 | spawn processor(procs[i], procs[(i + 1) % nprocs]) 35 | -------------------------------------------------------------------------------- /code/lock.hny: -------------------------------------------------------------------------------- 1 | def Lock() returns result: 2 | result = False 3 | 4 | def acquire(lk): 5 | atomically when not !lk: 6 | !lk = True 7 | 8 | def release(lk): 9 | assert !lk 10 | atomically !lk = False 11 | -------------------------------------------------------------------------------- /code/lock_demo.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | 3 | const NTHREADS = 5 4 | 5 | thelock = Lock() 6 | 7 | def thread(): 8 | acquire(?thelock) 9 | pass # critical section is here 10 | release(?thelock) 11 | 12 | for i in {1..NTHREADS}: 13 | spawn thread() 14 | -------------------------------------------------------------------------------- /code/lock_susp.hny: -------------------------------------------------------------------------------- 1 | def Lock() returns result: 2 | result = { .acquired: False, .suspended: [] } 3 | 4 | def acquire(lk): 5 | atomically: 6 | if lk->acquired: 7 | stop ?lk->suspended[len lk->suspended] 8 | assert lk->acquired 9 | else: 10 | lk->acquired = True 11 | 12 | def release(lk): 13 | atomically: 14 | assert lk->acquired 15 | if lk->suspended == []: 16 | lk->acquired = False 17 | else: 18 | go (lk->suspended[0]) () 19 | del lk->suspended[0] 20 | -------------------------------------------------------------------------------- /code/lock_tas.hny: -------------------------------------------------------------------------------- 1 | def test_and_set(s) returns oldvalue: 2 | atomically: 3 | oldvalue = !s 4 | !s = True 5 | 6 | def atomic_store(p, v): 7 | atomically !p = v 8 | 9 | def Lock() returns initvalue: 10 | initvalue = False 11 | 12 | def acquire(lk): 13 | while test_and_set(lk): 14 | pass 15 | 16 | def release(lk): 17 | atomic_store(lk, False) 18 | -------------------------------------------------------------------------------- /code/lock_test1.hny: -------------------------------------------------------------------------------- 1 | import lock 2 | 3 | const N = 5 4 | 5 | in_cs = 0 6 | invariant in_cs in { 0, 1 } 7 | 8 | thelock = lock.Lock() 9 | 10 | def thread(): 11 | while choose({ False, True }): 12 | lock.acquire(?thelock) 13 | 14 | atomically in_cs += 1 15 | # Critical section 16 | atomically in_cs -= 1 17 | 18 | lock.release(?thelock) 19 | 20 | for i in {1..N}: 21 | spawn thread() 22 | -------------------------------------------------------------------------------- /code/lock_test2.hny: -------------------------------------------------------------------------------- 1 | import synch 2 | 3 | lock = synch.Lock() 4 | 5 | count = 0 6 | invariant 0 <= count <= 1 7 | 8 | def thread(): 9 | synch.acquire(?lock) 10 | 11 | atomically count += 1 12 | 13 | # critical section is here 14 | assert count == 1 15 | 16 | atomically count -= 1 17 | 18 | synch.release(?lock) 19 | 20 | for i in {1..5}: 21 | spawn thread() 22 | -------------------------------------------------------------------------------- /code/lock_test3.hny: -------------------------------------------------------------------------------- 1 | from lock import Lock, acquire, release 2 | 3 | const NTHREADS = 5 4 | 5 | thelock = Lock() 6 | in_cs = 0 7 | 8 | def thread(): 9 | while choose { False, True }: 10 | acquire(?thelock) 11 | atomically in_cs += 1 12 | assert in_cs == 1 13 | atomically in_cs -= 1 14 | release(?thelock) 15 | 16 | for i in {1..NTHREADS}: 17 | spawn thread() 18 | -------------------------------------------------------------------------------- /code/lock_ticket.hny: -------------------------------------------------------------------------------- 1 | const MAX_THREADS = 8 2 | 3 | def fetch_and_increment(p) returns oldvalue: 4 | atomically: 5 | oldvalue = !p 6 | !p = (!p + 1) % MAX_THREADS 7 | 8 | def atomic_load(p) returns value: 9 | atomically value = !p 10 | 11 | def Lock(): 12 | result = { .counter: 0, .dispenser: 0 } 13 | 14 | def acquire(lk): 15 | let my_ticket = fetch_and_increment(?lk->dispenser): 16 | while atomic_load(?lk->counter) != my_ticket: 17 | pass 18 | 19 | def release(lk): 20 | fetch_and_increment(?lk->counter) 21 | -------------------------------------------------------------------------------- /code/lossy.hny: -------------------------------------------------------------------------------- 1 | to_server = to_client = {} 2 | 3 | def send(chan, msg): 4 | if choose { False, True }: 5 | atomically !chan |= { msg } 6 | 7 | def receive(chan) returns msgs: 8 | atomically msgs = !chan 9 | 10 | def server(): 11 | while True: 12 | let msgs = receive(?to_server): 13 | if "ping" in msgs: 14 | send(?to_client, "pong") 15 | 16 | def client(): 17 | var done = False 18 | while not done: 19 | send(?to_server, "ping") 20 | let msgs = receive(?to_client): 21 | done = "pong" in msgs 22 | 23 | spawn client() 24 | spawn eternal server() 25 | -------------------------------------------------------------------------------- /code/magic.hny: -------------------------------------------------------------------------------- 1 | const N = 4 2 | 3 | sq = [ permuted({ 1 .. N }) for _ in { 1 .. N } ] 4 | 5 | def is_a_solution() returns good: 6 | good = True 7 | for i in { 0 .. N-1 }: 8 | if { sq[i][j] for j in { 0 .. N-1 } } != { 1 .. N }: 9 | good = False 10 | for i in { 0 .. N-1 }: 11 | if { sq[j][i] for j in { 0 .. N-1 } } != { 1 .. N }: 12 | good = False 13 | 14 | assert not is_a_solution() 15 | -------------------------------------------------------------------------------- /code/memory.hny: -------------------------------------------------------------------------------- 1 | const MEM_SIZE = 0x10 2 | const WORD_SIZE = 16 3 | 4 | const WORD_MASK = (1 << WORD_SIZE) - 1 5 | memory = [0,] * MEM_SIZE 6 | 7 | def hw_load(address) returns value: 8 | atomically value = memory[address] 9 | 10 | def hw_store(address, value): 11 | atomically memory[address] = value 12 | 13 | def load_double(address) returns value: 14 | value = hw_load(address) | (hw_load(address + 1) << WORD_SIZE) 15 | 16 | def store_double(address, value): 17 | hw_store(address, value & WORD_MASK) 18 | hw_store(address + 1, (value >> WORD_SIZE) & WORD_MASK) 19 | 20 | def f(): 21 | store_double(0x6, 0xffffffff) 22 | 23 | def g(): 24 | print hex(load_double(0x6)) 25 | 26 | spawn f() 27 | spawn g() 28 | -------------------------------------------------------------------------------- /code/mersenne.hny: -------------------------------------------------------------------------------- 1 | from synch import * 2 | 3 | const MAX = 10 4 | 5 | def isPrime(v) returns prime: 6 | prime = True 7 | var d = 2 8 | while prime and (d < v): 9 | if v % d == 0: 10 | prime = False 11 | d += 1 12 | 13 | q1 = q2 = q3 = Queue() 14 | 15 | def actor0(): 16 | for v in {2..MAX}: 17 | put(?q1, v) 18 | 19 | def actor1(): 20 | while True: 21 | let v = get(?q1): 22 | put(?q2, (2 ** v) - 1) 23 | 24 | def actor2(): 25 | while True: 26 | let v = get(?q2): 27 | if isPrime(v): 28 | put(?q3, v) 29 | 30 | def actor3(): 31 | while True: 32 | let v = get(?q3): 33 | print(v) 34 | 35 | spawn actor0() 36 | spawn eternal actor1() 37 | spawn eternal actor2() 38 | spawn eternal actor3() 39 | -------------------------------------------------------------------------------- /code/mesa.hny: -------------------------------------------------------------------------------- 1 | def Condition() returns condition: 2 | condition = bags.empty() 3 | 4 | def wait(c, lk): 5 | var cnt = 0 6 | let _, ctx = save(): 7 | atomically: 8 | cnt = bags.multiplicity(!c, ctx) 9 | !c = bags.add(!c, ctx) 10 | !lk = False 11 | atomically when (not !lk) and (bags.multiplicity(!c, ctx) <= cnt): 12 | !lk = True 13 | 14 | def notify(c): 15 | atomically if !c != bags.empty(): 16 | !c = bags.remove(!c, bags.bchoose(!c)) 17 | 18 | def notify_all(c): 19 | !c = bags.empty() 20 | -------------------------------------------------------------------------------- /code/multitest.hny: -------------------------------------------------------------------------------- 1 | def seq_test(): 2 | pass 3 | 4 | def conc_test1(): 5 | pass 6 | 7 | def conc_test2(): 8 | pass 9 | 10 | def conc_test3(): 11 | pass 12 | 13 | seq_test() 14 | let test = choose({ conc_test1, conc_test2, conc_test3 }): 15 | test() 16 | -------------------------------------------------------------------------------- /code/naiveFlags.hny: -------------------------------------------------------------------------------- 1 | in_cs = 0 2 | invariant in_cs in { 0, 1 } 3 | 4 | flags = [ False, False ] 5 | 6 | def thread(self): 7 | while choose({ False, True }): 8 | # Enter critical section 9 | flags[self] = True 10 | await not flags[1 - self] 11 | 12 | atomically in_cs += 1 13 | # Critical section 14 | atomically in_cs -= 1 15 | 16 | # Leave critical section 17 | flags[self] = False 18 | 19 | spawn thread(0) 20 | spawn thread(1) 21 | -------------------------------------------------------------------------------- /code/naiveLock.hny: -------------------------------------------------------------------------------- 1 | in_cs = 0 2 | invariant in_cs in { 0, 1 } 3 | 4 | lockTaken = False 5 | 6 | def thread(self): 7 | while choose({ False, True }): 8 | # Enter critical section 9 | await not lockTaken 10 | lockTaken = True 11 | 12 | atomically in_cs += 1 13 | # Critical section 14 | atomically in_cs -= 1 15 | 16 | # Leave critical section 17 | lockTaken = False 18 | 19 | spawn thread(0) 20 | spawn thread(1) 21 | -------------------------------------------------------------------------------- /code/naiveTurn.hny: -------------------------------------------------------------------------------- 1 | in_cs = 0 2 | invariant in_cs in { 0, 1 } 3 | 4 | turn = 0 5 | 6 | def thread(self): 7 | while choose({ False, True }): 8 | # Enter critical section 9 | turn = 1 - self 10 | await turn == self 11 | 12 | atomically in_cs += 1 13 | # Critical section 14 | atomically in_cs -= 1 15 | 16 | # Leave critical section 17 | 18 | spawn thread(0) 19 | spawn thread(1) 20 | -------------------------------------------------------------------------------- /code/olb.hny: -------------------------------------------------------------------------------- 1 | # one lane bridge (east-bound or west-bound only) 2 | 3 | def OLB() returns lock: 4 | lock = { .n_wb: 0, .n_eb: 0 } 5 | 6 | def wb_acquire(olb): 7 | atomically when olb->n_eb == 0: 8 | olb->n_wb += 1 9 | 10 | def wb_release(olb): 11 | atomically olb->n_wb -= 1 12 | 13 | def eb_acquire(olb): 14 | atomically when olb->n_wb == 0: 15 | olb->n_eb += 1 16 | 17 | def eb_release(olb): 18 | atomically olb->n_eb -= 1 19 | -------------------------------------------------------------------------------- /code/olb_btest.hny: -------------------------------------------------------------------------------- 1 | import olb 2 | 3 | const NOPS = 3 4 | 5 | bridge = olb.OLB() 6 | 7 | def thread(self): 8 | while choose({ False, True }): 9 | if choose({ "eb", "wb" }) == "eb": 10 | print(str(self) + ": eb ae") 11 | olb.eb_acquire(?bridge) 12 | print(str(self) + ": eb ad") 13 | 14 | print(str(self) + ": eb re") 15 | olb.eb_release(?bridge) 16 | print(str(self) + ": eb rd") 17 | else: # wb 18 | print(str(self) + ": wb ae") 19 | olb.wb_acquire(?bridge) 20 | print(str(self) + ": wb ad") 21 | 22 | print(str(self) + ": wb re") 23 | olb.wb_release(?bridge) 24 | print(str(self) + ": wb rd") 25 | 26 | for i in {1..NOPS}: 27 | spawn thread(i) 28 | -------------------------------------------------------------------------------- /code/olb_locks.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | 3 | def OLB() returns lock: 4 | lock = { 5 | .lock: Lock(), 6 | .eb: { .lock: Lock(), .n: 0 }, 7 | .wb: { .lock: Lock(), .n: 0 } 8 | } 9 | 10 | def wb_acquire(olb): 11 | acquire(?olb->wb.lock) 12 | if olb->wb.n == 0: 13 | acquire(?olb->lock) 14 | olb->wb.n += 1 15 | release(?olb->wb.lock) 16 | 17 | def wb_release(olb): 18 | acquire(?olb->wb.lock) 19 | olb->wb.n -= 1 20 | if olb->wb.n == 0: 21 | release(?olb->lock) 22 | release(?olb->wb.lock) 23 | 24 | def eb_acquire(olb): 25 | acquire(?olb->eb.lock) 26 | if olb->eb.n == 0: 27 | acquire(?olb->lock) 28 | olb->eb.n += 1 29 | release(?olb->eb.lock) 30 | 31 | def eb_release(olb): 32 | acquire(?olb->eb.lock) 33 | olb->eb.n -= 1 34 | if olb->eb.n == 0: 35 | release(?olb->lock) 36 | release(?olb->eb.lock) 37 | -------------------------------------------------------------------------------- /code/olb_test1.hny: -------------------------------------------------------------------------------- 1 | import olb 2 | 3 | n_eb = n_wb = 0 4 | invariant ((n_eb >= 0) and (n_wb == 0)) or ((n_wb >= 0) and (n_eb == 0)) 5 | 6 | const NOPS = 3 7 | 8 | bridge = olb.OLB() 9 | 10 | def thread(): 11 | while choose({ False, True }): 12 | if choose({ "eb", "wb" }) == "eb": 13 | olb.eb_acquire(?bridge) 14 | atomically n_eb += 1 15 | atomically n_eb -= 1 16 | olb.eb_release(?bridge) 17 | else: # wb 18 | olb.wb_acquire(?bridge) 19 | atomically n_wb += 1 20 | atomically n_wb -= 1 21 | olb.wb_release(?bridge) 22 | 23 | for i in {1..NOPS}: 24 | spawn thread() 25 | -------------------------------------------------------------------------------- /code/primes.hny: -------------------------------------------------------------------------------- 1 | from synch import * 2 | 3 | ranges = { (2,10), (11,20), (21,30) } 4 | queues = { r:Queue() for r in ranges } 5 | mainq = Queue() 6 | 7 | def isPrime(v) returns prime: 8 | prime = True 9 | var d = 2 10 | while prime and (d < v): 11 | if v % d == 0: 12 | prime = False 13 | d += 1 14 | 15 | def worker(q): 16 | while True: 17 | let rq, (start, finish) = get(q): 18 | for p in { start .. finish }: 19 | if isPrime(p): 20 | put(rq, p) 21 | 22 | def main(rq, workers): 23 | for r:q in workers: 24 | put(q, (rq, r)) 25 | while True: 26 | print get(rq) 27 | 28 | for r in ranges: 29 | spawn eternal worker(?queues[r]) 30 | spawn eternal main(?mainq, { r:?queues[r] for r in ranges }) 31 | -------------------------------------------------------------------------------- /code/prog1.hny: -------------------------------------------------------------------------------- 1 | x = True 2 | 3 | def f(): assert x 4 | def g(): x = False 5 | 6 | f() 7 | g() 8 | -------------------------------------------------------------------------------- /code/prog2.hny: -------------------------------------------------------------------------------- 1 | x = True 2 | 3 | def f(): assert x 4 | def g(): x = False 5 | 6 | spawn f() 7 | spawn g() 8 | -------------------------------------------------------------------------------- /code/prog3.hny: -------------------------------------------------------------------------------- 1 | x = 0 2 | 3 | def f(): x += 1 4 | 5 | f() 6 | f() 7 | 8 | finally x == 2 9 | -------------------------------------------------------------------------------- /code/prog4.hny: -------------------------------------------------------------------------------- 1 | x = 0 2 | 3 | def f(): x += 1 4 | 5 | spawn f() 6 | spawn f() 7 | 8 | finally x == 2 9 | -------------------------------------------------------------------------------- /code/prog4enter.hny: -------------------------------------------------------------------------------- 1 | x = 0 2 | entered = [ False, False ] 3 | 4 | def f(self): 5 | entered[self] = True 6 | await not entered[1 - self] 7 | x += 1 8 | entered[self] = False 9 | 10 | spawn f(0) 11 | spawn f(1) 12 | 13 | finally x == 2 14 | -------------------------------------------------------------------------------- /code/prog4lock.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | 3 | shared = 0 4 | thelock = Lock() 5 | 6 | def f(): 7 | acquire(?thelock) 8 | shared += 1 9 | release(?thelock) 10 | 11 | spawn f() 12 | spawn f() 13 | 14 | finally shared == 2 15 | -------------------------------------------------------------------------------- /code/prog5.hny: -------------------------------------------------------------------------------- 1 | x = 0 2 | 3 | def f(): 4 | var register = x; 5 | register += 1 6 | x = register 7 | 8 | spawn f() 9 | spawn f() 10 | 11 | finally x == 2 12 | -------------------------------------------------------------------------------- /code/qbarrier.hny: -------------------------------------------------------------------------------- 1 | from synch import Queue, put, get 2 | 3 | const NTHREADS = 3 4 | const NROUNDS = 4 5 | 6 | round = [0,] * NTHREADS 7 | invariant (max(round) - min(round)) <= 1 8 | 9 | q = [Queue(),] * NTHREADS 10 | 11 | def thread(self): 12 | for r in {1..NROUNDS}: 13 | for i in {0..NTHREADS-1} where i != self: 14 | put(?q[i], None) 15 | for i in {0..NTHREADS-1} where i != self: 16 | get(?q[self]) 17 | round[self] += 1 18 | 19 | for i in {0..NTHREADS-1}: 20 | spawn thread(i) 21 | -------------------------------------------------------------------------------- /code/qsort.hny: -------------------------------------------------------------------------------- 1 | def Qsort(arr) returns state: 2 | state = { .arr: arr, .todo: { (0, len(arr) - 1) } } 3 | 4 | def swap(p, q): # swap !p and !q 5 | !p, !q = !q, !p 6 | 7 | def partition(qs, lo, hi) returns pivot: 8 | pivot = lo 9 | for i in {lo..hi - 1}: 10 | if qs->arr[i] <= qs->arr[hi]: 11 | swap(?qs->arr[pivot], ?qs->arr[i]) 12 | pivot += 1 13 | swap(?qs->arr[pivot], ?qs->arr[hi]) 14 | 15 | def sortrange(qs, range): 16 | let lo, hi = range let pivot = partition(qs, lo, hi): 17 | if (pivot - 1) > lo: 18 | qs->todo |= { (lo, pivot - 1) } 19 | if (pivot + 1) < hi: 20 | qs->todo |= { (pivot + 1, hi) } 21 | 22 | def sort(qs) returns sorted_list: 23 | while qs->todo != {}: 24 | let range = choose(qs->todo): 25 | qs->todo -= { range } 26 | sortrange(qs, range) 27 | sorted_list = qs->arr 28 | -------------------------------------------------------------------------------- /code/qsorttest.hny: -------------------------------------------------------------------------------- 1 | import qsort, bags 2 | 3 | const NITEMS = 4 4 | 5 | a = [ choose({1..NITEMS}) for i in {1..choose({1..NITEMS})} ] 6 | testqs = qsort.Qsort(a) 7 | sa = qsort.sort(?testqs) 8 | assert all(sa[i - 1] <= sa[i] for i in {1..len(sa)-1}) # sorted? 9 | assert bags.fromList(a) == bags.fromList(sa) # is it a permutation? 10 | -------------------------------------------------------------------------------- /code/queue.hny: -------------------------------------------------------------------------------- 1 | def Queue() returns empty: 2 | empty = [] 3 | 4 | def put(q, v): 5 | atomically !q += [v,] 6 | 7 | def get(q) returns next: 8 | atomically: 9 | if !q == []: 10 | next = None 11 | else: 12 | next = (!q)[0] 13 | del (!q)[0] 14 | -------------------------------------------------------------------------------- /code/queue_MS.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release, atomic_load, atomic_store 2 | from alloc import malloc, free 3 | 4 | def Queue() returns empty: 5 | let dummy = malloc({ .value: (), .next: None }): 6 | empty = { .head: dummy, .tail: dummy, 7 | .hdlock: Lock(), .tllock: Lock() } 8 | 9 | def put(q, v): 10 | let node = malloc({ .value: v, .next: None }): 11 | acquire(?q->tllock) 12 | atomic_store(?q->tail->next, node) 13 | q->tail = node 14 | release(?q->tllock) 15 | 16 | def get(q) returns next: 17 | acquire(?q->hdlock) 18 | let dummy = q->head 19 | let node = atomic_load(?dummy->next): 20 | if node == None: 21 | next = None 22 | release(?q->hdlock) 23 | else: 24 | next = node->value 25 | q->head = node 26 | release(?q->hdlock) 27 | free(dummy) 28 | -------------------------------------------------------------------------------- /code/queue_block.hny: -------------------------------------------------------------------------------- 1 | def Queue(): 2 | result = [] 3 | 4 | def put(q, v): 5 | atomically !q += [v,] 6 | 7 | def get(q): 8 | atomically when !q != []: 9 | result = (!q)[0] 10 | del (!q)[0] 11 | -------------------------------------------------------------------------------- /code/queue_block_cv.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, Condition, acquire, release, wait, notify 2 | from alloc import malloc, free 3 | 4 | def Queue() returns empty: 5 | empty = { .head: None, .tail: None, .lock: Lock(), .cv: Condition() } 6 | 7 | def put(q, v): 8 | let node = malloc({ .value: v, .next: None }): 9 | acquire(?q->lock) 10 | if q->tail == None: 11 | q->tail = q->head = node 12 | else: 13 | q->tail->next = node 14 | q->tail = node 15 | notify(?q->cv) 16 | release(?q->lock) 17 | 18 | def get(q) returns next: 19 | acquire(?q->lock) 20 | while q->head == None: 21 | wait(?q->cv, ?q->lock) 22 | let node = q->head: 23 | next = node->value 24 | q->head = node->next 25 | if q->head == None: 26 | q->tail = None 27 | free(node) 28 | release(?q->lock) 29 | -------------------------------------------------------------------------------- /code/queue_broken1.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | 3 | def Queue() returns empty: 4 | empty = { .elements: [], .lock: Lock() } 5 | 6 | def put(q, v): 7 | acquire(?q->lock) 8 | q->elements += [v,] 9 | release(?q->lock) 10 | 11 | 12 | def get(q) returns next: 13 | acquire(?q->lock) 14 | if q->elements == []: 15 | next = None 16 | else: 17 | next = q->elements[0] 18 | release(?q->lock) 19 | acquire(?q->lock) 20 | if q->elements != []: 21 | del q->elements[0] 22 | release(?q->lock) 23 | -------------------------------------------------------------------------------- /code/queue_broken2.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | from alloc import malloc, free 3 | 4 | def Queue() returns empty: 5 | empty = { .next: None, .value: None, .lock: Lock() } 6 | 7 | def put(q, v): 8 | let node = malloc({ .next: None, .value: v, .lock: Lock() }): 9 | var nq = q 10 | while nq != None: 11 | acquire(?nq->lock) 12 | let n = nq->next: 13 | if n == None: 14 | nq->next = node 15 | release(?nq->lock) 16 | nq = n 17 | 18 | def get(q) returns next: 19 | acquire(?q->lock) 20 | if q->next == None: 21 | next = None 22 | else: 23 | let node = q->next: 24 | q->next = node->next 25 | next = node->value 26 | free(node) 27 | release(?q->lock) 28 | -------------------------------------------------------------------------------- /code/queue_btest1.hny: -------------------------------------------------------------------------------- 1 | import queue 2 | 3 | const NOPS = 4 4 | q = queue.Queue() 5 | 6 | def put_test(self): 7 | print("call put", self) 8 | queue.put(?q, self) 9 | print("done put", self) 10 | 11 | def get_test(self): 12 | print("call get", self) 13 | let v = queue.get(?q): 14 | print("done get", self, v) 15 | 16 | nputs = choose {1..NOPS-1} 17 | for i in {1..nputs}: 18 | spawn put_test(i) 19 | for i in {1..NOPS-nputs}: 20 | spawn get_test(i) 21 | -------------------------------------------------------------------------------- /code/queue_btest2.hny: -------------------------------------------------------------------------------- 1 | import queue 2 | 3 | const N_PUT = 2 4 | const N_GET = 2 5 | q = queue.Queue() 6 | 7 | def put_test(self): 8 | print("call put", self) 9 | queue.put(?q, self) 10 | print("done put", self) 11 | 12 | def get_test(self): 13 | print("call get", self) 14 | let v = queue.get(?q): 15 | print("done get", self, v) 16 | 17 | for i in {1..N_PUT}: 18 | spawn put_test(i) 19 | for i in {1..N_GET}: 20 | spawn get_test(i) 21 | -------------------------------------------------------------------------------- /code/queue_cas.hny: -------------------------------------------------------------------------------- 1 | from alloc import malloc, free 2 | from synch import cas 3 | 4 | def Queue(): 5 | let node = malloc({.next: {.ptr: None, .cnt: 0}}): 6 | result = { 7 | .head: { .ptr: node, .cnt: 0 }, 8 | .tail: { .ptr: node, .cnt: 0 } 9 | } 10 | 11 | def put(q, v): 12 | let node = malloc({ .value: v, .next: { .ptr: None, .cnt: 0 } }): 13 | var tail, done = None, False 14 | while not done: 15 | tail = q->tail 16 | let next = tail.ptr->next: 17 | if tail == q->tail: 18 | if next.ptr == None: 19 | done = cas(?tail.ptr->next, next, 20 | { .ptr: node, .cnt: next.cnt + 1 }) 21 | else: 22 | cas(?q->tail, tail, 23 | { .ptr: next.ptr, .cnt: tail.cnt + 1 }) 24 | cas(?q->tail, tail, { .ptr: node, .cnt: tail.cnt + 1 }) 25 | 26 | def get(q): 27 | var done = False 28 | while not done: 29 | let head, tail = q->head, q->tail 30 | let next = head.ptr->next: 31 | if head == q->head: 32 | if head.ptr == tail.ptr: 33 | if next.ptr == None: 34 | result = None 35 | done = True 36 | else: 37 | cas(?q->tail, tail, 38 | { .ptr: next.ptr, .cnt: tail.cnt + 1 }) 39 | else: 40 | result = next.ptr->value 41 | done = cas(?q->head, head, 42 | { .ptr: next.ptr, .cnt: head.cnt + 1 }) 43 | # if done: 44 | # free(head.ptr) 45 | -------------------------------------------------------------------------------- /code/queue_direct.hny: -------------------------------------------------------------------------------- 1 | builtin iq_new "bogus$iq_new" 2 | def iq_new() returns iq: 3 | pass 4 | 5 | builtin iq_enqueue "bogus$iq_enqueue" 6 | def iq_enqueue(iq, v): 7 | pass 8 | 9 | builtin iq_dequeue "bogus$iq_dequeue" 10 | def iq_dequeue(iq, v) returns item: 11 | pass 12 | 13 | def Queue() returns nq: 14 | nq = iq_new() 15 | 16 | def put(q, v): 17 | iq_enqueue(!q, v) 18 | 19 | def get(q) returns item: 20 | item = iq_dequeue(!q) 21 | -------------------------------------------------------------------------------- /code/queue_fix.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | from alloc import malloc, free 3 | 4 | def Queue() returns empty: 5 | empty = { .next: None, .value: None, .lock: Lock() } 6 | 7 | def put(q, v): 8 | var nq = q 9 | let node = malloc({ .next: None, .value: v, .lock: Lock() }): 10 | acquire(?nq->lock) 11 | var n = nq->next 12 | while n != None: 13 | acquire(?n->lock) 14 | release(?nq->lock) 15 | nq = n 16 | n = n->next 17 | nq->next = node 18 | release(?nq->lock) 19 | 20 | def get(q) returns next: 21 | acquire(?q->lock) 22 | if q->next == None: 23 | next = None 24 | else: 25 | let node = q->next: 26 | acquire(?node->lock) 27 | q->next = node->next 28 | next = node->value 29 | release(?node->lock) 30 | free(node) 31 | release(?q->lock) 32 | -------------------------------------------------------------------------------- /code/queue_lin.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | from alloc import malloc, free 3 | 4 | def Queue(): 5 | result = { .head: None, .tail: None, .lock: Lock(), .time: 0 } 6 | 7 | def _linpoint(q): 8 | atomically: 9 | this.qtime = q->time 10 | q->time += 1 11 | 12 | def put(q, v): 13 | let node = malloc({ .value: v, .next: None }): 14 | acquire(?q->lock) 15 | if q->tail == None: 16 | q->tail = q->head = node 17 | else: 18 | q->tail->next = node 19 | q->tail = node 20 | _linpoint(q) 21 | release(?q->lock) 22 | 23 | def get(q): 24 | acquire(?q->lock) 25 | let node = q->head: 26 | if node == None: 27 | result = None 28 | else: 29 | result = node->value 30 | q->head = node->next 31 | if q->head == None: 32 | q->tail = None 33 | free(node) 34 | _linpoint(q) 35 | release(?q->lock) 36 | -------------------------------------------------------------------------------- /code/queue_lock.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | from alloc import malloc, free 3 | 4 | def Queue() returns empty: 5 | empty = { .head: None, .tail: None, .lock: Lock() } 6 | 7 | def put(q, v): 8 | let node = malloc({ .value: v, .next: None }): 9 | acquire(?q->lock) 10 | if q->tail == None: 11 | q->tail = q->head = node 12 | else: 13 | q->tail->next = node 14 | q->tail = node 15 | release(?q->lock) 16 | 17 | def get(q) returns next: 18 | acquire(?q->lock) 19 | let node = q->head: 20 | if node == None: 21 | next = None 22 | else: 23 | next = node->value 24 | q->head = node->next 25 | if q->head == None: 26 | q->tail = None 27 | free(node) 28 | release(?q->lock) 29 | -------------------------------------------------------------------------------- /code/queue_nonatom.hny: -------------------------------------------------------------------------------- 1 | def Queue() returns empty: 2 | empty = [] 3 | 4 | def put(q, v): 5 | !q += [v,] 6 | 7 | 8 | def get(q) returns next: 9 | if !q == []: 10 | next = None 11 | else: 12 | next = (!q)[0] 13 | del (!q)[0] 14 | -------------------------------------------------------------------------------- /code/queue_nonatom_seq.hny: -------------------------------------------------------------------------------- 1 | def Queue() returns empty: 2 | empty = { .data: [], .head: 0, .tail: 0 } 3 | 4 | def put(q, v): 5 | let i = q->tail: 6 | q->data[i] = v 7 | q->tail = i + 1 8 | 9 | def get(q) returns next: 10 | let i = q->head: 11 | if i == q->tail: 12 | next = None 13 | else: 14 | next = q->data[i] 15 | q->head = i + 1 16 | -------------------------------------------------------------------------------- /code/queue_test1.hny: -------------------------------------------------------------------------------- 1 | import queue 2 | 3 | def sender(q, v): 4 | queue.put(q, v) 5 | 6 | def receiver(q): 7 | let v = queue.get(q): 8 | assert v in { None, 1, 2 } 9 | 10 | demoq = queue.Queue() 11 | spawn sender(?demoq, 1) 12 | spawn sender(?demoq, 2) 13 | spawn receiver(?demoq) 14 | spawn receiver(?demoq) 15 | -------------------------------------------------------------------------------- /code/queue_test2.hny: -------------------------------------------------------------------------------- 1 | import queue 2 | 3 | const NTHREADS = 4 4 | 5 | myq = queue.Queue() 6 | 7 | def thread(v): 8 | if choose({.put, .get}) == .put: 9 | queue.put(?myq, v) 10 | else: 11 | let w = queue.get(?myq): 12 | assert (w == None) or (w in {1..NTHREADS}) 13 | 14 | for i in {1..NTHREADS}: 15 | spawn thread(i) 16 | -------------------------------------------------------------------------------- /code/queue_test3.hny: -------------------------------------------------------------------------------- 1 | import queue 2 | 3 | const N = 3 4 | 5 | sequential putcount 6 | 7 | testq = queue.Queue() 8 | putcount = 0 9 | 10 | def putter(v): 11 | queue.put(?testq, v) 12 | atomically putcount += 1 13 | 14 | def main(): 15 | await putcount == N 16 | var gotten = {} 17 | while gotten != {0..N-1}: 18 | let v = queue.get(?testq): 19 | assert v not in gotten 20 | gotten |= {v} 21 | let v = queue.get(?testq): 22 | assert v == None 23 | 24 | for i in {0..N-1}: 25 | spawn putter(i) 26 | spawn main() 27 | -------------------------------------------------------------------------------- /code/queue_test4.hny: -------------------------------------------------------------------------------- 1 | import queue 2 | 3 | const N = 3 4 | 5 | sequential gotten 6 | 7 | testq = queue.Queue() 8 | for i in {0..N-1}: 9 | queue.put(?testq, i) 10 | gotten = {} 11 | 12 | def getter(): 13 | let v = queue.get(?testq): 14 | atomically: 15 | assert v not in gotten 16 | assert v != None 17 | gotten |= {v} 18 | 19 | def main(): 20 | await gotten == {0..N-1} 21 | let v = queue.get(?testq): 22 | assert v == None 23 | 24 | for i in {0..N-1}: 25 | spawn getter() 26 | spawn main() 27 | -------------------------------------------------------------------------------- /code/queue_test5.hny: -------------------------------------------------------------------------------- 1 | import queue 2 | 3 | const N = 2 4 | 5 | testq = queue.Queue() 6 | gotten = {:} 7 | 8 | def putter(i): 9 | queue.put(?testq, (i, 1)) 10 | queue.put(?testq, (i, 2)) 11 | 12 | def getter(i): 13 | let x = queue.get(?testq) 14 | let y = queue.get(?testq): 15 | gotten[i] = (x, y) 16 | if (x != None) and (y != None): 17 | assert (x[0] != y[0]) or ((x[1], y[1]) == (1, 2)) 18 | 19 | for i in {0..N-1}: 20 | spawn putter(i) 21 | spawn getter(i) 22 | -------------------------------------------------------------------------------- /code/queue_test6.hny: -------------------------------------------------------------------------------- 1 | import queue 2 | 3 | q1 = q2 = queue.Queue() 4 | queue.put(?q1, 1) 5 | queue.put(?q2, 2) 6 | 7 | def getter(q, v): 8 | let x = queue.get(q): 9 | assert x == v 10 | 11 | spawn getter(?q1, 1) 12 | spawn getter(?q2, 2) 13 | -------------------------------------------------------------------------------- /code/queue_test_lin.hny: -------------------------------------------------------------------------------- 1 | import queuelin, queuespec 2 | 3 | const NOPS = 4 4 | const VALUES = { 1..NOPS } 5 | 6 | sequential qtime 7 | qtime = 0 8 | 9 | implq = queuelin.Queue() 10 | specq = queuespec.Queue() 11 | 12 | def thread(): 13 | let op = choose({ "get", "put" }): 14 | if op == "put": 15 | let v = choose(VALUES): 16 | queuelin.put(?implq, v) 17 | await qtime == this.qtime 18 | queuespec.put(?specq, v) 19 | else: 20 | let v = queuelin.get(?implq): 21 | await qtime == this.qtime 22 | let w = queuespec.get(?specq): 23 | assert v == w 24 | atomically qtime += 1 25 | 26 | for i in {1..NOPS}: 27 | spawn thread() 28 | -------------------------------------------------------------------------------- /code/queue_test_seq.hny: -------------------------------------------------------------------------------- 1 | import queue, queueconc 2 | 3 | const NOPS = 4 4 | const VALUES = { 1..NOPS } 5 | 6 | specq = queue.Queue() 7 | implq = queueconc.Queue() 8 | 9 | for i in {1..NOPS}: 10 | let op = choose({ "get", "put" }): 11 | if op == "put": 12 | let v = choose(VALUES): 13 | queueconc.put(?implq, v) 14 | queue.put(?specq, v) 15 | else: 16 | let v = queueconc.get(?implq) 17 | let w = queue.get(?specq): 18 | assert v == w 19 | -------------------------------------------------------------------------------- /code/register.hny: -------------------------------------------------------------------------------- 1 | reg = None 2 | 3 | def init(): 4 | pass 5 | 6 | def read(uid) returns contents: 7 | atomically contents = reg 8 | 9 | def write(uid, v): 10 | atomically reg = v 11 | -------------------------------------------------------------------------------- /code/rollercoaster.hny: -------------------------------------------------------------------------------- 1 | from synch import * 2 | 3 | def RollerCoaster(nseats): result = { 4 | .mutex: Lock(), .nseats: nseats, .entered: 0, .left: nseats, 5 | .empty: Condition(), .full: Condition() 6 | } 7 | 8 | def enter(b): 9 | acquire(?b->mutex) 10 | while b->entered == b->nseats: # wait for car to empty out 11 | wait(?b->empty, ?b->mutex) 12 | b->entered += 1 13 | if b->entered != b->nseats: # wait for car to fill up 14 | while b->entered < b->nseats: 15 | wait(?b->full, ?b->mutex) 16 | else: # car is ready to go 17 | b->left = 0 18 | notify_all(?b->full) # wake up others waiting in car 19 | release(?b->mutex) 20 | 21 | def exit(b): 22 | acquire(?b->mutex) 23 | assert b->entered == b->nseats 24 | b->left += 1 25 | if b->left == b->nseats: # car is empty 26 | b->entered = 0 27 | # notify_all(?b->empty) # wake up riders wanting to go 28 | notify(?b->empty) 29 | notify(?b->empty) 30 | notify(?b->empty) 31 | notify(?b->empty) 32 | release(?b->mutex) 33 | 34 | const NSEATS = 4 35 | const NTHREADS = 8 36 | 37 | therc = RollerCoaster(NSEATS) 38 | 39 | def student(): 40 | enter(?therc) 41 | exit(?therc) 42 | 43 | for _ in { 1 .. NTHREADS }: 44 | spawn student() 45 | -------------------------------------------------------------------------------- /code/rsm.hny: -------------------------------------------------------------------------------- 1 | const NREPLICAS = 3 # number of replicas 2 | const NOPS = 2 # number of operations 3 | 4 | network = [] # the network is a queue of messages 5 | 6 | def crash(): 7 | stop() 8 | 9 | def send(msg): 10 | atomically network += [msg,] 11 | 12 | def replica(self, immortal): 13 | if not immortal: 14 | trap crash() 15 | var delivered = 0 16 | while True: 17 | atomically when len(network) > delivered: 18 | let msg = network[delivered]: 19 | print(self, msg) 20 | delivered += 1 21 | 22 | def client(self): 23 | print(self) 24 | send(self) 25 | 26 | let immortal = choose {1..NREPLICAS}: 27 | for i in {1..NREPLICAS}: 28 | spawn eternal replica(i, i == immortal) 29 | for i in {1..NOPS}: 30 | spawn client(i) 31 | -------------------------------------------------------------------------------- /code/rsmspec.hny: -------------------------------------------------------------------------------- 1 | const NREPLICAS = 3 # number of replicas 2 | const NOPS = 3 # number of operations 3 | 4 | network = [] # the network is a queue of messages 5 | 6 | def send(msg): 7 | atomically network += [msg,] 8 | 9 | def replica(immortal): 10 | var hist = [] 11 | while choose({ immortal, True }) and (len(hist) < NOPS): 12 | atomically when len(network) > len(hist): 13 | hist += [network[len(hist)],] 14 | if len(hist) == NOPS: # successful completion 15 | assert hist == network 16 | assert choose({1..NOPS}) in hist 17 | print hist 18 | 19 | def client(self): 20 | send(self) 21 | 22 | let survivor = choose({ 0 .. NREPLICAS - 1 }): 23 | for i in { 0 .. NREPLICAS - 1 }: 24 | spawn replica(i == survivor) 25 | for i in {1..NOPS}: 26 | spawn client(i) 27 | -------------------------------------------------------------------------------- /code/rwlock.hny: -------------------------------------------------------------------------------- 1 | def RWlock() returns lock: 2 | lock = { .nreaders: 0, .nwriters: 0 } 3 | 4 | def read_acquire(rw): 5 | atomically when rw->nwriters == 0: 6 | rw->nreaders += 1 7 | 8 | def read_release(rw): 9 | atomically rw->nreaders -= 1 10 | 11 | def write_acquire(rw): 12 | atomically when (rw->nreaders == 0) and (rw->nwriters == 0): 13 | rw->nwriters = 1 14 | 15 | def write_release(rw): 16 | atomically rw->nwriters = 0 17 | -------------------------------------------------------------------------------- /code/rwlock_btest.hny: -------------------------------------------------------------------------------- 1 | import rwlock 2 | 3 | const NOPS = 3 4 | 5 | rw = rwlock.RWlock() 6 | 7 | def thread(self): 8 | while choose({ False, True }): 9 | if choose({ "read", "write" }) == "read": 10 | print(self, "enter ra") 11 | rwlock.read_acquire(?rw) 12 | print(self, "exit ra") 13 | 14 | print(self, "enter rr") 15 | rwlock.read_release(?rw) 16 | print(self, "exit rr") 17 | else: # write 18 | print(self, "enter wa") 19 | rwlock.write_acquire(?rw) 20 | print(self, "exit wa") 21 | 22 | print(self, "enter wr") 23 | rwlock.write_release(?rw) 24 | print(self, "enter wr") 25 | 26 | for i in {1..NOPS}: 27 | spawn thread(i) 28 | -------------------------------------------------------------------------------- /code/rwlock_btest2.hny: -------------------------------------------------------------------------------- 1 | import rwlock 2 | 3 | const N_READERS = 2 4 | const N_WRITERS = 1 5 | 6 | rw = rwlock.RWlock() 7 | 8 | def reader(self): 9 | print(self, "enter ra") 10 | rwlock.read_acquire(?rw) 11 | print(self, "exit ra") 12 | 13 | print(self, "enter rr") 14 | rwlock.read_release(?rw) 15 | print(self, "exit rr") 16 | 17 | def writer(self): 18 | print(self, "enter wa") 19 | rwlock.write_acquire(?rw) 20 | print(self, "exit wa") 21 | 22 | print(self, "enter wr") 23 | rwlock.write_release(?rw) 24 | print(self, "enter wr") 25 | 26 | for i in {1..N_READERS}: 27 | spawn reader(i) 28 | for i in {1..N_WRITERS}: 29 | spawn writer(i) 30 | -------------------------------------------------------------------------------- /code/rwlock_busy.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | 3 | def RWlock() returns lock: 4 | lock = { .lock: Lock(), .nreaders: 0, .nwriters: 0 } 5 | 6 | def read_acquire(rw): 7 | acquire(?rw->lock) 8 | while rw->nwriters > 0: 9 | release(?rw->lock) 10 | acquire(?rw->lock) 11 | rw->nreaders += 1 12 | release(?rw->lock) 13 | 14 | def read_release(rw): 15 | acquire(?rw->lock) 16 | rw->nreaders -= 1 17 | release(?rw->lock) 18 | 19 | def write_acquire(rw): 20 | acquire(?rw->lock) 21 | while rw->nreaders > 0 or rw->nwriters > 0: 22 | release(?rw->lock) 23 | acquire(?rw->lock) 24 | rw->nwriters = 1 25 | release(?rw->lock) 26 | 27 | def write_release(rw): 28 | acquire(?rw->lock) 29 | rw->nwriters = 0 30 | release(?rw->lock) 31 | -------------------------------------------------------------------------------- /code/rwlock_cheat.hny: -------------------------------------------------------------------------------- 1 | import synch 2 | 3 | def RWlock() returns lock: 4 | lock = synch.Lock() 5 | 6 | def read_acquire(rw): 7 | synch.acquire(rw) 8 | 9 | def read_release(rw): 10 | synch.release(rw) 11 | 12 | def write_acquire(rw): 13 | synch.acquire(rw) 14 | 15 | def write_release(rw): 16 | synch.release(rw) 17 | -------------------------------------------------------------------------------- /code/rwlock_cv.hny: -------------------------------------------------------------------------------- 1 | from synch import * 2 | 3 | def RWlock() returns lock: 4 | lock = { 5 | .nreaders: 0, .nwriters: 0, .mutex: Lock(), 6 | .r_cond: Condition(), .w_cond: Condition() 7 | } 8 | 9 | def read_acquire(rw): 10 | acquire(?rw->mutex) 11 | while rw->nwriters > 0: 12 | wait(?rw->r_cond, ?rw->mutex) 13 | rw->nreaders += 1 14 | release(?rw->mutex) 15 | 16 | def read_release(rw): 17 | acquire(?rw->mutex) 18 | rw->nreaders -= 1 19 | if rw->nreaders == 0: 20 | notify(?rw->w_cond) 21 | release(?rw->mutex) 22 | 23 | def write_acquire(rw): 24 | acquire(?rw->mutex) 25 | while rw->nreaders > 0 or rw->nwriters > 0: 26 | wait(?rw->w_cond, ?rw->mutex) 27 | rw->nwriters = 1 28 | release(?rw->mutex) 29 | 30 | def write_release(rw): 31 | acquire(?rw->mutex) 32 | rw->nwriters = 0 33 | notify_all(?rw->r_cond) 34 | notify(?rw->w_cond) 35 | release(?rw->mutex) 36 | -------------------------------------------------------------------------------- /code/rwlock_sbs.hny: -------------------------------------------------------------------------------- 1 | from synch import BinSema, acquire, release 2 | 3 | def RWlock() returns lock: 4 | lock = { 5 | .nreaders: 0, .nwriters: 0, .mutex: BinSema(False), 6 | .r_gate: { .sema: BinSema(True), .count: 0 }, 7 | .w_gate: { .sema: BinSema(True), .count: 0 } 8 | } 9 | 10 | def _release_one(rw): 11 | if (rw->nwriters == 0) and (rw->r_gate.count > 0): 12 | release(?rw->r_gate.sema) 13 | elif (rw->nreaders + rw->nwriters == 0) and (rw->w_gate.count > 0): 14 | release(?rw->w_gate.sema) 15 | else: 16 | release(?rw->mutex) 17 | 18 | def read_acquire(rw): 19 | acquire(?rw->mutex) 20 | if rw->nwriters > 0: 21 | rw->r_gate.count += 1; _release_one(rw) 22 | acquire(?rw->r_gate.sema); rw->r_gate.count -= 1 23 | rw->nreaders += 1 24 | _release_one(rw) 25 | 26 | def read_release(rw): 27 | acquire(?rw->mutex); rw->nreaders -= 1; _release_one(rw) 28 | 29 | def write_acquire(rw): 30 | acquire(?rw->mutex) 31 | if rw->nreaders > 0 or rw->nwriters > 0: 32 | rw->w_gate.count += 1; _release_one(rw) 33 | acquire(?rw->w_gate.sema); rw->w_gate.count -= 1 34 | rw->nwriters += 1 35 | _release_one(rw) 36 | 37 | def write_release(rw): 38 | acquire(?rw->mutex); rw->nwriters -= 1; _release_one(rw) 39 | -------------------------------------------------------------------------------- /code/rwlock_sbs_fair.hny: -------------------------------------------------------------------------------- 1 | from synch import BinSema, acquire, release 2 | 3 | def RWlock() returns lock: 4 | lock = { 5 | .nreaders: 0, .nwriters: 0, .mutex: BinSema(False), 6 | .r_gate: { .sema: BinSema(True), .count: 0 }, 7 | .w_gate: { .sema: BinSema(True), .count: 0 } 8 | } 9 | 10 | def read_acquire(rw): 11 | acquire(?rw->mutex) 12 | if (rw->nwriters > 0) or (rw->w_gate.count > 0): 13 | rw->r_gate.count += 1; release(?rw->mutex) 14 | acquire(?rw->r_gate.sema); rw->r_gate.count -= 1 15 | rw->nreaders += 1 16 | if rw->r_gate.count > 0: 17 | release(?rw->r_gate.sema) 18 | else: 19 | release(?rw->mutex) 20 | 21 | def read_release(rw): 22 | acquire(?rw->mutex) 23 | rw->nreaders -= 1 24 | if (rw->w_gate.count > 0) and (rw->nreaders == 0): 25 | release(?rw->w_gate.sema) 26 | else: 27 | release(?rw->mutex) 28 | 29 | def write_acquire(rw): 30 | acquire(?rw->mutex) 31 | if rw->nreaders > 0 or rw->nwriters > 0: 32 | rw->w_gate.count += 1; release(?rw->mutex) 33 | acquire(?rw->w_gate.sema); rw->w_gate.count -= 1 34 | rw->nwriters += 1 35 | release(?rw->mutex) 36 | 37 | def write_release(rw): 38 | acquire(?rw->mutex) 39 | rw->nwriters -= 1 40 | if rw->r_gate.count > 0: 41 | release(?rw->r_gate.sema) 42 | elif rw->w_gate.count > 0: 43 | release(?rw->w_gate.sema) 44 | else: 45 | release(?rw->mutex) 46 | -------------------------------------------------------------------------------- /code/rwlock_test1.hny: -------------------------------------------------------------------------------- 1 | import rwlock 2 | 3 | nreaders = nwriters = 0 4 | invariant ((nreaders >= 0) and (nwriters == 0)) or 5 | ((nreaders == 0) and (nwriters == 1)) 6 | 7 | const NOPS = 4 8 | 9 | rw = rwlock.RWlock() 10 | 11 | def thread(): 12 | while choose({ False, True }): 13 | if choose({ "read", "write" }) == "read": 14 | rwlock.read_acquire(?rw) 15 | atomically nreaders += 1 16 | atomically nreaders -= 1 17 | rwlock.read_release(?rw) 18 | else: # write 19 | rwlock.write_acquire(?rw) 20 | atomically nwriters += 1 21 | atomically nwriters -= 1 22 | rwlock.write_release(?rw) 23 | 24 | for i in {1..NOPS}: 25 | spawn thread() 26 | -------------------------------------------------------------------------------- /code/setobj.hny: -------------------------------------------------------------------------------- 1 | from alloc import malloc 2 | 3 | def SetObject() returns object: 4 | object = malloc({}) 5 | 6 | def insert(s, v): 7 | atomically !s |= {v} 8 | 9 | def remove(s, v): 10 | atomically !s -= {v} 11 | 12 | def contains(s, v) returns present: 13 | atomically present = v in !s 14 | -------------------------------------------------------------------------------- /code/setobj_btest.hny: -------------------------------------------------------------------------------- 1 | from setobj import * 2 | 3 | const N_CONTAINS = 2 4 | const N_INSERT = 2 5 | const N_REMOVE = 2 6 | 7 | myset = SetObject() 8 | 9 | def test_contains(self): 10 | print("contains", self) 11 | let v = contains(myset, 1): 12 | print("contains done", self, v) 13 | 14 | def test_insert(self): 15 | print("insert", self) 16 | insert(myset, self) 17 | print("insert done", self) 18 | 19 | def test_remove(self): 20 | print("remove", self) 21 | remove(myset, self) 22 | print("remove done", self) 23 | 24 | for i in { 1 .. N_CONTAINS }: 25 | spawn test_contains(i) 26 | for i in { 1 .. N_INSERT }: 27 | spawn test_insert(i) 28 | for i in { 1 .. N_REMOVE }: 29 | spawn test_remove(i) 30 | -------------------------------------------------------------------------------- /code/setobj_linkedlist.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | from alloc import malloc, free 3 | 4 | def _node(v, n) returns node: # allocate and initialize a new list node 5 | node = malloc({ .lock: Lock(), .value: v, .next: n }) 6 | 7 | def _find(lst, v) returns pair: 8 | var before = lst 9 | acquire(?before->lock) 10 | var after = before->next 11 | acquire(?after->lock) 12 | while after->value < (0, v): 13 | release(?before->lock) 14 | before = after 15 | after = before->next 16 | acquire(?after->lock) 17 | pair = (before, after) 18 | 19 | def SetObject() returns object: 20 | object = _node((-1, None), _node((1, None), None)) 21 | 22 | def insert(lst, v): 23 | let before, after = _find(lst, v): 24 | if after->value != (0, v): 25 | before->next = _node((0, v), after) 26 | release(?after->lock) 27 | release(?before->lock) 28 | 29 | def remove(lst, v): 30 | let before, after = _find(lst, v): 31 | if after->value == (0, v): 32 | before->next = after->next 33 | free(after) 34 | else: 35 | release(?after->lock) 36 | release(?before->lock) 37 | 38 | def contains(lst, v) returns present: 39 | let before, after = _find(lst, v): 40 | present = after->value == (0, v) 41 | release(?after->lock) 42 | release(?before->lock) 43 | -------------------------------------------------------------------------------- /code/setobj_test1.hny: -------------------------------------------------------------------------------- 1 | from setobj import * 2 | 3 | myset = SetObject() 4 | 5 | def thread1(): 6 | insert(myset, 1) 7 | let x = contains(myset, 1): 8 | assert x 9 | 10 | def thread2(v): 11 | insert(myset, v) 12 | remove(myset, v) 13 | 14 | spawn thread1() 15 | spawn thread2(0) 16 | spawn thread2(2) 17 | -------------------------------------------------------------------------------- /code/spinlock.hny: -------------------------------------------------------------------------------- 1 | const N = 5 2 | 3 | in_cs = 0 4 | invariant in_cs in { 0, 1 } 5 | 6 | shared = False 7 | private = [ True, ] * N 8 | invariant [x for x in [shared,] + private where not x] == [False,] 9 | 10 | def swap(s, p): 11 | atomically !p, !s = !s, !p 12 | 13 | def thread(self): 14 | while choose({ False, True }): 15 | # Enter critical section 16 | while private[self]: 17 | swap(?shared, ?private[self]) 18 | 19 | atomically in_cs += 1 20 | assert not private[self] 21 | atomically in_cs -= 1 22 | 23 | # Leave critical section 24 | swap(?shared, ?private[self]) 25 | 26 | for i in {0..N-1}: 27 | spawn thread(i) 28 | -------------------------------------------------------------------------------- /code/stack.hny: -------------------------------------------------------------------------------- 1 | def Stack() returns stack: 2 | stack = [] 3 | 4 | def push(st, v): 5 | (!st)[len(!st)] = v 6 | 7 | def pop(st) returns next: 8 | let n = len(!st) - 1: 9 | next = (!st)[n] 10 | del (!st)[n] 11 | -------------------------------------------------------------------------------- /code/stack1.hny: -------------------------------------------------------------------------------- 1 | def Stack() returns stack: 2 | stack = [] 3 | 4 | def push(st, v): 5 | (!st)[len(!st)] = v 6 | 7 | def pop(st) returns next: 8 | let n = len(!st) - 1: 9 | next = (!st)[n] 10 | del (!st)[n] 11 | -------------------------------------------------------------------------------- /code/stack2.hny: -------------------------------------------------------------------------------- 1 | import lists 2 | 3 | def Stack() returns stack: 4 | stack = [] 5 | 6 | def push(st, v): 7 | !st += [v,] 8 | 9 | def pop(st) returns next: 10 | let n = len(!st) - 1: 11 | next = (!st)[n] 12 | !st = lists.subseq(!st, 0, n) 13 | -------------------------------------------------------------------------------- /code/stack3.hny: -------------------------------------------------------------------------------- 1 | def Stack() returns stack: 2 | stack = () 3 | 4 | def push(st, v): 5 | (!st) = (v, !st) 6 | 7 | def pop(st) returns next: 8 | let (top, rest) = !st: 9 | next = top 10 | !st = rest 11 | -------------------------------------------------------------------------------- /code/stack4.hny: -------------------------------------------------------------------------------- 1 | from alloc import malloc, free 2 | 3 | def Stack() returns stack: 4 | stack = None 5 | 6 | def push(st, v): 7 | !st = malloc({ .value: v, .rest: !st }) 8 | 9 | def pop(st) returns next: 10 | let node = !st: 11 | next = node->value 12 | !st = node->rest 13 | free(node) 14 | -------------------------------------------------------------------------------- /code/stacktest.hny: -------------------------------------------------------------------------------- 1 | from stack import Stack, push, pop 2 | 3 | teststack = Stack() 4 | push(?teststack, 1) 5 | push(?teststack, 2) 6 | v = pop(?teststack) 7 | assert v == 2 8 | push(?teststack, 3) 9 | v = pop(?teststack) 10 | assert v == 3 11 | v = pop(?teststack) 12 | assert v == 1 13 | -------------------------------------------------------------------------------- /code/trap.hny: -------------------------------------------------------------------------------- 1 | count = 0 2 | done = False 3 | 4 | finally count == 1 5 | 6 | def handler(): 7 | count += 1 8 | done = True 9 | 10 | def main(): 11 | trap handler() 12 | await done 13 | 14 | spawn main() 15 | -------------------------------------------------------------------------------- /code/trap2.hny: -------------------------------------------------------------------------------- 1 | count = 0 2 | done = False 3 | 4 | finally count == 2 5 | 6 | def handler(): 7 | count += 1 8 | done = True 9 | 10 | def main(): 11 | trap handler() 12 | count += 1 13 | await done 14 | 15 | spawn main() 16 | -------------------------------------------------------------------------------- /code/trap3.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | 3 | countlock = Lock() 4 | count = 0 5 | done = False 6 | 7 | finally count == 2 8 | 9 | def handler(): 10 | acquire(?countlock) 11 | count += 1 12 | release(?countlock) 13 | done = True 14 | 15 | def main(): 16 | trap handler() 17 | acquire(?countlock) 18 | count += 1 19 | release(?countlock) 20 | await done 21 | 22 | spawn main() 23 | -------------------------------------------------------------------------------- /code/trap4.hny: -------------------------------------------------------------------------------- 1 | count = 0 2 | done = False 3 | 4 | finally count == 2 5 | 6 | def handler(): 7 | count += 1 8 | done = True 9 | 10 | def main(): 11 | trap handler() 12 | setintlevel(True) 13 | count += 1 14 | setintlevel(False) 15 | await done 16 | 17 | spawn main() 18 | -------------------------------------------------------------------------------- /code/trap5.hny: -------------------------------------------------------------------------------- 1 | count = 0 2 | done = False 3 | 4 | finally count == 2 5 | 6 | def increment(): 7 | let prior = setintlevel(True): 8 | count += 1 9 | setintlevel(prior) 10 | 11 | def handler(): 12 | increment() 13 | done = True 14 | 15 | def main(): 16 | trap handler() 17 | increment() 18 | await done 19 | 20 | spawn main() 21 | -------------------------------------------------------------------------------- /code/trap6.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | 3 | count = 0 4 | countlock = Lock() 5 | done = [ False, False ] 6 | 7 | finally count == 4 8 | 9 | def increment(): 10 | let prior = setintlevel(True): 11 | acquire(?countlock) 12 | count += 1 13 | release(?countlock) 14 | setintlevel(prior) 15 | 16 | def handler(self): 17 | increment() 18 | done[self] = True 19 | 20 | def thread(self): 21 | trap handler(self) 22 | increment() 23 | await done[self] 24 | 25 | spawn thread(0) 26 | spawn thread(1) 27 | -------------------------------------------------------------------------------- /code/triangle.hny: -------------------------------------------------------------------------------- 1 | const N = 10 2 | 3 | def triangle(n) returns result: # computes the n'th triangle number 4 | result = 0 5 | for i in {1..n}: # for each integer from 1 to n inclusive 6 | result += i # add i to result 7 | 8 | x = choose {0..N} # select an x between 0 and N inclusive 9 | assert triangle(x) == x * (x + 1) / 2 10 | -------------------------------------------------------------------------------- /code/wal.hny: -------------------------------------------------------------------------------- 1 | from alloc import malloc 2 | 3 | const BITS_PER_BLOCK = 3 4 | 5 | def new(n_blocks) returns wal: 6 | wal = malloc([ None, ] * n_blocks) 7 | 8 | def getsize(wal) returns size: 9 | size = len !wal 10 | 11 | def read(wal, bno) returns block: 12 | block = (!wal)[bno] 13 | 14 | def write(wal, bno, block): 15 | (!wal)[bno] = block 16 | 17 | def txbegin(wal, id): 18 | pass 19 | 20 | def txend(wal, id): 21 | pass 22 | -------------------------------------------------------------------------------- /code/xy.hny: -------------------------------------------------------------------------------- 1 | x, y = 0, 100 2 | 3 | def setX(a): 4 | x = a 5 | y = 100 - a 6 | 7 | def getXY() returns xy: 8 | xy = [x, y] 9 | 10 | def checker(): 11 | let xy = getXY(): 12 | assert (xy[0] + xy[1]) == 100, xy 13 | 14 | spawn checker() 15 | spawn setX(50) 16 | -------------------------------------------------------------------------------- /compose.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harmonylang/harmony/d06ac438fe7bd79539915cb67819728be5b7d803/compose.pdf -------------------------------------------------------------------------------- /distributions/harmony-0.9.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harmonylang/harmony/d06ac438fe7bd79539915cb67819728be5b7d803/distributions/harmony-0.9.zip -------------------------------------------------------------------------------- /distributions/harmony-1.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harmonylang/harmony/d06ac438fe7bd79539915cb67819728be5b7d803/distributions/harmony-1.0.zip -------------------------------------------------------------------------------- /distributions/harmony-1.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harmonylang/harmony/d06ac438fe7bd79539915cb67819728be5b7d803/distributions/harmony-1.1.zip -------------------------------------------------------------------------------- /distributions/makedistr: -------------------------------------------------------------------------------- 1 | dir=harmony-1.2 2 | rm -rf $dir 3 | mkdir $dir 4 | (cd ..; python3 src/archive/implode.py manifest) > $dir/archive.xml 5 | cp ../install.py $dir 6 | cp ../README.txt $dir 7 | rm -f $dir.zip 8 | cd $dir 9 | zip -r ../$dir.zip * 10 | -------------------------------------------------------------------------------- /doc-images/adding-new-path.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harmonylang/harmony/d06ac438fe7bd79539915cb67819728be5b7d803/doc-images/adding-new-path.png -------------------------------------------------------------------------------- /doc-images/find-c++-build-tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harmonylang/harmony/d06ac438fe7bd79539915cb67819728be5b7d803/doc-images/find-c++-build-tools.png -------------------------------------------------------------------------------- /doc-images/first-pane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harmonylang/harmony/d06ac438fe7bd79539915cb67819728be5b7d803/doc-images/first-pane.png -------------------------------------------------------------------------------- /doc-images/hover-new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harmonylang/harmony/d06ac438fe7bd79539915cb67819728be5b7d803/doc-images/hover-new.png -------------------------------------------------------------------------------- /doc-images/press-install-c++-build-tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harmonylang/harmony/d06ac438fe7bd79539915cb67819728be5b7d803/doc-images/press-install-c++-build-tools.png -------------------------------------------------------------------------------- /doc-images/simple-graph-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harmonylang/harmony/d06ac438fe7bd79539915cb67819728be5b7d803/doc-images/simple-graph-example.png -------------------------------------------------------------------------------- /h2py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from harmony_model_checker.harmony.DumpASTVisitor import DumpASTVisitor 4 | from harmony_model_checker.h2py.h2py import h2py 5 | from harmony_model_checker.compile import parse 6 | 7 | import ast as past 8 | 9 | import argparse 10 | 11 | 12 | parser = argparse.ArgumentParser(description='Harmony to Python') 13 | parser.add_argument('filename') 14 | parser.add_argument('--verbose', action='store_true') 15 | 16 | 17 | if __name__ == '__main__': 18 | args = parser.parse_args() 19 | 20 | harmony_ast = parse(args.filename) 21 | if args.verbose: 22 | print('Dumped Harmony AST:') 23 | dump = DumpASTVisitor(indent_unit=2) 24 | print(dump(harmony_ast)) 25 | print() 26 | 27 | python_ast = h2py(harmony_ast) 28 | if args.verbose: 29 | print('Dumped Python AST:') 30 | print(past.dump(python_ast, indent=2)) 31 | print() 32 | 33 | print(past.unparse(python_ast)) 34 | -------------------------------------------------------------------------------- /harmony: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | from harmony_model_checker.main import main 5 | 6 | if __name__ == '__main__': 7 | sys.exit(main()) 8 | -------------------------------------------------------------------------------- /harmony.bat: -------------------------------------------------------------------------------- 1 | 0<0# : ^ 2 | ''' 3 | @echo off 4 | python "%~f0" %* 5 | exit /b 0 6 | ''' 7 | import sys 8 | from harmony_model_checker.main import main 9 | 10 | if __name__ == "__main__": 11 | sys.exit(main()) 12 | -------------------------------------------------------------------------------- /harmony_model_checker/charm/dot.h: -------------------------------------------------------------------------------- 1 | #ifndef SRC_DOT_H 2 | #define SRC_DOT_H 3 | 4 | #include 5 | #include 6 | 7 | struct dot_node_t { 8 | const char *name; // null-terminated string 9 | bool terminating; 10 | bool initial; 11 | bool choosing; 12 | int choosing_atomic_level; 13 | int *fwd; // forward edges 14 | int fwd_len; // number forward edges 15 | }; 16 | 17 | typedef struct dot_graph_t { 18 | struct dot_node_t **nodes; 19 | int len; 20 | int _alloc_len; 21 | } dot_graph_t; 22 | 23 | struct dot_graph_t *dot_graph_init(int alloc_len); 24 | void dot_graph_deinit(dot_graph_t *graph); 25 | struct dot_node_t *dot_graph_new_node(dot_graph_t *graph); 26 | void dot_graph_add_edge(dot_graph_t *graph, int from_idx, int to_idx); 27 | void dot_graph_fprint(dot_graph_t *graph, FILE *f); 28 | 29 | #endif //SRC_DOT_H 30 | -------------------------------------------------------------------------------- /harmony_model_checker/charm/global.c: -------------------------------------------------------------------------------- 1 | #include "head.h" 2 | 3 | #ifdef _WIN32 4 | #include 5 | #endif 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #ifndef HARMONY_COMBINE 12 | #include "global.h" 13 | #endif 14 | 15 | // Convert a string representation of an integer to an unsigned long value. 16 | unsigned long to_ulong(const char *p, int len){ 17 | unsigned long r = 0; 18 | 19 | while (len > 0) { 20 | assert(isdigit(*p)); 21 | r *= 10; 22 | r += *p - '0'; 23 | len--; 24 | p++; 25 | } 26 | return r; 27 | } 28 | 29 | // Something went terribly wrong. Print a message and exit. 30 | void panic(char *s){ 31 | fprintf(stderr, "Panic: %s\n", s); 32 | exit(1); 33 | } 34 | 35 | 36 | #ifdef __APPLE__ 37 | #ifdef __clang__ 38 | void *my_aligned_alloc(size_t alignment, size_t size){ 39 | if (__builtin_available(macOS 10.15, *)) { 40 | return aligned_alloc(alignment, size); 41 | } 42 | 43 | static bool warned; 44 | if (!warned) { 45 | fprintf(stderr, "aligned_alloc not available in current version of MacOSX\n"); 46 | warned = true; 47 | } 48 | return malloc(size); 49 | } 50 | #endif 51 | #endif 52 | -------------------------------------------------------------------------------- /harmony_model_checker/charm/gnfa.h: -------------------------------------------------------------------------------- 1 | #ifndef SRC_GNFA_H 2 | #define SRC_GNFA_H 3 | 4 | #include "global.h" 5 | 6 | struct regexp { 7 | enum { RE_EPSILON, RE_SYMBOL, RE_DISJUNCTION, RE_SEQUENCE, RE_KLEENE } type; 8 | union { 9 | hvalue_t symbol; 10 | struct { 11 | unsigned int n; 12 | struct regexp **entries; 13 | } list; // disjunction or sequence 14 | struct regexp *kleene; 15 | } u; 16 | }; 17 | 18 | struct gnfa { 19 | unsigned int nstates; // number of states 20 | unsigned int size; // original size of matrix 21 | struct regexp **transitions; 22 | }; 23 | 24 | struct gnfa *gnfa_from_dfa(struct dfa *dfa); 25 | void gnfa_rip(struct gnfa *gnfa); 26 | 27 | #endif // SRC_GNFA_H 28 | -------------------------------------------------------------------------------- /harmony_model_checker/charm/head.h: -------------------------------------------------------------------------------- 1 | // #define DEBUGGING 2 | 3 | // #define SHORT_PTR 4 | 5 | #ifdef DEBUGGING 6 | # undef NDEBUG 7 | #else 8 | # ifndef NDEBUG 9 | # define NDEBUG 10 | # endif 11 | #endif 12 | 13 | // This file is included at the start of every C source. It mostly deals with 14 | // architecture dependent stuff 15 | 16 | #ifdef _WIN32 17 | #define HEAP_ALLOC 18 | #else // _WIN32 19 | #define ALIGNED_ALLOC 20 | #include 21 | #if defined(__APPLE__) && defined(__clang__) 22 | void *my_aligned_alloc(size_t alignment, size_t size); 23 | #else 24 | #define my_aligned_alloc(a, s) aligned_alloc(a, s) 25 | #endif // __APPLE__ 26 | #endif // _WIN32 27 | 28 | #ifdef __linux__ 29 | #ifdef NUMA 30 | #include 31 | #include 32 | #include 33 | #endif 34 | #endif 35 | -------------------------------------------------------------------------------- /harmony_model_checker/charm/iface.obs/hashset.c: -------------------------------------------------------------------------------- 1 | #include "head.h" 2 | 3 | #include "global.h" 4 | #include "hashset.h" 5 | 6 | struct hashset_t hashset_new(int initial_size) { 7 | struct hashset_t set; 8 | set.dict = dict_new("hashset", 0, initial_size, 0, false); 9 | return set; 10 | } 11 | 12 | // returns true iff key was in the set before 13 | bool hashset_insert(struct hashset_t set, const void *key, unsigned int keylen) { 14 | bool new; 15 | dict_insert(set.dict, NULL, key, keylen, &new); 16 | return !new; 17 | } 18 | 19 | // returns true iff key was in the set before 20 | bool hashset_remove(struct hashset_t set, const void *key, unsigned int keylen) { 21 | return dict_remove(set.dict, key, keylen); 22 | } 23 | 24 | // TODO. Need better implementation 25 | bool hashset_contains(struct hashset_t set, const void *key, unsigned int keylen) { 26 | bool new; 27 | dict_insert(set.dict, NULL, key, keylen, &new); 28 | if (new) { 29 | dict_remove(set.dict, key, keylen); 30 | } 31 | return !new; 32 | } 33 | 34 | void hashset_delete(struct hashset_t set) { 35 | dict_delete(set.dict); 36 | } 37 | -------------------------------------------------------------------------------- /harmony_model_checker/charm/iface.obs/hashset.h: -------------------------------------------------------------------------------- 1 | // TODO. May be obsolete 2 | 3 | #ifndef SRC_HASHSET_H 4 | #define SRC_HASHSET_H 5 | 6 | #include 7 | #include 8 | #include "hashdict.h" 9 | 10 | struct hashset_t { 11 | struct dict *dict; // a dict from values to DUMMY 12 | }; 13 | 14 | struct hashset_t hashset_new(int initial_size); 15 | 16 | // returns true iff key was in the set before 17 | bool hashset_insert(struct hashset_t set, const void *key, unsigned int keylen); 18 | 19 | // returns true iff key was in the set before 20 | bool hashset_remove(struct hashset_t set, const void *key, unsigned int keylen); 21 | 22 | bool hashset_contains(struct hashset_t set, const void *key, unsigned int keylen); 23 | 24 | void hashset_delete(struct hashset_t set); 25 | 26 | #endif //SRC_HASHSET_H 27 | -------------------------------------------------------------------------------- /harmony_model_checker/charm/iface.obs/iface.h: -------------------------------------------------------------------------------- 1 | #ifndef SRC_IFACE_H 2 | #define SRC_IFACE_H 3 | 4 | #ifndef HARMONY_COMBINE 5 | #include "value.h" 6 | #include "strbuf.h" 7 | #include "ops.h" 8 | #include "charm.h" 9 | #include "graph.h" 10 | #include "dot.h" 11 | #endif 12 | 13 | void iface_write_spec_graph_to_file(struct global *global, const char* filename); 14 | void iface_write_spec_graph_to_json_file(struct global *global, const char* filename); 15 | 16 | #endif //SRC_IFACE_H 17 | -------------------------------------------------------------------------------- /harmony_model_checker/charm/iface.obs/iface_graph.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by William Ma on 10/12/21. 3 | // 4 | 5 | #ifndef SRC_IFACE_GRAPH_H 6 | #define SRC_IFACE_GRAPH_H 7 | 8 | #include 9 | #include 10 | 11 | #ifndef HARMONY_COMBINE 12 | #include "value.h" 13 | #endif 14 | 15 | struct iface_node_t { 16 | int idx; 17 | struct node *node; 18 | 19 | uint64_t value; 20 | bool initial; 21 | bool terminated; 22 | bool choosing; 23 | 24 | struct state *state; 25 | 26 | struct iface_edge_t *fwd; 27 | struct iface_edge_t *bwd; 28 | 29 | int _tag; 30 | }; 31 | 32 | struct iface_edge_t { 33 | struct iface_edge_t *next; 34 | 35 | /** 36 | * is_fwd iff this edge \in src.fwd 37 | * !is_fwd iff this edge \in dst.bwd 38 | */ 39 | bool is_fwd; 40 | struct iface_node_t *src; 41 | struct iface_node_t *dst; 42 | }; 43 | 44 | struct iface_graph_t { 45 | struct iface_node_t **nodes; 46 | int nodes_len; 47 | int _nodes_alloc_len; 48 | 49 | struct iface_edge_t **edges; // all edges, including fwd and bwd 50 | int edges_len; 51 | int _edges_alloc_len; 52 | }; 53 | 54 | void iface_graph_print(struct iface_graph_t *graph); 55 | struct iface_graph_t *iface_graph_init(int initial_size); 56 | void iface_graph_deinit(struct iface_graph_t *graph); 57 | struct iface_node_t *iface_graph_add_node(struct iface_graph_t *graph); 58 | void iface_graph_add_edge(struct iface_graph_t *graph, int src_idx, int dst_idx); 59 | struct iface_graph_t *iface_graph_destutter(struct iface_graph_t *graph); 60 | 61 | #endif //SRC_IFACE_GRAPH_H 62 | -------------------------------------------------------------------------------- /harmony_model_checker/charm/iface.obs/minheap.h: -------------------------------------------------------------------------------- 1 | #ifndef _MINHEAP_H 2 | #define _MINHEAP_H 3 | 4 | #include 5 | 6 | struct minheap *minheap_create(int (*cmp)(void *, void *)); 7 | void *minheap_getmin(struct minheap *); 8 | void minheap_insert(struct minheap *, void *); 9 | void minheap_decrease(struct minheap *, void *); 10 | int minheap_size(struct minheap *); 11 | bool minheap_empty(struct minheap *mh); 12 | void minheap_move(struct minheap *mh1, struct minheap *mh2); 13 | void minheap_destroy(struct minheap *); 14 | bool minheap_check(struct minheap *hm, void *key); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /harmony_model_checker/charm/iface.obs/queue.h: -------------------------------------------------------------------------------- 1 | // TODO. Possibly obsolete 2 | 3 | #ifndef SRC_QUEUE_H 4 | #define SRC_QUEUE_H 5 | 6 | #include "stdint.h" 7 | 8 | struct queue { 9 | struct element *first, **last; 10 | int nelts; 11 | }; 12 | 13 | void queue_init(struct queue *q); 14 | void queue_insert(struct queue *q, void *item); 15 | void queue_append(struct queue *q, void *, char *file, int line); 16 | unsigned int queue_size(struct queue *q); 17 | void queue_add(struct queue *q, void *); 18 | void queue_add_uint(struct queue *q, uint64_t); 19 | void *queue_get(struct queue *q); 20 | bool queue_tget(struct queue *q, void **item); 21 | bool queue_get_uint(struct queue *q, uint64_t *); 22 | bool queue_empty(struct queue *q); 23 | void queue_release(struct queue *q); 24 | 25 | #endif // SRC_QUEUE_H 26 | -------------------------------------------------------------------------------- /harmony_model_checker/charm/iface.obs/stack.c: -------------------------------------------------------------------------------- 1 | #include "head.h" 2 | 3 | // 4 | // Created by William Ma on 10/12/21. 5 | // 6 | #include 7 | #include 8 | 9 | #include "stack.h" 10 | 11 | struct stack_t *stack_init(int alloc_len) { 12 | assert(alloc_len > 0); 13 | 14 | struct stack_t *stack = malloc(sizeof(struct stack_t)); 15 | stack->len = 0; 16 | stack->alloc_len = alloc_len; 17 | stack->arr = malloc(stack->alloc_len * sizeof(void *)); 18 | return stack; 19 | } 20 | 21 | void stack_deinit(struct stack_t *stack) { 22 | free(stack->arr); 23 | free(stack); 24 | } 25 | 26 | void stack_push(struct stack_t *stack, void *elem) { 27 | stack->len++; 28 | if (stack->len > stack->alloc_len) { 29 | stack->alloc_len = 2 * stack->len; 30 | stack->arr = realloc(stack->arr, stack->alloc_len * sizeof(void *)); 31 | } 32 | 33 | stack->arr[stack->len - 1] = elem; 34 | } 35 | 36 | void *stack_pop(struct stack_t *stack) { 37 | assert(stack->len > 0); 38 | stack->len--; 39 | return stack->arr[stack->len]; 40 | } 41 | 42 | int stack_len(struct stack_t *stack) { 43 | return stack->len; 44 | } 45 | -------------------------------------------------------------------------------- /harmony_model_checker/charm/iface.obs/stack.h: -------------------------------------------------------------------------------- 1 | // TODO. Possibly obsolete 2 | 3 | // 4 | // Created by William Ma on 10/12/21. 5 | // 6 | 7 | #ifndef SRC_STACK_H 8 | #define SRC_STACK_H 9 | 10 | #include 11 | #include 12 | 13 | struct stack_t { 14 | void **arr; 15 | int len; 16 | int alloc_len; 17 | }; 18 | 19 | struct stack_t *stack_init(int alloc_len); 20 | 21 | void stack_deinit(struct stack_t *stack); 22 | 23 | void stack_push(struct stack_t *stack, void *elem); 24 | 25 | void *stack_pop(struct stack_t *stack); 26 | 27 | int stack_len(struct stack_t *stack); 28 | 29 | #endif //SRC_STACK_H 30 | -------------------------------------------------------------------------------- /harmony_model_checker/charm/json.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_H 2 | #define JSON_H 3 | 4 | // A JSON "atom" is a list of characters which may or may not be quoted. 5 | typedef struct json_buf { 6 | char *base; 7 | unsigned int len; 8 | bool quoted; 9 | } json_buf_t; 10 | 11 | // A JSON "value" is either an atom, a map, or a list. 12 | struct json_value { 13 | enum { JV_ATOM, JV_MAP, JV_LIST } type; 14 | union { 15 | json_buf_t atom; 16 | struct dict *map; // maps atoms to json_values 17 | struct { 18 | struct json_value **vals; 19 | unsigned int nvals; 20 | } list; 21 | } u; 22 | }; 23 | 24 | struct json_value *json_parse_value(json_buf_t *buf); 25 | struct json_value *json_string(char *s, unsigned int len); 26 | void json_value_free(struct json_value *jv); 27 | void json_dump(struct json_value *jv, FILE *fp, unsigned int indent); 28 | void json_list_append(struct json_value *list, struct json_value *jv); 29 | void json_map_append(struct json_value *map, json_buf_t key, struct json_value *jv); 30 | char *json_lookup_string(struct dict *map, char *key); 31 | struct json_value *json_lookup_map(struct dict *map, char *key); 32 | struct json_value *json_lookup_value(struct dict *map, char *key); 33 | char *json_escape(const char *s, unsigned int len); 34 | 35 | #endif /* JSON_H */ 36 | -------------------------------------------------------------------------------- /harmony_model_checker/charm/prefetcher.h: -------------------------------------------------------------------------------- 1 | #ifndef PREFETCHER_H 2 | #define PREFETCHER_H 3 | 4 | #include 5 | 6 | #if defined(__GNUC__) || defined(__clang__) 7 | #define PREFETCH(addr, rw, locality) __builtin_prefetch((addr), (rw), (locality)) 8 | #elif defined(_WIN32) 9 | #include 10 | #define PREFETCH(addr, rw, locality) _mm_prefetch((const char*)(addr), _MM_HINT_T0) 11 | #else 12 | #define PREFETCH(addr, rw, locality) // No prefetch available 13 | #endif 14 | 15 | #endif // PREFETCHER_H -------------------------------------------------------------------------------- /harmony_model_checker/charm/python_ext/ext.c: -------------------------------------------------------------------------------- 1 | 2 | #include "Python.h" 3 | 4 | int exec_model_checker(int argc, char** argv); 5 | 6 | static PyObject* run_model_checker(PyObject *self, PyObject *args) { 7 | Py_ssize_t tupleSize = PyTuple_Size(args); 8 | Py_ssize_t argc = tupleSize + 1; 9 | char **argv = malloc(argc * sizeof(char *)); 10 | argv[0] = "charm"; 11 | for (Py_ssize_t i = 0; i < tupleSize; ++i) { 12 | PyObject *a = PyTuple_GetItem(args, i); 13 | char *s; 14 | if (!PyArg_Parse(a, "s", &s)) { 15 | return NULL; 16 | } 17 | argv[i + 1] = s; 18 | } 19 | PyObject *r = PyLong_FromLong(exec_model_checker(argc, argv)); 20 | free(argv); 21 | return r; 22 | } 23 | 24 | static char module_docstring[] = 25 | "This module provides an interface for running the Harmony model checker."; 26 | static char run_model_checker_sub_docstring[] = 27 | "Perform model check."; 28 | 29 | static PyMethodDef module_methods[] = { 30 | {"run_model_checker", run_model_checker, METH_VARARGS, run_model_checker_sub_docstring}, 31 | {NULL, NULL, 0, NULL} 32 | }; 33 | 34 | static PyModuleDef mod_def = { 35 | PyModuleDef_HEAD_INIT, 36 | "charm", 37 | module_docstring, 38 | -1, 39 | module_methods, 40 | }; 41 | 42 | PyObject* PyInit_charm(void) 43 | { 44 | return PyModule_Create(&mod_def); 45 | }; 46 | // Redefined in the rest of charm.c 47 | #undef _GNU_SOURCE 48 | -------------------------------------------------------------------------------- /harmony_model_checker/charm/spawn.h: -------------------------------------------------------------------------------- 1 | // Supports experimental feature to execute Harmony code rather than model checking it. 2 | 3 | struct spawn_info { 4 | struct state *state; 5 | struct context *ctx; 6 | }; 7 | 8 | void spawn_thread(struct state *state, struct context *ctx); 9 | -------------------------------------------------------------------------------- /harmony_model_checker/charm/strbuf.h: -------------------------------------------------------------------------------- 1 | #ifndef SRC_STRBUF_H 2 | #define SRC_STRBUF_H 3 | 4 | #include 5 | 6 | // A "string buffer" is simply a sequence of UTF-8 (or ASCII) characters. 7 | // 8 | typedef struct strbuf { 9 | char *buf; // points to the characters 10 | unsigned int len; // actual #characters 11 | unsigned int allocated; // current size of the buffer 12 | } strbuf; 13 | 14 | void strbuf_init(strbuf *sb); 15 | void strbuf_append(strbuf *sb, const char *str, unsigned int len); 16 | void strbuf_vprintf(strbuf *sb, const char *fmt, va_list args); 17 | void strbuf_printf(strbuf *sb, const char *fmt, ...); 18 | char *strbuf_getstr(strbuf *sb); 19 | unsigned int strbuf_getlen(strbuf *sb); 20 | void strbuf_deinit(strbuf *sb); 21 | char *strbuf_convert(strbuf *sb); 22 | 23 | #endif // SRC_STRBUF_H 24 | -------------------------------------------------------------------------------- /harmony_model_checker/exception.py: -------------------------------------------------------------------------------- 1 | from typing import Any, List, NamedTuple 2 | 3 | class ErrorToken(NamedTuple): 4 | line: int 5 | message: str 6 | column: int 7 | lexeme: str 8 | filename: str 9 | is_eof_error: bool 10 | 11 | class HarmonyCompilerErrorCollection(Exception): 12 | def __init__(self, errors: List[ErrorToken]) -> None: 13 | super().__init__() 14 | self.errors = errors 15 | 16 | class HarmonyCompilerError(Exception): 17 | """ 18 | Error encountered during the compilation of a Harmony program. 19 | """ 20 | 21 | def __init__(self, message: str, filename: str = None, line: int = None, 22 | column: int = None, lexeme: Any = None, is_eof_error=False): 23 | super().__init__() 24 | self.message = message 25 | self.token = ErrorToken( 26 | message=message, 27 | filename=filename or "", 28 | line=line or 0, 29 | column=column or 0, 30 | lexeme=str(lexeme), 31 | is_eof_error=is_eof_error 32 | ) 33 | -------------------------------------------------------------------------------- /harmony_model_checker/h2py/H2PyEnv.py: -------------------------------------------------------------------------------- 1 | class H2PyEnv: 2 | 3 | def __init__(self): 4 | self._parent = None 5 | 6 | def rep(self, **kwargs): 7 | child = H2PyEnv() 8 | child._parent = self 9 | for k, v in kwargs.items(): 10 | setattr(child, k, v) 11 | return child 12 | 13 | def get(self, name): 14 | env = self 15 | while env is not None: 16 | v = getattr(env, name, None) 17 | if v is not None: 18 | return v 19 | env = env._parent 20 | return None 21 | -------------------------------------------------------------------------------- /harmony_model_checker/h2py/h2py.py: -------------------------------------------------------------------------------- 1 | from harmony_model_checker.h2py.H2PyStmtVisitor import H2PyStmtVisitor 2 | import harmony_model_checker.harmony.ast as hast 3 | 4 | import ast as past 5 | 6 | 7 | def h2py(hast: hast.AST) -> past.AST: 8 | stmt_visitor = H2PyStmtVisitor() 9 | return past.Module( 10 | body=[ 11 | past.ImportFrom( 12 | module='h2py_runtime', 13 | names=[past.alias(name='*')], 14 | level=0 15 | ) 16 | ] + stmt_visitor(hast), 17 | type_ignores=[] 18 | ) 19 | -------------------------------------------------------------------------------- /harmony_model_checker/h2py/util.py: -------------------------------------------------------------------------------- 1 | import harmony_model_checker.h2py.h2py_runtime as h2py_runtime 2 | 3 | # Symbolic constants for indexing into a token. 4 | T_TOKEN = 0 5 | T_FILE = 1 6 | T_LINENO = 2 7 | T_COLNO = 3 8 | 9 | 10 | def escape_name(name: str) -> str: 11 | while name in dir(h2py_runtime): 12 | name = f'_{name}' 13 | return name 14 | -------------------------------------------------------------------------------- /harmony_model_checker/harmony/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harmonylang/harmony/d06ac438fe7bd79539915cb67819728be5b7d803/harmony_model_checker/harmony/__init__.py -------------------------------------------------------------------------------- /harmony_model_checker/harmony/bag_util.py: -------------------------------------------------------------------------------- 1 | def bag_add(bag, item): 2 | cnt = bag.get(item) 3 | if cnt is None: 4 | bag[item] = 1 5 | else: 6 | bag[item] = cnt + 1 7 | 8 | def bag_remove(bag, item): 9 | cnt = bag[item] 10 | assert cnt > 0 11 | if cnt == 1: 12 | del bag[item] 13 | else: 14 | bag[item] = cnt - 1 -------------------------------------------------------------------------------- /harmony_model_checker/harmony/charm.css: -------------------------------------------------------------------------------- 1 | #table-wrapper { 2 | position:relative; 3 | } 4 | #table-scroll { 5 | height:200px; 6 | overflow:auto; 7 | } 8 | #table-wrapper table { 9 | width:100%; 10 | } 11 | #table-wrapper table * { 12 | color:black; 13 | } 14 | #table-wrapper table thead th .text { 15 | position:absolute; 16 | top:-20px; 17 | z-index:2; 18 | height:20px; 19 | width:35%; 20 | border:1px solid red; 21 | } 22 | .table-transparent { 23 | border-collapse: collapse; 24 | border-style: hidden; 25 | border: none !important; 26 | } 27 | .table-transparent td { 28 | border-collapse: collapse; 29 | border-style: hidden; 30 | border: none !important; 31 | } 32 | table { 33 | border-collapse: collapse; 34 | border-style: hidden; 35 | } 36 | table td, table th { 37 | border: 1px solid black; 38 | } 39 | -------------------------------------------------------------------------------- /harmony_model_checker/modules/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harmonylang/harmony/d06ac438fe7bd79539915cb67819728be5b7d803/harmony_model_checker/modules/__init__.py -------------------------------------------------------------------------------- /harmony_model_checker/modules/action.hny: -------------------------------------------------------------------------------- 1 | def _union(s) returns result: 2 | result = {} 3 | for opt in s: 4 | result |= opt() 5 | 6 | def explore(s): 7 | var going = True 8 | while going: 9 | let options = _union(s): 10 | if options == {}: 11 | going = False 12 | else: 13 | let closure = choose(options): 14 | atomically !closure 15 | -------------------------------------------------------------------------------- /harmony_model_checker/modules/alloc.hny: -------------------------------------------------------------------------------- 1 | pool = {:} 2 | next = 0 3 | 4 | # builtin malloc "alloc$malloc" 5 | # TODO. builtin malloc temporarily disabled 6 | def malloc(v) returns copy: 7 | atomically: 8 | pool[next] = v 9 | copy = ?pool[next] 10 | next += 1 11 | 12 | # Commented out code tests for bad frees, but can lead to data races 13 | def free(r): 14 | atomically: 15 | # let poolcopy = pool: 16 | del !r 17 | # assert poolcopy != pool, .bad_free 18 | 19 | def leak_check(): 20 | assert pool == {:}, .alloc_leak 21 | -------------------------------------------------------------------------------- /harmony_model_checker/modules/hoare.hny: -------------------------------------------------------------------------------- 1 | import synch 2 | 3 | def Monitor() returns mon: 4 | mon = synch.Lock() 5 | 6 | def enter(mon): 7 | synch.acquire(mon) 8 | 9 | def exit(mon): 10 | synch.release(mon) 11 | 12 | def Condition() returns cond: 13 | cond = { .sema: synch.BinSema(True), .count: 0 } 14 | 15 | def wait(cond, mon): 16 | cond->count += 1 17 | exit(mon) 18 | synch.acquire(?cond->sema) 19 | cond->count -= 1 20 | 21 | def signal(cond, mon): 22 | if cond->count > 0: 23 | synch.release(?cond->sema) 24 | enter(mon) 25 | -------------------------------------------------------------------------------- /harmony_model_checker/modules/synchBusy.hny: -------------------------------------------------------------------------------- 1 | def tas(lk): 2 | atomically: 3 | result = !lk 4 | !lk = True 5 | 6 | def Lock(): 7 | result = False 8 | 9 | def lock(lk): 10 | while tas(lk): 11 | pass 12 | 13 | def unlock(lk): 14 | !lk = False 15 | 16 | def Condition(lk): 17 | result = lk 18 | 19 | def wait(c): 20 | unlock(!c) 21 | lock(!c) 22 | 23 | def notify(c): 24 | pass 25 | 26 | def notify_all(c): 27 | pass 28 | 29 | # Deprecated 30 | def notifyAll(c): 31 | pass 32 | 33 | def Semaphore(cnt): 34 | result = cnt 35 | 36 | def P(sema): 37 | atomically when !sema > 0: 38 | !sema -= 1 39 | 40 | def V(sema): 41 | atomically !sema += 1 42 | -------------------------------------------------------------------------------- /harmony_model_checker/modules/synchImprecise.hny: -------------------------------------------------------------------------------- 1 | def tas(lk): 2 | atomically: 3 | result = !lk 4 | !lk = True 5 | 6 | def Lock(): 7 | result = False 8 | 9 | def lock(lk): 10 | while tas(lk): 11 | pass 12 | 13 | def unlock(lk): 14 | !lk = False 15 | 16 | def Condition(lk): 17 | result = { .lock: lk, .waiters: {} } 18 | 19 | def wait(c): 20 | var lk = None 21 | atomically: 22 | lk = c->lock 23 | c->waiters += { nametag() } 24 | !lk = False 25 | atomically when (not (!lk)) and (not ((nametag()) in c->waiters)): 26 | !lk = True 27 | 28 | def notify(c): 29 | atomically let waiters = c->waiters: 30 | if waiters != {}: 31 | c->waiters = waiters - { choose(waiters) } 32 | 33 | def notify_all(c): 34 | c->waiters = {} 35 | 36 | # Deprecated 37 | def notifyAll(c): 38 | c->waiters = {} 39 | 40 | def Semaphore(cnt): 41 | result = cnt 42 | 43 | def P(sema): 44 | atomically when (!sema) > 0: 45 | !sema -= 1 46 | 47 | def V(sema): 48 | atomically !sema += 1 49 | -------------------------------------------------------------------------------- /harmony_model_checker/modules/thread.hny: -------------------------------------------------------------------------------- 1 | import alloc, synch 2 | 3 | def _helper(closure, handle): 4 | handle->result = !closure 5 | synch.release(?handle->sema) 6 | 7 | def fork(closure) returns handle: 8 | handle = alloc.malloc({ .sema: synch.BinSema(True), .result: None }) 9 | spawn _helper(closure, handle) 10 | 11 | def join(meta) returns result: 12 | synch.acquire(?meta->sema) 13 | result = meta->result 14 | alloc.free(meta) 15 | -------------------------------------------------------------------------------- /harmony_model_checker/parser/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harmonylang/harmony/d06ac438fe7bd79539915cb67819728be5b7d803/harmony_model_checker/parser/__init__.py -------------------------------------------------------------------------------- /harmony_model_checker/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harmonylang/harmony/d06ac438fe7bd79539915cb67819728be5b7d803/harmony_model_checker/util/__init__.py -------------------------------------------------------------------------------- /heval: -------------------------------------------------------------------------------- 1 | file=/tmp/harmony$$ 2 | echo "print($*)" > $file.hny 3 | harmony --noweb $file.hny > /dev/null 2>&1 4 | python3 heval.py $file.hco 5 | rm -f $file.* 6 | -------------------------------------------------------------------------------- /install-test-pkg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | exec python3 -m pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple --upgrade harmony 4 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | -------------------------------------------------------------------------------- /python/Up.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | count = 0 4 | done = [ False, False ] 5 | 6 | def incrementer(self): 7 | global count 8 | count = count + 1 9 | done[self] = True 10 | while not done[1 - self]: 11 | pass 12 | assert count == 2 13 | 14 | threading.Thread(target=incrementer, args=(0,)).start() 15 | threading.Thread(target=incrementer, args=(1,)).start() 16 | -------------------------------------------------------------------------------- /python/UpMany.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | N = 1000000 4 | count = 0 5 | done = [ False, False ] 6 | 7 | def incrementer(self): 8 | global count 9 | for i in range(N): 10 | count = count + 1 11 | done[self] = True 12 | while not done[1 - self]: 13 | pass 14 | assert count == 2*N, count 15 | 16 | threading.Thread(target=incrementer, args=(0,)).start() 17 | threading.Thread(target=incrementer, args=(1,)).start() 18 | -------------------------------------------------------------------------------- /python/inc.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | shared = 0 4 | 5 | def f(): 6 | global shared 7 | shared += 1 8 | 9 | t1 = threading.Thread(target=f) 10 | t2 = threading.Thread(target=f) 11 | t1.start() 12 | t2.start() 13 | t1.join() 14 | t2.join() 15 | assert shared == 2 16 | -------------------------------------------------------------------------------- /python/incmany.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | N = 1000 4 | shared = 0 5 | 6 | def inc(x): 7 | return x + 1 8 | 9 | def f(): 10 | global shared 11 | for i in range(N): 12 | shared = inc(shared) 13 | 14 | t1 = threading.Thread(target=f) 15 | t2 = threading.Thread(target=f) 16 | t1.start() 17 | t2.start() 18 | t1.join() 19 | t2.join() 20 | assert shared == 2*N 21 | -------------------------------------------------------------------------------- /python/qtestpar.py: -------------------------------------------------------------------------------- 1 | import queue, threading, random 2 | 3 | NOPS = 4 4 | q = queue.Queue() 5 | 6 | def put_test(self): 7 | print("call put", self) 8 | q.put(self) 9 | print("done put", self) 10 | 11 | def get_test(self): 12 | print("call get", self) 13 | try: 14 | v = q.get(block=False) 15 | print("done get", self, v) 16 | except queue.Empty: 17 | print("done get empty", self) 18 | 19 | nputs = random.randint(1, NOPS - 1) 20 | for i in range(nputs): 21 | threading.Thread(target=put_test, args=(i,)).start() 22 | for i in range(NOPS - nputs): 23 | threading.Thread(target=get_test, args=(i,)).start() 24 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | antlr-denter==1.3.1 2 | antlr4-python3-runtime==4.9.3 3 | automata-lib==5.0.0 4 | lxml==5.3.0 5 | mypy==0.971 6 | mypy-extensions==0.4.3 7 | pydot==1.4.2 8 | requests==2.27.1 9 | twine==3.7.1 10 | types-requests==2.28.11 11 | types-setuptools==65.3.0 12 | types-urllib3==1.26.25 13 | typing_extensions==4.1.1 14 | -------------------------------------------------------------------------------- /test/Bakery.hny: -------------------------------------------------------------------------------- 1 | const NUM_THREADS = 3 2 | const MAX_ROUNDS = 2 3 | 4 | in_cs = 0 5 | invariant in_cs in { 0, 1 } 6 | 7 | sequential entering, number 8 | 9 | entering = [False,] * NUM_THREADS 10 | number = [0,] * NUM_THREADS 11 | 12 | def lock(i): 13 | entering[i] = True 14 | number[i] = max(number) + 1 15 | entering[i] = False 16 | for j in {0 .. NUM_THREADS - 1}: 17 | await not entering[j] 18 | await (number[j] == 0) or ((number[j], j) >= (number[i], i)) 19 | 20 | def unlock(i): 21 | number[i] = 0 22 | 23 | def process(self): 24 | for i in {1 .. choose { 0 .. MAX_ROUNDS } }: 25 | lock(self) 26 | atomically in_cs += 1 27 | atomically in_cs -= 1 28 | unlock(self) 29 | 30 | for i in {0 .. NUM_THREADS - 1}: 31 | spawn process(i) 32 | -------------------------------------------------------------------------------- /test/Dekker.hny: -------------------------------------------------------------------------------- 1 | in_cs = 0 2 | invariant in_cs in { 0, 1 } 3 | 4 | sequential flag, turn 5 | 6 | flag = [ False, False ] 7 | turn = choose {0, 1} 8 | 9 | def lock(self): 10 | flag[self] = True 11 | while flag[1 - self]: 12 | if turn != self: 13 | flag[self] = False 14 | await turn == self 15 | flag[self] = True 16 | 17 | def unlock(self): 18 | turn = 1 - self 19 | flag[self] = False 20 | 21 | def process(self): 22 | while choose({ False, True }): 23 | lock(self) 24 | atomically in_cs += 1 25 | atomically in_cs -= 1 26 | unlock(self) 27 | 28 | spawn process(0) 29 | spawn process(1) 30 | -------------------------------------------------------------------------------- /test/DinersCVwrong.hny: -------------------------------------------------------------------------------- 1 | import synch; 2 | 3 | const N = 5; 4 | 5 | def diner(which): 6 | let left = which, right = (which % N) + 1: 7 | while choose({ False, True }): 8 | call lock &(mutex); 9 | while forks[left]: 10 | call wait &(conds[left]); 11 | ; 12 | while forks[right]: 13 | call wait &(conds[right]); 14 | ; 15 | assert not forks[left]; 16 | assert not forks[right]; 17 | forks[left] = True; 18 | forks[right] = True; 19 | call unlock &(mutex); 20 | 21 | # dine 22 | 23 | call lock &(mutex); 24 | forks[left] = False; 25 | forks[right] = False; 26 | call notify &(conds[left]); 27 | call notify &(conds[right]); 28 | call unlock &(mutex); 29 | 30 | # think 31 | ; 32 | ; 33 | ; 34 | mutex = Lock(); 35 | forks = dict{ False for i in 1..N }; 36 | conds = dict{ Condition(&(mutex)) for i in 1..N }; 37 | for i in 1..N: 38 | spawn diner(i); 39 | ; 40 | -------------------------------------------------------------------------------- /test/DinersOrdered.hny: -------------------------------------------------------------------------------- 1 | import synch; 2 | 3 | const N = 5; 4 | 5 | def diner(which): 6 | let left, right = which, (which % N) + 1: 7 | if left < right: 8 | lock(?forks[left]); 9 | lock(?forks[right]); 10 | else: 11 | lock(?forks[right]); 12 | lock(?forks[left]); 13 | ; 14 | # dine 15 | unlock(?forks[left]); 16 | unlock(?forks[right]); 17 | # think 18 | ; 19 | ; 20 | forks = dict{ Lock() for i in {1..N} }; 21 | for i in {1..N}: 22 | spawn diner(i); 23 | ; 24 | -------------------------------------------------------------------------------- /test/DinersVar.hny: -------------------------------------------------------------------------------- 1 | from synch import Lock, acquire, release 2 | 3 | const N = 5 4 | 5 | forks = [Lock(),] * N 6 | 7 | def diner(which): 8 | # let left, right = (which, (which + 1) % N): 9 | var left, right = (which, (which + 1) % N) 10 | while choose({ False, True }): 11 | acquire(?forks[left]) 12 | acquire(?forks[right]) 13 | # dine 14 | release(?forks[left]) 15 | release(?forks[right]) 16 | # think 17 | 18 | for i in {0..N-1}: 19 | spawn diner(i) 20 | 21 | -------------------------------------------------------------------------------- /test/EM.hny: -------------------------------------------------------------------------------- 1 | # Eisenstein-McGuire mutual exclusion algorithm 2 | 3 | const N = 3; 4 | 5 | def lock(self): 6 | let blocked = True: 7 | while blocked: 8 | flags[self] = .waiting; 9 | let index = turn: 10 | while index != self: 11 | if flags[index] != .idle: 12 | index = turn; 13 | else: 14 | index = (index + 1) % N; 15 | ; 16 | ; 17 | ; 18 | flags[self] = .active; 19 | let index = 0: 20 | while ((index < N) and 21 | ((index == self) or (flags[index] != .active))): 22 | index = index + 1; 23 | ; 24 | if ((index >= N) and ((turn == self) or 25 | (flags[turn] == .idle))): 26 | blocked = False; 27 | ; 28 | ; 29 | ; 30 | ; 31 | turn = self; 32 | ; 33 | def unlock(self): 34 | let index = (turn + 1) % N: 35 | while flags[index] == .idle: 36 | index = (index + 1) % N; 37 | ; 38 | turn = index; 39 | ; 40 | flags[self] = .idle; 41 | ; 42 | flags = [.idle,] * N; 43 | turn = choose({0..N-1}); 44 | 45 | def process(self): 46 | while choose({ False, True }): 47 | lock(self); 48 | @cs: assert atLabel.cs == dict{ nametag(): 1 }; 49 | unlock(self); 50 | ; 51 | ; 52 | for i in {0..N-1}: 53 | spawn process(i); 54 | ; 55 | -------------------------------------------------------------------------------- /test/InfLoop.hny: -------------------------------------------------------------------------------- 1 | # mutual exclusion by infinite loop: safe but not live 2 | 3 | def process(): 4 | await False 5 | @cs: pass # critical section 6 | 7 | spawn process() 8 | spawn process() 9 | -------------------------------------------------------------------------------- /test/Lock.hny: -------------------------------------------------------------------------------- 1 | import synch; 2 | 3 | def process(lk): 4 | while choose({ False, True }): 5 | call lock(lk); 6 | @cs: assert atLabel.cs == dict{ nametag(): 1 }; 7 | call unlock(lk); 8 | ; 9 | ; 10 | mylock = Lock(); 11 | for i in 1..10: 12 | spawn process &(mylock); 13 | ; 14 | -------------------------------------------------------------------------------- /test/NotLiveSym.hny: -------------------------------------------------------------------------------- 1 | # symmetric but non-live solution to mutual exclusion problem 2 | 3 | def process(self): 4 | while choose({ False, True }): 5 | flags[self] = True; 6 | await not flags[1 - self]; 7 | @cs: assert atLabel.cs == dict{ nametag(): 1 }; 8 | flags[self] = False; 9 | ; 10 | ; 11 | flags = dict{ 0: False, 1: False }; 12 | spawn process(0), 0; 13 | spawn process(1), 1; 14 | -------------------------------------------------------------------------------- /test/NotSaveSym.hny: -------------------------------------------------------------------------------- 1 | # symmetric but non-safe solution to mutual exclusion problem 2 | 3 | def process(self): 4 | while choose({ False, True }): 5 | await not mutex; 6 | mutex = True; 7 | @cs: assert atLabel.cs == dict{ nametag(): 1 }; 8 | mutex = False; 9 | ; 10 | ; 11 | mutex = False; 12 | spawn process(0), 0; 13 | spawn process(1), 1; 14 | -------------------------------------------------------------------------------- /test/PCbinsem.hny: -------------------------------------------------------------------------------- 1 | # split binary semaphore solution to producer/consumer bounded buffer 2 | 3 | import synch; 4 | 5 | const N = 2; # size of bounded buffer 6 | 7 | def vHat(): 8 | if (cnt < N) and (pwaiting > 0): 9 | pwaiting = pwaiting - 1; 10 | V(?psema); 11 | elif (cnt > 0) and (cwaiting > 0): 12 | cwaiting = cwaiting - 1; 13 | V(?csema); 14 | else: 15 | V(?mutex); 16 | ; 17 | ; 18 | def produce(item): 19 | P(?mutex); 20 | if cnt == N: 21 | pwaiting = pwaiting + 1; 22 | vHat(); 23 | P(?psema); 24 | ; 25 | # buf[myin] = choose({ 10, 20 }); 26 | buf[myin] = item; 27 | myin = (myin % N) + 1; 28 | cnt = cnt + 1; 29 | vHat(); 30 | ; 31 | def consume(): 32 | P(?mutex); 33 | if cnt == 0: 34 | cwaiting = cwaiting + 1; 35 | vHat(); 36 | P(?csema); 37 | ; 38 | result = buf[myout]; 39 | myout = (myout % N) + 1; 40 | cnt = cnt - 1; 41 | vHat(); 42 | ; 43 | buf = dict{ 0 for x in {1..N} }; 44 | cnt = 0; 45 | myin = 1; 46 | myout = 1; 47 | pwaiting = 0; 48 | cwaiting = 0; 49 | mutex = Semaphore(1); 50 | psema = Semaphore(0); 51 | csema = Semaphore(0); 52 | -------------------------------------------------------------------------------- /test/PCcv.hny: -------------------------------------------------------------------------------- 1 | # condition variable solution to producer/consumer bounded buffer 2 | 3 | import synch; 4 | 5 | const N = 2; # size of bounded buffer 6 | 7 | def produce(item): 8 | call lock &(mylock); 9 | while cnt == N: 10 | call wait&(prodcv); 11 | ; 12 | cnt = cnt + 1; 13 | buf[myin] = item; 14 | myin = (myin % N) + 1; 15 | call notify&(conscv); 16 | call unlock &(mylock); 17 | ; 18 | def consume(): 19 | call lock &(mylock); 20 | while cnt == 0: 21 | call wait&(conscv); 22 | ; 23 | cnt = cnt - 1; 24 | result = buf[myout]; 25 | myout = (myout % N) + 1; 26 | call notify&(prodcv); 27 | call unlock &(mylock); 28 | ; 29 | def producer(): 30 | while True: 31 | # var item = choose({ 10, 20 }); 32 | var item = 1; 33 | @before_produce: 34 | call produce(item); 35 | @after_produce: pass; 36 | ; 37 | ; 38 | def consumer(): 39 | while True: 40 | @before_consume: 41 | var item = consume(); 42 | @after_consume: pass; 43 | ; 44 | ; 45 | buf = dict{ 0 for x in 1..N }; 46 | myin = 1; 47 | myout = 1; 48 | cnt = 0; 49 | mylock = Lock(); 50 | conscv = Condition&(mylock); 51 | prodcv = Condition&(mylock); 52 | 53 | spawn producer(), 0; 54 | spawn producer(), 0; 55 | spawn consumer(), 1; 56 | spawn consumer(), 1; 57 | -------------------------------------------------------------------------------- /test/PClock.hny: -------------------------------------------------------------------------------- 1 | # busy waiting solution to producer/consumer bounded buffer just using a lock 2 | 3 | import synch; 4 | 5 | const N = 2; # size of bounded buffer 6 | 7 | def produce(item): 8 | var full = True; 9 | while full: 10 | call lock &(mylock); 11 | if cnt < N: 12 | full = False; 13 | else: 14 | assert cnt == N, cnt; 15 | call unlock &(mylock); 16 | ; 17 | ; 18 | @room: 19 | cnt = cnt + 1; 20 | # buf[myin] = choose({ 10, 20 }); 21 | buf[myin] = item; 22 | myin = (myin % N) + 1; 23 | 24 | call unlock &(mylock); 25 | ; 26 | def consume(): 27 | var empty = True; 28 | while empty: 29 | call lock &(mylock); 30 | if cnt > 0: 31 | empty = False; 32 | else: 33 | assert cnt == 0, cnt; 34 | call unlock &(mylock); 35 | ; 36 | ; 37 | @avail: 38 | cnt = cnt - 1; 39 | result = buf[myout]; 40 | myout = (myout % N) + 1; 41 | call unlock &(mylock); 42 | ; 43 | def producer(): 44 | while True: 45 | # call produce(choose({ 10, 20 })); 46 | call produce(1); 47 | @produced: pass; 48 | ; 49 | ; 50 | def consumer(): 51 | while True: 52 | call consume(); 53 | @consumed: pass; 54 | ; 55 | ; 56 | buf = dict{ 0 for x in 1..N }; 57 | myin = 1; 58 | myout = 1; 59 | cnt = 0; 60 | mylock = Lock(); 61 | 62 | spawn producer(), 0; 63 | spawn producer(), 0; 64 | spawn consumer(), 1; 65 | spawn consumer(), 1; 66 | -------------------------------------------------------------------------------- /test/PetersonBadProof.hny: -------------------------------------------------------------------------------- 1 | # Peterson's algorithm 2 | 3 | def process(self): 4 | while True: 5 | flags[self] = True; 6 | turn = 1 - self; 7 | await (not flags[1 - self]) or (turn == self); 8 | @cs: assert (not (flags[1 - self])) or (turn == self); 9 | flags[self] = False; 10 | ; 11 | ; 12 | flags = [ False, False ]; 13 | turn = 0; 14 | spawn process(0), 0; 15 | spawn process(1), 1; 16 | -------------------------------------------------------------------------------- /test/PetersonBroken.hny: -------------------------------------------------------------------------------- 1 | # Broken Peterson's algorithm by swapping first two assignments 2 | 3 | flags = [ False, False ] 4 | turn = choose({0, 1}) 5 | 6 | def thread(self): 7 | while choose({ False, True }): 8 | # Enter critical section 9 | turn = 1 - self 10 | flags[self] = True 11 | await (not flags[1 - self]) or (turn == self) 12 | 13 | # critical section is here 14 | @cs: assert atLabel(cs) == { (thread, self): 1 } 15 | 16 | # Leave critical section 17 | flags[self] = False 18 | 19 | spawn thread(0) 20 | spawn thread(1) 21 | -------------------------------------------------------------------------------- /test/PetersonOO.hny: -------------------------------------------------------------------------------- 1 | def P_enter(pm, pid): 2 | (!pm).flags[pid] = True; 3 | (!pm).turn = 1 - pid; 4 | await (not (!pm).flags[1 - pid]) or ((!pm).turn == pid); 5 | ; 6 | def P_exit(pm, pid): 7 | (!pm).flags[pid] = False; 8 | ; 9 | def P_mutex(): 10 | result = dict{ 11 | .turn: 0, .flags: [ False, False ], 12 | .enter: P_enter, .exit: P_exit 13 | }; 14 | ; 15 | def process(self, pm): 16 | while choose({ False, True }): 17 | call (!pm).enter(pm, self); 18 | @cs: assert atLabel.cs == dict{ nametag(): 1 }; 19 | call (!pm).exit(pm, self); 20 | ; 21 | ; 22 | mutex = P_mutex(); 23 | spawn process(0, ?(mutex)), 0; 24 | spawn process(1, ?(mutex)), 1; 25 | -------------------------------------------------------------------------------- /test/RWbadlock.hny: -------------------------------------------------------------------------------- 1 | import synch; 2 | 3 | def process(): 4 | while choose({ False, True }): 5 | if choose({ .reader, .writer }) == .reader: 6 | call lock &(rwlock); 7 | 8 | @rcs: assert atLabel.wcs == dict{} 9 | ; 10 | 11 | call unlock &(rwlock); 12 | else: 13 | call lock &(rwlock); 14 | 15 | @wcs: assert (atLabel.wcs == dict{ nametag(): 1 }) and 16 | (atLabel.rcs == dict{}) 17 | ; 18 | 19 | call unlock &(rwlock); 20 | ; 21 | ; 22 | ; 23 | rwlock = Lock(); 24 | for i in 1..4: 25 | spawn process(); 26 | ; 27 | -------------------------------------------------------------------------------- /test/Sema.hny: -------------------------------------------------------------------------------- 1 | # correct mutual exclusion using a binary semaphore 2 | 3 | import synch; 4 | 5 | def process(): 6 | while choose({ False, True }): 7 | call P&(mysema); 8 | @cs: assert atLabel.cs == dict{ nametag(): 1 }; 9 | call V&(mysema); 10 | ; 11 | ; 12 | mysema = Semaphore(1); 13 | spawn process(), 0; 14 | spawn process(), 0; 15 | spawn process(), 1; 16 | spawn process(), 1; 17 | -------------------------------------------------------------------------------- /test/Stop.hny: -------------------------------------------------------------------------------- 1 | import synch; 2 | 3 | def process(lk): 4 | call lock(lk); 5 | call unlock(lk); 6 | ; 7 | mylock = Lock(); 8 | for i in 1..2: 9 | spawn process &(mylock); 10 | ; 11 | -------------------------------------------------------------------------------- /test/Szymanski.hny: -------------------------------------------------------------------------------- 1 | const N = 3 2 | 3 | sequential flag 4 | 5 | flag = { i:0 for i in {1..N} } 6 | 7 | def lock(self): 8 | flag[self] = 1 9 | await all(flag[i] in { 0, 1, 2 } for i in {1..N}) 10 | flag[self] = 3 11 | if any(flag[i] == 1 for i in {1..N}): 12 | flag[self] = 2 13 | await any(flag[i] == 4 for i in {1..N}) 14 | flag[self] = 4 15 | await all(flag[i] in { 0, 1 } for i in {1..self-1}) 16 | 17 | def unlock(self): 18 | await all(flag[i] in { 0, 1, 4 } for i in {self+1..N}) 19 | flag[self] = 0 20 | 21 | def process(self): 22 | while choose({ False, True }): 23 | lock(self) 24 | @cs: assert atLabel(cs) == { (process, self): 1 } 25 | unlock(self) 26 | 27 | for i in {1..N}: 28 | spawn process(i) 29 | -------------------------------------------------------------------------------- /test/Turn.hny: -------------------------------------------------------------------------------- 1 | def p(self): 2 | while choose({ False, True }): 3 | @ncs: pass; 4 | 5 | # Enter critical section 6 | await turn == self; 7 | 8 | # Critical section 9 | @cs: assert atLabel.cs == dict{ nametag(): 1 }; 10 | 11 | # Leave critical section 12 | turn = 1 - self; 13 | ; 14 | ; 15 | turn = 0; 16 | spawn p(0), 0; 17 | spawn p(1), 1; 18 | -------------------------------------------------------------------------------- /test/anonbosco.hny: -------------------------------------------------------------------------------- 1 | import bag 2 | 3 | const F = 1 4 | const N = (3 * F) + 1 5 | const NROUNDS = 3 6 | 7 | network = bag.empty() 8 | decisions = {} 9 | 10 | def broadcast(msg): 11 | atomic: 12 | bag.add(?network, msg) 13 | 14 | # Wait for k messages in the given round 15 | def receive(round, k): 16 | let msgs = bag.empty(): 17 | while bag.size(msgs) < k: 18 | atomic: 19 | msgs = { (r,e):network[r, e] 20 | for r, e in keys(network) where r == round } 21 | result = choose(bag.combinations(msgs, k)) 22 | 23 | def process(proposal): 24 | let est = proposal: 25 | for round in {0..NROUNDS-1}: 26 | # Broadcast estimate 27 | broadcast(round, est) 28 | 29 | let quorum = receive(round, N - F) 30 | let count = [ bag.count(quorum, (round, i)) for i in { 0..1 } ]: 31 | assert (count[0] + count[1]) == (N - F) 32 | assert count[0] != count[1] 33 | est = 0 if count[0] > count[1] else 1 34 | if count[est] == (N - F): 35 | atomic: 36 | decisions |= { est } 37 | assert len(decisions) <= 1 38 | 39 | let nzeroes = choose({0..N/2}): 40 | for i in {0..N-1}: 41 | spawn process(0 if i < nzeroes else 1) 42 | -------------------------------------------------------------------------------- /test/anonbosco2.hny: -------------------------------------------------------------------------------- 1 | import bag 2 | 3 | const F = 1 4 | const N = (3 * F) + 1 5 | const NROUNDS = 3 6 | 7 | network = bag.empty() 8 | decisions = {} 9 | 10 | def broadcast(msg): 11 | atomic: 12 | bag.add(?network, msg) 13 | 14 | def receive(round, k): 15 | let msgs = { (r,e):c for (r,e):c in network where r == round }: 16 | result = bag.combinations(msgs, k) 17 | 18 | def process(proposal): 19 | broadcast(0, proposal) 20 | for round in {0..NROUNDS-1}: 21 | select quorum in receive(round, N - F): 22 | let count = [ bag.count(quorum, (round, i)) for i in { 0..1 } ]: 23 | assert(count[0] != count[1]) 24 | proposal = 0 if count[0] > count[1] else 1 25 | if count[proposal] == (N - F): 26 | decisions |= { proposal } 27 | assert len(decisions) <= 1 28 | broadcast(round + 1, proposal) 29 | 30 | let nzeroes = choose({0..N/2}): 31 | for i in {0..N-1}: 32 | spawn process(0 if i < nzeroes else 1) 33 | -------------------------------------------------------------------------------- /test/anonbosco3.hny: -------------------------------------------------------------------------------- 1 | import synch, bag, list 2 | 3 | const F = 1 4 | const N = (3 * F) + 1 5 | const NROUNDS = 3 6 | 7 | sequential network 8 | 9 | network = bag.empty() 10 | decisions = {} 11 | 12 | def broadcast(msg): 13 | atomic: 14 | bag.add(?network, msg) 15 | 16 | def receive(round): 17 | let receiving = True: 18 | while receiving: 19 | atomic: 20 | receiving = list.sum(network[r, e] for (r, e) in keys(network) 21 | where r == round) < (N - F) 22 | result = network 23 | 24 | def process(proposal): 25 | let est = proposal: 26 | for round in {0..NROUNDS-1}: 27 | # Broadcast estimate 28 | broadcast(round, est) 29 | 30 | let msgs = receive(round) 31 | let count = [0, 0] 32 | let m = { e:msgs[r,e] for (r, e) in keys(msgs) where r == round }: 33 | while bag.size(m) > (N - F): 34 | let e = bag.bchoose(m): 35 | m = bag.f_remove(m, e) 36 | 37 | # Update estimate 38 | if 0 in keys(m): 39 | count[0] = m[0] 40 | if 1 in keys(m): 41 | count[1] = m[1] 42 | assert(count[0] != count[1]) 43 | est = 0 if count[0] < count[1] else 1 44 | if count[est] == (N - F): 45 | atomic: 46 | decisions |= { est } 47 | assert len(decisions) <= 1 48 | 49 | let nzeroes = choose({0..N/2}): 50 | for i in {0..N-1}: 51 | spawn process(0 if i < nzeroes else 1) 52 | -------------------------------------------------------------------------------- /test/barber.hny: -------------------------------------------------------------------------------- 1 | import synch; 2 | 3 | const NSEATS = 2; 4 | 5 | seated = {}; 6 | done = {}; 7 | mutex = Lock(); 8 | barbercond = Condition(?mutex); 9 | customercond = Condition(?mutex); 10 | 11 | def barber_sleep(): 12 | lock(?mutex); 13 | while seated == {}: 14 | wait(?barbercond); 15 | ; 16 | result = choose(seated); 17 | seated -= { result }; 18 | unlock(?mutex); 19 | ; 20 | def barber_finished(customer): 21 | lock(?mutex); 22 | done |= { customer }; 23 | notifyAll(?customercond); 24 | unlock(?mutex); 25 | ; 26 | def customer_enter(self): 27 | lock(?mutex); 28 | if len(seated) == NSEATS: 29 | result = False; 30 | else: 31 | seated |= { self }; 32 | notify(?barbercond); 33 | result = True; 34 | ; 35 | unlock(?mutex); 36 | ; 37 | def customer_wait(self): 38 | lock(?mutex); 39 | while self not in done: 40 | wait(?customercond); 41 | ; 42 | unlock(?mutex); 43 | ; 44 | 45 | def barber(): 46 | let customer = barber_sleep(): 47 | # barber cuts customer's hair 48 | barber_finished(customer); 49 | ; 50 | ; 51 | def customer(self): 52 | if customer_enter(self): 53 | # customer waits for barber 54 | customer_wait(self); 55 | ; 56 | ; 57 | for i in {1..2}: 58 | spawn barber(); 59 | spawn customer(i); 60 | ; 61 | -------------------------------------------------------------------------------- /test/barriertest.hny: -------------------------------------------------------------------------------- 1 | import synch 2 | 3 | const NROUNDS = 3 4 | const NPROC = 3 5 | 6 | def barrier_enter(self): 7 | lock(?mutex) 8 | nstarting += 1 9 | if nstarting < NPROC: 10 | while nstarting < NPROC: 11 | wait(?start) 12 | else: 13 | nfinishing = 0 14 | notifyAll(?start) 15 | unlock(?mutex) 16 | 17 | def barrier_exit(self): 18 | lock(?mutex) 19 | nfinishing += 1 20 | if nfinishing < NPROC: 21 | while nfinishing < NPROC: 22 | wait(?finish) 23 | else: 24 | nstarting = 0 25 | notifyAll(?finish) 26 | 27 | unlock(?mutex) 28 | 29 | mutex = Lock() 30 | start = Condition(?mutex) 31 | finish = Condition(?mutex) 32 | nstarting = 0 33 | nfinishing = 0 34 | 35 | # check that all non-None values in round are the same 36 | def check(): 37 | result = True 38 | let x = None: 39 | for i in {0..NPROC-1}: 40 | if result and (round[i] != None): 41 | if x != None: 42 | result = round[i] == x 43 | x = round[i] 44 | 45 | def process(self): 46 | for r in {0..NROUNDS-1}: 47 | barrier_enter(self) 48 | round[self] = r 49 | assert check() 50 | round[self] = None 51 | barrier_exit(self) 52 | done[self] = True 53 | 54 | def main(): 55 | await all(done) 56 | 57 | round = [None,] * NPROC 58 | done = [False,] * NPROC 59 | for i in {0..NPROC-1}: 60 | spawn process(i) 61 | spawn main() 62 | -------------------------------------------------------------------------------- /test/bosco.hny: -------------------------------------------------------------------------------- 1 | import synch 2 | 3 | const N = 4 4 | const F = 1 5 | const NROUNDS = 2 6 | 7 | sequential network, done 8 | 9 | network = {} 10 | decisions = {} 11 | done = [False,] * N 12 | 13 | def broadcast(msg): 14 | atomic: 15 | network |= {msg} 16 | 17 | def process(self, proposal): 18 | let est = proposal: 19 | for round in {0..NROUNDS-1}: 20 | # Broadcast estimate 21 | broadcast(self, round, est) 22 | 23 | # Handle received messages 24 | let received = {(self, round, est)}: 25 | # Receive messages until there are enough 26 | while len(received) < (N - F): 27 | let eligible = { (p,r,e) for (p,r,e) in (network - received) 28 | where r == round }: 29 | if len(eligible) > 0: 30 | received |= {choose(eligible)} 31 | 32 | # Update estimate 33 | let ests = { e for (p,r,e) in received } 34 | let cnts = { (len({(p,x) for (p,r,x) in received 35 | where x == e}), e) for e in ests } 36 | let (n, best) = max(cnts): 37 | est = best 38 | if n >= (N - F): 39 | atomic: 40 | decisions |= { best } 41 | 42 | done[self] = True 43 | 44 | def main(): 45 | await all(done) 46 | assert len(decisions) <= 1 47 | 48 | let nzeroes = choose({0..N/2}): 49 | for i in {0..N-1}: 50 | spawn process(i, 0 if i < nzeroes else 1) 51 | 52 | spawn main() 53 | -------------------------------------------------------------------------------- /test/bound.hny: -------------------------------------------------------------------------------- 1 | import synch; 2 | 3 | def BLnew(bound): 4 | result = dict{ .lock: Lock(), .count: 0, .bound: bound }; 5 | ; 6 | 7 | def BLacquire(bl): 8 | let blocked = True: 9 | while blocked: 10 | lock(?bl->lock); 11 | if bl->count < bl->bound: 12 | bl->count += 1; 13 | blocked = False; 14 | ; 15 | unlock(?bl->lock); 16 | ; 17 | ; 18 | ; 19 | 20 | def BLrelease(bl): 21 | lock(?bl->lock); 22 | bl->count -= 1; 23 | unlock(?bl->lock); 24 | ; 25 | -------------------------------------------------------------------------------- /test/bound_chk1.hny: -------------------------------------------------------------------------------- 1 | import boundsem; 2 | import list; 3 | 4 | const BOUND = 2; 5 | const NPROC = 3; 6 | 7 | boundlock = BLnew(BOUND); 8 | # BLinit(?boundlock); 9 | acquired = [0,] * NPROC; 10 | 11 | def tester(self, bl): 12 | BLacquire(bl); 13 | acquired[self] = 1; 14 | assert sum(acquired) <= BOUND; 15 | acquired[self] = 0; 16 | BLrelease(bl); 17 | ; 18 | 19 | for i in {0..NPROC-1}: 20 | spawn tester(i, ?boundlock); 21 | ; 22 | -------------------------------------------------------------------------------- /test/bound_chk2.hny: -------------------------------------------------------------------------------- 1 | import boundsem; 2 | import list; 3 | 4 | const BOUND = 2; 5 | const NPROC = 3; 6 | 7 | boundlock = BLnew(BOUND); 8 | # BLinit(?boundlock); 9 | acquired = [0,] * NPROC; 10 | 11 | def waiter(self, bl): 12 | BLacquire(bl); 13 | acquired[self] = 1; 14 | await sum(acquired) >= BOUND; 15 | BLrelease(bl); 16 | ; 17 | 18 | for i in {0..NPROC-1}: 19 | spawn waiter(i, ?boundlock); 20 | ; 21 | -------------------------------------------------------------------------------- /test/busywait.hny: -------------------------------------------------------------------------------- 1 | let blocked = True: 2 | while blocked: 3 | lock(); 4 | if application-condition-holds: 5 | blocked = False; 6 | else: 7 | unlock(): 8 | @cr: application-code; 9 | unlock(): 10 | -------------------------------------------------------------------------------- /test/byzbosco.hny: -------------------------------------------------------------------------------- 1 | import bag 2 | 3 | const F = 1 4 | const N = (5 * F) + 1 5 | const NROUNDS = 2 6 | 7 | network = bag.empty() 8 | decisions = {} 9 | 10 | def broadcast(msg): 11 | atomic: 12 | bag.add(?network, msg) 13 | 14 | def receive(round, k): 15 | let msgs = { (r,e):c for (r,e):c in network where r == round }: 16 | result = bag.combinations(msgs, k) 17 | 18 | def process(proposal): 19 | broadcast(0, proposal) 20 | for round in {0..NROUNDS-1}: 21 | select quorum in receive(round, N - F): 22 | let count = [ bag.count(quorum, (round, i)) for i in { 0..1 } ]: 23 | assert(count[0] != count[1]) 24 | proposal = 0 if count[0] > count[1] else 1 25 | if count[proposal] == (N - F): 26 | decisions |= { proposal } 27 | assert len(decisions) <= 1 28 | broadcast(round + 1, proposal) 29 | 30 | def adversary(): 31 | broadcast(0, 0) 32 | broadcast(0, 1) 33 | for round in {0..NROUNDS-1}: 34 | select quorum in receive(round, N - F): 35 | broadcast(round + 1, 0) 36 | broadcast(round + 1, 1) 37 | 38 | for i in {1..N - F}: 39 | spawn process(choose({ 0, 1 })) 40 | for i in {1..F}: 41 | spawn adversary() 42 | -------------------------------------------------------------------------------- /test/ctriangle.hny: -------------------------------------------------------------------------------- 1 | const N = 10; 2 | 3 | def mystery(n): 4 | result = 2; 5 | for i in {1..n}: 6 | result += 6 * i; 7 | ; 8 | ; 9 | x = choose({0..N}); 10 | assert mystery(x) == ((3 * (x ** 2)) + (3 * x) + 2); 11 | -------------------------------------------------------------------------------- /test/dijkstra.hny: -------------------------------------------------------------------------------- 1 | # Mutual exclusion based on Dijkstra's "Solution of a Problem in 2 | # Concurrent Programming Control" 3 | 4 | sequential flags, turn, ready 5 | 6 | def Lock(n) returns lock: 7 | lock = { 8 | .flags: [False,] * n, 9 | .ready: [False,] * n, 10 | .turn: choose { 0 .. n - 1 } 11 | } 12 | 13 | def acquire(self, lk): 14 | lk->flags[self] = lk->ready[self] = True 15 | while any(lk->ready[i] 16 | for i in { 0 .. len(lk->ready) - 1 } where i != self): 17 | while (lk->turn != self) or not lk->flags[lk->turn]: 18 | lk->ready[self] = False 19 | if not lk->flags[lk->turn]: 20 | lk->turn = self 21 | lk->ready[self] = True 22 | 23 | def release(self, lk): 24 | lk->flags[self] = lk->ready[self] = False 25 | 26 | ######## 27 | 28 | const N = 3 29 | 30 | sequential thelock 31 | thelock = Lock(N) 32 | 33 | def process(self): 34 | while choose { False, True }: 35 | acquire(self, ?thelock) 36 | cs: assert countLabel(cs) == 1 37 | release(self, ?thelock) 38 | 39 | for x in { 0 .. N - 1 }: 40 | spawn process(x) 41 | -------------------------------------------------------------------------------- /test/extqtest.hny: -------------------------------------------------------------------------------- 1 | def chkleak(): 2 | pass; 3 | ; 4 | 5 | import extqueue; 6 | 7 | const MAX = 5; 8 | 9 | q = Qnew(); 10 | assert not Qcontains(?q, 0); 11 | 12 | # Tail pointer test 13 | Qenqueue(?q, 0); 14 | Qenqueue(?q, 1); 15 | Qremove(?q, 1); 16 | Qenqueue(?q, 1); 17 | assert Qcontains(?q, 0); 18 | assert Qcontains(?q, 1); 19 | Qremove(?q, 0); 20 | Qremove(?q, 1); 21 | 22 | n = 0; 23 | N = choose{1..MAX}; 24 | for i in {1..N}: 25 | let v = choose({0, 1}): 26 | if v == 0: 27 | n += 1; 28 | ; 29 | Qenqueue(?q, v); 30 | if n > 0: 31 | assert Qcontains(?q, 0), n; 32 | ; 33 | if n < i: 34 | assert Qcontains(?q, 1), (N, n); 35 | ; 36 | ; 37 | ; 38 | Qremove(?q, 0); 39 | assert not Qcontains(?q, 0); 40 | if n < N: 41 | assert Qcontains(?q, 1), (N, n); 42 | ; 43 | Qenqueue(?q, 1); 44 | assert Qcontains(?q, 1); 45 | Qremove(?q, 1); 46 | assert not Qcontains(?q, 1); 47 | assert not Qcontains(?q, 0); 48 | chkleak(); 49 | -------------------------------------------------------------------------------- /test/extqueue.hny: -------------------------------------------------------------------------------- 1 | import alloc; 2 | 3 | def Qnew(): 4 | result = dict{ .head: None, .tail: None, .lock: Lock() }; 5 | ; 6 | def Qenqueue(q, v): 7 | let node = malloc(dict{ .value: v, .next: None }): 8 | lock(?q->lock); 9 | if q->head == None: 10 | q->head = q->tail = node; 11 | else: 12 | q->tail->next = node; 13 | q->tail = node; 14 | ; 15 | unlock(?q->lock); 16 | ; 17 | ; 18 | def Qdequeue(q): 19 | lock(?q->lock); 20 | let node = q->head: 21 | if node == None: 22 | result = (); 23 | else: 24 | result = (node->value,); 25 | q->head = node->next; 26 | free(node); 27 | ; 28 | ; 29 | unlock(?q->lock); 30 | ; 31 | def Qcontains(q, v): 32 | lock(?q->lock); 33 | result = False; 34 | let node = q->head: 35 | while (node != None) and not result: 36 | if node->value == v: 37 | result = True; 38 | ; 39 | node = node->next; 40 | ; 41 | ; 42 | unlock(?q->lock); 43 | ; 44 | def Qremove(q, v): 45 | lock(?q->lock); 46 | q->tail = None; 47 | let p = ?q->head: 48 | while !p != None: 49 | let node = !p: 50 | if node->value == v: 51 | !p = node->next; 52 | free(node); 53 | else: 54 | q->tail = node; 55 | p = ?node->next; 56 | ; 57 | ; 58 | ; 59 | ; 60 | unlock(?q->lock); 61 | ; 62 | -------------------------------------------------------------------------------- /test/msort.hny: -------------------------------------------------------------------------------- 1 | import list; 2 | 3 | const N = 4; 4 | 5 | def merge(lower, higher): 6 | result = []; 7 | let i = 0, j = 0, ll = len(lower), lh = len(higher): 8 | while (i < ll) or (j < lh): 9 | if (j == lh) or ((i < ll) and (lower[i] < higher[j])): 10 | result = result + [lower[i],]; 11 | i = i + 1; 12 | else: 13 | result = result + [higher[j],]; 14 | j = j + 1; 15 | ; 16 | ; 17 | ; 18 | ; 19 | def mergesort(a): 20 | if len(a) <= 1: 21 | result = a; 22 | else: 23 | let half = len(a)/2: 24 | result = merge( 25 | mergesort(subseq(a, 0, half)), 26 | mergesort(subseq(a, half, len(a))) 27 | ); 28 | ; 29 | ; 30 | ; 31 | def sorted(a): 32 | result = True; 33 | for i in 1..(len(a) - 1): 34 | if a[i - 1] > a[i]: 35 | result = False; 36 | ; 37 | ; 38 | ; 39 | 40 | const values = 1..N; 41 | input = [ choose(values) for i in 1..choose(0..N) ]; 42 | output = mergesort(input); 43 | assert sorted(output); 44 | assert list2bag(input) == list2bag(output), (input, output); 45 | -------------------------------------------------------------------------------- /test/mutex.hny: -------------------------------------------------------------------------------- 1 | fun __mutex__(): 2 | let P = processes(), Q = atLabel.cs, nprocs = 0, ncs = 0: 3 | for p in keys(P): 4 | nprocs = nprocs + P[p]; 5 | ; 6 | for q in keys(Q): 7 | ncs = ncs + Q[q]; 8 | ; 9 | assert (ncs == 0) or (ncs == 1); 10 | assert ncs <= nprocs; 11 | result = (nprocs, ncs); 12 | ; 13 | ; 14 | fun __step__(state): 15 | if state[0] == 0: 16 | assert state[1] == 0; 17 | result = { }; 18 | elif (state[0] == 1) and (state[1] == 1): 19 | result = { (state[0], 0) }; 20 | else: 21 | assert state[0] > 0, state; 22 | assert (state[1] == 0) or (state[1] == 1); 23 | result = { (state[0] - 1, state[1]), (state[0], 1 - state[1]) }; 24 | ; 25 | ; 26 | -------------------------------------------------------------------------------- /test/pascal.hny: -------------------------------------------------------------------------------- 1 | const N = 2 2 | 3 | def factorial(n): 4 | result = 1 if n == 0 else (n * factorial(n - 1)) 5 | 6 | def C(n, k): 7 | result = factorial(n) / (factorial(k) * factorial(n - k)) 8 | 9 | def pascal(x, n, k): 10 | result = 0 11 | while x > 0: 12 | if k == n: 13 | k, n = 0, n + 1 14 | else: 15 | k += 1 16 | result += C(n, k) 17 | x -= 1 18 | 19 | x = choose({0..N}) 20 | # assert pascal(x, 0, 0) == x 21 | assert pascal((x * (x + 1))/2, 0, 0) == ((2 ** x) - 1) 22 | -------------------------------------------------------------------------------- /test/poolmesa.hny: -------------------------------------------------------------------------------- 1 | from synch import * 2 | 3 | def Pool(nlanes): 4 | result = { 5 | .mutex: Lock(), 6 | .condition: [ Condition(), Condition() ], 7 | .count: [ 0, 0 ], 8 | .nlanes: nlanes 9 | } 10 | 11 | def enter(pool, level): 12 | acquire(?pool->mutex) 13 | while (pool->count[1 - level] > 0) or (pool->count[level] == pool->nlanes): 14 | wait(?pool->condition[level], ?pool->mutex) 15 | pool->count[level] += 1 16 | release(?pool->mutex) 17 | 18 | def exit(pool, level): 19 | acquire(?pool->mutex) 20 | notify(?pool->condition[level]) 21 | pool->count[level] -= 1 22 | if pool->count[level] == 0: 23 | notifyAll(?pool->condition[1 - level]) 24 | release(?pool->mutex) 25 | -------------------------------------------------------------------------------- /test/poolsbs.hny: -------------------------------------------------------------------------------- 1 | from synch import BinSema, acquire, release 2 | 3 | def Pool(nlanes): 4 | result = { 5 | .mutex: BinSema(False), .condition: [BinSema(True),] * 2, 6 | .waiting: [ 0, 0 ], .count: [ 0, 0 ], .nlanes: nlanes 7 | } 8 | 9 | def release_one(pool): 10 | if (pool->count[1] == 0) and (pool->count[0] < pool->nlanes) and (pool->waiting[0] > 0): 11 | release(?pool->condition[0]) 12 | elif (pool->count[0] == 0) and (pool->count[1] < pool->nlanes) and (pool->waiting[1] > 0): 13 | release(?pool->condition[1]) 14 | else: 15 | release(?pool->mutex) 16 | 17 | def enter(pool, level): 18 | acquire(?pool->mutex) 19 | if (pool->count[1 - level] > 0) or (pool->count[level] == pool->nlanes): 20 | pool->waiting[level] += 1 21 | release(?pool->mutex) 22 | acquire(?pool->condition[level]) 23 | pool->waiting[level] -= 1 24 | pool->count[level] += 1 25 | release_one(pool) 26 | 27 | def exit(pool, level): 28 | acquire(?pool->mutex) 29 | pool->count[level] -= 1 30 | release_one(pool) 31 | -------------------------------------------------------------------------------- /test/pooltest.hny: -------------------------------------------------------------------------------- 1 | import pool, list 2 | 3 | const NMIDDLE = 3 4 | const NHIGH = 3 5 | const NLANES = 2 6 | 7 | schoolpool = pool.Pool(NLANES) 8 | inpool_ms = [0,] * NMIDDLE 9 | inpool_hs = [0,] * NHIGH 10 | inpool = [ inpool_ms, inpool_hs ] 11 | 12 | def student(level, id): 13 | pool.enter(?schoolpool, level) 14 | inpool[level][id] = 1 15 | assert list.sum(inpool[level]) <= NLANES 16 | assert list.sum(inpool[1 - level]) == 0 17 | inpool[level][id] = 0 18 | pool.exit(?schoolpool, level) 19 | 20 | for i in {1..NMIDDLE}: 21 | spawn student(0, i) 22 | for i in {1..NHIGH}: 23 | spawn student(1, i) 24 | -------------------------------------------------------------------------------- /test/queue.hny: -------------------------------------------------------------------------------- 1 | const Q_NPOOL = 10; # number of queue node entries 2 | const Q_END = -1; # end of queue 3 | 4 | def q_release(qnode): 5 | q_pool[qnode].next = q_free; 6 | q_free = qnode; 7 | ; 8 | def q_new(): 9 | result = q_free; 10 | q_free = q_pool[result].next; 11 | q_pool[result].next = Q_END; 12 | ; 13 | def enqueue(item): 14 | new = q_new(); 15 | if q_tail == Q_END: 16 | q_head = new; 17 | else: 18 | q_pool[q_tail].next = new; 19 | ; 20 | q_tail = new; 21 | q_pool[new].item = item; 22 | ; 23 | def dequeue(): 24 | head = q_head; 25 | result = q_pool[head].item; 26 | q_head = q_pool[head].next; 27 | call q_release(head); 28 | ; 29 | 30 | q_pool = [ dict{ .item: (), .next: Q_END } for i in 0..(Q_NPOOL-1) ]; 31 | q_free = -1; 32 | for i in 0..(Q_NPOOL-1): 33 | call q_release(i); 34 | ; 35 | q_head = Q_END; 36 | q_tail = Q_END; 37 | 38 | call enqueue(1); 39 | call enqueue(2); 40 | call enqueue(3); 41 | x = dequeue(); 42 | assert x == 1; 43 | x = dequeue(); 44 | assert x == 2; 45 | x = dequeue(); 46 | assert x == 3; 47 | -------------------------------------------------------------------------------- /test/rdwr.hny: -------------------------------------------------------------------------------- 1 | fun __mutex__(): 2 | let n = bagsize(processes()), nrcs = bagsize(atLabel.rcs), 3 | nwcs = bagsize(atLabel.wcs): 4 | assert ((nrcs >= 0) and (nwcs == 0)) or ((nrcs == 0) and (nwcs == 1)); 5 | assert (nrcs + nwcs) <= n; 6 | result = (n, nrcs, nwcs); 7 | ; 8 | ; 9 | fun __step__(state): 10 | assert (state[1] + state[2]) <= state[0]; 11 | if state == (0, 0, 0): 12 | result = { }; 13 | elif state[0] == state[1]: # all processes are readers 14 | assert state[2] == 0; 15 | result = { (state[0], state[1] - 1, 0) }; 16 | elif state[0] == state[2]: # all processes are writers 17 | assert state[1] == 0; 18 | assert state[2] == 1; 19 | result = { (state[0], 0, state[2] - 1) }; 20 | elif state[1] > 0: 21 | assert state[2] == 0; 22 | result = { (state[0] - 1, state[1], 0), (state[0], state[1] - 1, 0), 23 | (state[0], state[1] + 1, 0) }; 24 | elif state[2] > 0: 25 | assert state[1] == 0; 26 | assert state[2] == 1; 27 | result = { (state[0] - 1, 0, state[2]), (state[0], 0, 0) }; 28 | else: 29 | assert state[1] == 0; 30 | assert state[2] == 0; 31 | result = { (state[0] - 1, 0, 0), (state[0], 1, 0), (state[0], 0, 1) }; 32 | ; 33 | ; 34 | -------------------------------------------------------------------------------- /test/sorttest.hny: -------------------------------------------------------------------------------- 1 | import list; 2 | 3 | const N = 4; 4 | 5 | def sorted(a): 6 | result = True; 7 | for i in 1..(len(a) - 1): 8 | if a[i - 1] > a[i]: 9 | result = False; 10 | ; 11 | ; 12 | ; 13 | const values = 1..N; 14 | list = [ choose(values) for i in 1..choose(0..N) ]; 15 | s = qsort(list); 16 | assert sorted(s); 17 | assert list2bag(list) == list2bag(s); 18 | -------------------------------------------------------------------------------- /test/teahouse.hny: -------------------------------------------------------------------------------- 1 | from synch import * 2 | 3 | const NPAIRS = 3 4 | 5 | def Teahouse(): 6 | result = { 7 | .mutex: Lock(), 8 | .tables: { .black: 0, .green: 0 }, 9 | .seating: { .black: Condition(), .green: Condition() }, 10 | .drinking: { .black: Condition(), .green: Condition() } 11 | } 12 | 13 | def seatYourself(th, pref): 14 | acquire(?th->mutex) 15 | while th->tables[pref] >= 2: 16 | wait(?th->seating[pref], ?th->mutex) 17 | th->tables[pref] += 1 18 | notify(?th->drinking[pref]) 19 | release(?th->mutex) 20 | 21 | def drinkTea(th, pref): 22 | acquire(?th->mutex) 23 | while th->tables[pref] < 2: 24 | wait(?th->drinking[pref], ?th->mutex) 25 | release(?th->mutex) 26 | 27 | def leave(th, pref): 28 | acquire(?th->mutex) 29 | th->tables[pref] = (th->tables[pref] + 1) % 4 30 | if th->tables[pref] == 0: 31 | notifyAll(?th->seating[pref]) 32 | release(?th->mutex) 33 | 34 | def student(th, pref): 35 | seatYourself(th, pref) 36 | drinkTea(th, pref) 37 | leave(th, pref) 38 | 39 | teahouse = Teahouse() 40 | 41 | for i in {1 .. NPAIRS}: 42 | let pref = choose({ .green, .black }): 43 | spawn student(?teahouse, pref) 44 | spawn student(?teahouse, pref) 45 | -------------------------------------------------------------------------------- /test/test.hny: -------------------------------------------------------------------------------- 1 | def v(x): 2 | result = x 3 | 4 | assert (v(1) + v(2) + v(3)) == 6, 1 5 | assert (v([1,]) + v([2,]) + v([3,]) + v([])) == [1, 2, 3], 2 6 | assert (v(2) * v(3)) == 6, 3 7 | assert (v([1,]) * 3) == [1, 1, 1], (4, (v([1,]) * 3)) 8 | assert (v(1) | v(2) | v(3)) == 3, 5 9 | assert (v({1, 2}) | v({2, 3}) | v({})) == {1, 2, 3}, 6 10 | assert (v({1, 2, 3}) & v({2, 3, 4}) & v({3, 4, 5})) == {3}, 7 11 | assert (v(1) - v(2)) == -1, 8 12 | assert (v({1, 2, 4}) - v({0, 2, 3})) == {1, 4}, 9 13 | assert v(2) in v({ 1, 2, 3 }), 10 14 | assert v(0) not in v({ 1, 2, 3 }), 11 15 | assert (v(3) // v(2)) == 1 16 | assert abs(v(1)) == 1 17 | assert abs(v(0)) == 0 18 | assert abs(v(-1)) == 1 19 | assert ~v(0) == -1 20 | assert ~v(1) == -2 21 | assert ~v(-1) == 0 22 | assert (v(3) ** v(2)) == 9 23 | assert (v(-2) ** v(3)) == -8 24 | assert (v(2) << v(3)) == 16 25 | assert (v(16) >> v(1)) == 8 26 | assert (v({1, 2, 3}) ^ v({2, 3, 4}) ^ v({3, 4, 5})) == {1,3,5} 27 | assert v(inf) > v(1) 28 | assert -v(inf) < v(-1) 29 | assert v(-inf) < v(-1), v(-inf) 30 | assert v(True) in { True, (1,), (2,) }, 12 31 | assert v(False) not in { 1 }, 13 32 | assert { v(1):2, 1:1, 1:3, 1:1 } == { 1:3 } 33 | assert ([v(1), 2, 3] | [2, 1]) == [2, 2, 3] 34 | assert ([v(1), 2, 3] & [2, 1]) == [1, 1] 35 | assert { i%2 for i in { 1, 2, 3 } } == { 0, 1 } 36 | assert { v(1), 2, 3 } == { 3, 2, 1 } 37 | assert { v(1), 2, 1 } == { 2, 1 } 38 | 39 | # x = v(3) + v(False) 40 | # x = all v([3, 4]) 41 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harmonylang/harmony/d06ac438fe7bd79539915cb67819728be5b7d803/tests/__init__.py -------------------------------------------------------------------------------- /tests/resources/h2py/addr_1.hny: -------------------------------------------------------------------------------- 1 | x = {.a: 5} 2 | y = ?x 3 | z = ?y->a 4 | !z = 7 5 | assert x.a == 7 -------------------------------------------------------------------------------- /tests/resources/h2py/addr_1.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | x = H({'a': 5}) 3 | y = HAddr('x') 4 | z = HAddr((y, 'a')) 5 | z.assign(7) 6 | assert x('a') == 7 -------------------------------------------------------------------------------- /tests/resources/h2py/addr_2.hny: -------------------------------------------------------------------------------- 1 | x = {.a: 5, .b: {.c: 7}} 2 | y = ?x 3 | z = ?(!y)[.a] 4 | y = ?x[.b] 5 | z = ?(!y)[.c] 6 | y = ?x[.b][.c] -------------------------------------------------------------------------------- /tests/resources/h2py/addr_2.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | x = H({'a': 5, 'b': H({'c': 7})}) 3 | y = HAddr('x') 4 | z = HAddr((y, 'a')) 5 | y = HAddr(('x', 'b')) 6 | z = HAddr((y, 'c')) 7 | y = HAddr((('x', 'b'), 'c')) -------------------------------------------------------------------------------- /tests/resources/h2py/addr_3.hny: -------------------------------------------------------------------------------- 1 | def f(x): 2 | x->y->z = 7 3 | result = x->y->w 4 | 5 | a = {.w: 5, .z: 10} 6 | x = {.y: ?a} 7 | assert f(?x) == 5 8 | assert a.z == 7 -------------------------------------------------------------------------------- /tests/resources/h2py/addr_3.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | 3 | def f(x): 4 | result = None 5 | x.get()('y').get()['z'] = 7 6 | result = x.get()('y').get()('w') 7 | return result 8 | a = H({'w': 5, 'z': 10}) 9 | x = H({'y': HAddr('a')}) 10 | assert f(HAddr('x')) == 5 11 | assert a('z') == 7 -------------------------------------------------------------------------------- /tests/resources/h2py/apply_1.hny: -------------------------------------------------------------------------------- 1 | def f(): 2 | print("Hi") 3 | 4 | f() -------------------------------------------------------------------------------- /tests/resources/h2py/apply_1.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | 3 | def f(): 4 | result = None 5 | print('Hi') 6 | return result 7 | f() -------------------------------------------------------------------------------- /tests/resources/h2py/binops.hny: -------------------------------------------------------------------------------- 1 | x = y = None 2 | z = x and y 3 | z = x or y 4 | z = x => y 5 | z = x & y 6 | z = x | y 7 | z = x ^ y 8 | z = x - y 9 | z = x + y 10 | z = x * y 11 | z = x // y 12 | z = x / y 13 | z = x % y 14 | z = x mod y 15 | z = x ** y 16 | z = x << y 17 | z = x >> y 18 | z = x == y 19 | z = x != y 20 | z = x < y 21 | z = x <= y 22 | z = x > y 23 | z = x >= y -------------------------------------------------------------------------------- /tests/resources/h2py/binops.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | x = y = None 3 | z = x and y 4 | z = x or y 5 | z = not x or y 6 | z = x & y 7 | z = x | y 8 | z = x ^ y 9 | z = x - y 10 | z = x + y 11 | z = x * y 12 | z = x // y 13 | z = x // y 14 | z = x % y 15 | z = x % y 16 | z = x ** y 17 | z = x << y 18 | z = x >> y 19 | z = x == y 20 | z = x != y 21 | z = x < y 22 | z = x <= y 23 | z = x > y 24 | z = x >= y -------------------------------------------------------------------------------- /tests/resources/h2py/choose_1.hny: -------------------------------------------------------------------------------- 1 | x = choose({.y: 5, .z: 7}) 2 | assert (x == 5) or (x == 7) -------------------------------------------------------------------------------- /tests/resources/h2py/choose_1.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | x = choose(H({'y': 5, 'z': 7})) 3 | assert x == 5 or x == 7 -------------------------------------------------------------------------------- /tests/resources/h2py/dict.hny: -------------------------------------------------------------------------------- 1 | x = { .y: 5, .z: 10 } 2 | print(x.y + x.z) -------------------------------------------------------------------------------- /tests/resources/h2py/dict.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | x = H({'y': 5, 'z': 10}) 3 | print(x('y') + x('z')) -------------------------------------------------------------------------------- /tests/resources/h2py/dict_assign.hny: -------------------------------------------------------------------------------- 1 | x = { .y: 5, .z: 10 } 2 | x.y = 7 3 | print(x.y + x.z) -------------------------------------------------------------------------------- /tests/resources/h2py/dict_assign.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | x = H({'y': 5, 'z': 10}) 3 | x['y'] = 7 4 | print(x('y') + x('z')) -------------------------------------------------------------------------------- /tests/resources/h2py/func_1.hny: -------------------------------------------------------------------------------- 1 | def f(x): 2 | print(x) 3 | f(5) -------------------------------------------------------------------------------- /tests/resources/h2py/func_1.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | 3 | def f(x): 4 | result = None 5 | print(x) 6 | return result 7 | f(5) -------------------------------------------------------------------------------- /tests/resources/h2py/h2py_name_conflict.hny: -------------------------------------------------------------------------------- 1 | H = 5 2 | P = 6 3 | HValue = 7 4 | print((H + P) + HValue) -------------------------------------------------------------------------------- /tests/resources/h2py/h2py_name_conflict.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | _H = 5 3 | _P = 6 4 | _HValue = 7 5 | print(_H + _P + _HValue) -------------------------------------------------------------------------------- /tests/resources/h2py/h2py_name_conflict_2.hny: -------------------------------------------------------------------------------- 1 | def f(): 2 | _H = 10 3 | H = 20 4 | assert (H + _H) == 30 5 | -------------------------------------------------------------------------------- /tests/resources/h2py/h2py_name_conflict_2.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | 3 | def f(): 4 | result = None 5 | _H = 10 6 | _H = 20 7 | assert _H + _H == 30 8 | return result 9 | -------------------------------------------------------------------------------- /tests/resources/h2py/h2py_runtime: -------------------------------------------------------------------------------- 1 | ../../../harmony_model_checker/h2py/h2py_runtime -------------------------------------------------------------------------------- /tests/resources/h2py/if_1.hny: -------------------------------------------------------------------------------- 1 | def f(x): 2 | result = x 3 | 4 | if f(True): 5 | print("True") -------------------------------------------------------------------------------- /tests/resources/h2py/if_1.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | 3 | def f(x): 4 | result = None 5 | result = x 6 | return result 7 | if f(True): 8 | print('True') -------------------------------------------------------------------------------- /tests/resources/h2py/if_elif_else.hny: -------------------------------------------------------------------------------- 1 | x = True 2 | y = False 3 | if x: 4 | print('True') 5 | elif y: 6 | print('False, True') 7 | else: 8 | print('False, False') -------------------------------------------------------------------------------- /tests/resources/h2py/if_elif_else.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | x = True 3 | y = False 4 | if x: 5 | print('True') 6 | elif y: 7 | print('False, True') 8 | else: 9 | print('False, False') -------------------------------------------------------------------------------- /tests/resources/h2py/if_else.hny: -------------------------------------------------------------------------------- 1 | x = True 2 | if x: 3 | print('True') 4 | else: 5 | print('False') -------------------------------------------------------------------------------- /tests/resources/h2py/if_else.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | x = True 3 | if x: 4 | print('True') 5 | else: 6 | print('False') -------------------------------------------------------------------------------- /tests/resources/h2py/imports.hny: -------------------------------------------------------------------------------- 1 | import synch 2 | import a, b 3 | from synch import Lock, acquire, release 4 | from synch import * -------------------------------------------------------------------------------- /tests/resources/h2py/imports.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | import synch 3 | import a, b 4 | from synch import Lock, acquire, release 5 | from synch import * -------------------------------------------------------------------------------- /tests/resources/h2py/local_assign.hny: -------------------------------------------------------------------------------- 1 | def f(x, y): 2 | let z = x + y: 3 | print(z) 4 | f(3, 4) -------------------------------------------------------------------------------- /tests/resources/h2py/local_assign.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | 3 | def f(x, y): 4 | result = None 5 | z = x + y 6 | print(z) 7 | z = None 8 | return result 9 | f(3, 4) -------------------------------------------------------------------------------- /tests/resources/h2py/local_assign_assert.hny: -------------------------------------------------------------------------------- 1 | def f(x, y): 2 | let z = x + y: 3 | print(x + y) 4 | assert z == 5 5 | f(2, 3) -------------------------------------------------------------------------------- /tests/resources/h2py/local_assign_assert.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | 3 | def f(x, y): 4 | result = None 5 | z = x + y 6 | print(x + y) 7 | assert z == 5 8 | z = None 9 | return result 10 | f(2, 3) -------------------------------------------------------------------------------- /tests/resources/h2py/print.hny: -------------------------------------------------------------------------------- 1 | print(5) -------------------------------------------------------------------------------- /tests/resources/h2py/print.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | print(5) -------------------------------------------------------------------------------- /tests/resources/h2py/ptr_apply_1.hny: -------------------------------------------------------------------------------- 1 | def f(x): 2 | result = x->y 3 | x = {.y: 5} 4 | assert f(?x) == 5 -------------------------------------------------------------------------------- /tests/resources/h2py/ptr_apply_1.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | 3 | def f(x): 4 | result = None 5 | result = x.get()('y') 6 | return result 7 | x = H({'y': 5}) 8 | assert f(HAddr('x')) == 5 -------------------------------------------------------------------------------- /tests/resources/h2py/ptr_assign_1.hny: -------------------------------------------------------------------------------- 1 | def f(x_ptr): 2 | !x_ptr = 5 3 | x = 3 4 | f(?x) 5 | print(x) -------------------------------------------------------------------------------- /tests/resources/h2py/ptr_assign_1.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | 3 | def f(x_ptr): 4 | result = None 5 | x_ptr.assign(5) 6 | return result 7 | x = 3 8 | f(HAddr('x')) 9 | print(x) -------------------------------------------------------------------------------- /tests/resources/h2py/ptr_assign_2.hny: -------------------------------------------------------------------------------- 1 | def f(x_y_ptr): 2 | !x_y_ptr = 5 3 | x = { .y: 3 } 4 | f(?x.y) 5 | print(x.y) -------------------------------------------------------------------------------- /tests/resources/h2py/ptr_assign_2.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | 3 | def f(x_y_ptr): 4 | result = None 5 | x_y_ptr.assign(5) 6 | return result 7 | x = H({'y': 3}) 8 | f(HAddr(('x', 'y'))) 9 | print(x('y')) -------------------------------------------------------------------------------- /tests/resources/h2py/ptr_assign_3.hny: -------------------------------------------------------------------------------- 1 | def f(x, z): 2 | x->y = z 3 | d = {.y: 5} 4 | f(?d, 7) 5 | assert d.y == 7 -------------------------------------------------------------------------------- /tests/resources/h2py/ptr_assign_3.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | 3 | def f(x, z): 4 | result = None 5 | x.get()['y'] = z 6 | return result 7 | d = H({'y': 5}) 8 | f(HAddr('d'), 7) 9 | assert d('y') == 7 -------------------------------------------------------------------------------- /tests/resources/h2py/ptr_assign_4.hny: -------------------------------------------------------------------------------- 1 | memory = {0: None, 1: None, 2: None} 2 | idx = 0 # index of the next free slot in memory 3 | 4 | def malloc(): 5 | result = ?memory[idx] 6 | idx = idx + 1; 7 | 8 | def malloc_init(x): 9 | result = malloc() 10 | !result = x 11 | 12 | x = malloc_init('Hello!') 13 | assert !x == 'Hello!' 14 | 15 | y = malloc_init('Goodbye!') 16 | assert !y == 'Goodbye!' 17 | -------------------------------------------------------------------------------- /tests/resources/h2py/ptr_assign_4.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | memory = H({0: None, 1: None, 2: None}) 3 | idx = 0 4 | 5 | def malloc(): 6 | result = None 7 | result = HAddr(('memory', idx)) 8 | idx = idx + 1 9 | return result 10 | 11 | def malloc_init(x): 12 | result = None 13 | result = malloc() 14 | result.assign(x) 15 | return result 16 | x = malloc_init('Hello!') 17 | assert x.get() == 'Hello!' 18 | y = malloc_init('Goodbye!') 19 | assert y.get() == 'Goodbye!' 20 | -------------------------------------------------------------------------------- /tests/resources/h2py/tuple_assign.hny: -------------------------------------------------------------------------------- 1 | x, y = 3, 4 2 | print(x + y) -------------------------------------------------------------------------------- /tests/resources/h2py/tuple_assign.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | (x, y) = (3, 4) 3 | print(x + y) -------------------------------------------------------------------------------- /tests/resources/h2py/var_1.hny: -------------------------------------------------------------------------------- 1 | def f(x): 2 | var y = x 3 | print(y) 4 | f(5) -------------------------------------------------------------------------------- /tests/resources/h2py/var_1.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | 3 | def f(x): 4 | result = None 5 | y = x 6 | print(y) 7 | return result 8 | f(5) -------------------------------------------------------------------------------- /tests/resources/h2py/var_2.hny: -------------------------------------------------------------------------------- 1 | var (x, y) = (5, 7) 2 | print(x, y) -------------------------------------------------------------------------------- /tests/resources/h2py/var_2.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | (x, y) = (5, 7) 3 | print((x, y)) -------------------------------------------------------------------------------- /tests/resources/h2py/while_1.hny: -------------------------------------------------------------------------------- 1 | x = 0 2 | while x < 10: 3 | print(x) 4 | x = x + 1 -------------------------------------------------------------------------------- /tests/resources/h2py/while_1.py: -------------------------------------------------------------------------------- 1 | from h2py_runtime import * 2 | x = 0 3 | while x < 10: 4 | print(x) 5 | x = x + 1 -------------------------------------------------------------------------------- /webinstall: -------------------------------------------------------------------------------- 1 | mkdir -p output 2 | make 3 | 4 | dir=/research/harmony 5 | mkdir -p $dir/code 6 | mkdir -p $dir/modules 7 | mkdir -p $dir/python 8 | mkdir -p $dir/output 9 | mkdir -p $dir/distributions 10 | 11 | cd distributions 12 | sh makedistr 13 | cd .. 14 | 15 | python3 src/archive/implode.py manifest > archive.xml 16 | cp archive.xml $dir 17 | python3 src/archive/implode.py /dev/null > $dir/version.xml 18 | 19 | ./harmony --noweb code/Up.hny 20 | mv code/Up.htm output/Up.html 21 | ./harmony --noweb code/naiveLock.hny 22 | mv code/naiveLock.htm output/naiveLock.html 23 | ./harmony --noweb code/naiveFlags.hny 24 | mv code/naiveFlags.htm output/naiveFlags.html 25 | cp output/*.html $dir/output 26 | 27 | cp harmony harmony.py $dir 28 | (cd book; make all) 29 | cp book/paper.pdf $dir/book.pdf 30 | cp HarmonyOnWindows.pdf $dir 31 | 32 | cp code/*.hny $dir/code 33 | cp modules/*.hny $dir/modules 34 | cp python/*.py $dir/python 35 | cp distributions/*.zip $dir/distributions 36 | 37 | zip -r $dir/sources.zip code modules python 38 | --------------------------------------------------------------------------------