--- /dev/null
+#define rwoff1 (write_off - read_off >= 0)
+#define rwoff2 (write_off - read_off < HALF_UCHAR)
+
+#define wcsum1 (write_off - _commit_sum >= 0)
+#define wcsum2 (write_off - _commit_sum < HALF_UCHAR)
+
+#define buffer_large_enough (NUMPROCS + NUMSWITCH <= BUFSIZE)
+#define have_events_lost (events_lost != 0)
--- /dev/null
+;; Display
+(set-default-font "6x13")
+;;(standard-display-european t) ; affichage des caracte`res iso-latin
+(require 'iso-insert) ; pour l'insertion de caracte`res
+
+
+;; Auto font lock mode
+(if (string-match "XEmacs" emacs-version 0)
+ (progn
+ (require 'font-lock)
+ (setq-default font-lock-auto-fontify t))
+ (global-font-lock-mode t)
+)
+
+
+;; Custom variables and keys
+(menu-bar-mode 0)
+(tool-bar-mode 0)
+(setq-default auto-save-mode nil)
+(global-set-key "\M-g" 'goto-line)
+(setq-default indent-tabs-mode nil)
+(setq c-basic-offset 8)
+(global-set-key [delete] 'delete-char) ; [Del]
+(global-set-key [home] 'beginning-of-line) ; [Home]
+(global-set-key [end] 'end-of-line) ; [End]
+
+
+;; Promela mode
+(autoload 'promela-mode "promela-mode" "PROMELA mode" nil t)
+(setq auto-mode-alist
+ (append
+ (list (cons "\\.promela$" 'promela-mode)
+ (cons "\\.spin$" 'promela-mode)
+ (cons "\\.pml$" 'promela-mode)
+ )
+ auto-mode-alist))
+
+;; Mousewheel
+(defun sd-mousewheel-scroll-up (event)
+ "Scroll window under mouse up by five lines."
+ (interactive "e")
+ (let ((current-window (selected-window)))
+ (unwind-protect
+ (progn
+ (select-window (posn-window (event-start event)))
+ (scroll-up 5))
+ (select-window current-window))))
+
+(defun sd-mousewheel-scroll-down (event)
+ "Scroll window under mouse down by five lines."
+ (interactive "e")
+ (let ((current-window (selected-window)))
+ (unwind-protect
+ (progn
+ (select-window (posn-window (event-start event)))
+ (scroll-down 5))
+ (select-window current-window))))
+
+(global-set-key (kbd "<mouse-5>") 'sd-mousewheel-scroll-up)
+(global-set-key (kbd "<mouse-4>") 'sd-mousewheel-scroll-down)
+
--- /dev/null
+Exit-Status 0
+warning: for p.o. reduction to be valid the never claim must be stutter-invariant
+(never claims generated from LTL formulae are stutter-invariant)
+depth 0: Claim reached state 5 (line 301)
+Depth= 198 States= 1e+06 Transitions= 2.9e+06 Memory= 79.649 t= 7.71 R= 1e+05
+
+(Spin Version 5.1.6 -- 9 May 2008)
+ + Partial Order Reduction
+
+Full statespace search for:
+ never claim +
+ assertion violations + (if within scope of claim)
+ acceptance cycles + (fairness disabled)
+ invalid end states - (disabled by never claim)
+
+State-vector 100 byte, depth reached 200, errors: 0
+ 1295413 states, stored
+ 2540827 states, matched
+ 3836240 transitions (= stored+matched)
+ 4818193 atomic steps
+hash conflicts: 1991528 (resolved)
+
+Stats on memory usage (in Megabytes):
+ 143.307 equivalent memory usage for states (stored*(State-vector + overhead))
+ 100.700 actual memory usage for states (compression: 70.27%)
+ state-vector as stored = 66 byte + 16 byte overhead
+ 2.000 memory used for hash table (-w19)
+ 0.305 memory used for DFS stack (-m10000)
+ 102.891 total actual memory usage
+
+unreached in proctype switcher
+ (0 of 31 states)
+unreached in proctype tracer
+ (0 of 51 states)
+unreached in proctype reader
+ (0 of 29 states)
+unreached in proctype cleaner
+ (0 of 9 states)
+unreached in proctype :init:
+ (0 of 43 states)
+unreached in proctype :never:
+ line 306, "pan.___", state 8, "-end-"
+ (1 of 8 states)
+
+pan: elapsed time 10.3 seconds
+pan: rate 125768.25 states/second
+pan: avg transition delay 2.6849e-06 usec
+Exit-Status 0
+warning: for p.o. reduction to be valid the never claim must be stutter-invariant
+(never claims generated from LTL formulae are stutter-invariant)
+depth 0: Claim reached state 5 (line 301)
+Depth= 198 States= 1e+06 Transitions= 2.9e+06 Memory= 79.649 t= 7.7 R= 1e+05
+
+(Spin Version 5.1.6 -- 9 May 2008)
+ + Partial Order Reduction
+
+Full statespace search for:
+ never claim +
+ assertion violations + (if within scope of claim)
+ acceptance cycles + (fairness disabled)
+ invalid end states - (disabled by never claim)
+
+State-vector 100 byte, depth reached 200, errors: 0
+ 1295413 states, stored
+ 2540827 states, matched
+ 3836240 transitions (= stored+matched)
+ 4818193 atomic steps
+hash conflicts: 1991528 (resolved)
+
+Stats on memory usage (in Megabytes):
+ 143.307 equivalent memory usage for states (stored*(State-vector + overhead))
+ 100.700 actual memory usage for states (compression: 70.27%)
+ state-vector as stored = 66 byte + 16 byte overhead
+ 2.000 memory used for hash table (-w19)
+ 0.305 memory used for DFS stack (-m10000)
+ 102.891 total actual memory usage
+
+unreached in proctype switcher
+ (0 of 31 states)
+unreached in proctype tracer
+ (0 of 51 states)
+unreached in proctype reader
+ (0 of 29 states)
+unreached in proctype cleaner
+ (0 of 9 states)
+unreached in proctype :init:
+ (0 of 43 states)
+unreached in proctype :never:
+ line 306, "pan.___", state 8, "-end-"
+ (1 of 8 states)
+
+pan: elapsed time 10.3 seconds
+pan: rate 125890.48 states/second
+pan: avg transition delay 2.6823e-06 usec
+Exit-Status 0
+warning: for p.o. reduction to be valid the never claim must be stutter-invariant
+(never claims generated from LTL formulae are stutter-invariant)
+depth 0: Claim reached state 3 (line 302)
+depth 25: Claim reached state 7 (line 307)
+pan: acceptance cycle (at depth 167)
+pan: wrote model.spin.trail
+
+(Spin Version 5.1.6 -- 9 May 2008)
+Warning: Search not completed
+ + Partial Order Reduction
+
+Full statespace search for:
+ never claim +
+ assertion violations + (if within scope of claim)
+ acceptance cycles + (fairness disabled)
+ invalid end states - (disabled by never claim)
+
+State-vector 100 byte, depth reached 168, errors: 1
+ 43 states, stored
+ 0 states, matched
+ 43 transitions (= stored+matched)
+ 83 atomic steps
+hash conflicts: 0 (resolved)
+
+Stats on memory usage (in Megabytes):
+ 0.005 equivalent memory usage for states (stored*(State-vector + overhead))
+ 0.277 actual memory usage for states (unsuccessful compression: 5822.98%)
+ state-vector as stored = 6739 byte + 16 byte overhead
+ 2.000 memory used for hash table (-w19)
+ 0.305 memory used for DFS stack (-m10000)
+ 2.501 total actual memory usage
+
+unreached in proctype switcher
+ line 80, "pan.___", state 8, "(1)"
+ line 75, "pan.___", state 9, "(((((new_off-read_off)>4)&&((new_off-read_off)<(255/2)))||(size==(4/2))))"
+ line 75, "pan.___", state 9, "else"
+ line 86, "pan.___", state 15, "write_off = new_off"
+ line 83, "pan.___", state 18, "((prev_off!=write_off))"
+ line 83, "pan.___", state 18, "else"
+ line 96, "pan.___", state 21, "commit_count[((prev_off%4)/(4/2))] = tmp_commit"
+ line 102, "pan.___", state 25, "(1)"
+ line 97, "pan.___", state 26, "((((((prev_off/4)*4)/2)+(4/2))-tmp_commit))"
+ line 97, "pan.___", state 26, "else"
+ line 90, "pan.___", state 29, "tmp_commit = (commit_count[((prev_off%4)/(4/2))]+size)"
+ (8 of 31 states)
+unreached in proctype tracer
+ line 153, "pan.___", state 34, "((i<size))"
+ line 153, "pan.___", state 34, "((i>=size))"
+ line 151, "pan.___", state 46, "i = 0"
+ line 176, "pan.___", state 48, "events_lost = (events_lost+1)"
+ (3 of 51 states)
+unreached in proctype reader
+ line 201, "pan.___", state 12, "i = 0"
+ line 215, "pan.___", state 23, "i = 0"
+ (2 of 29 states)
+unreached in proctype cleaner
+ (0 of 9 states)
+unreached in proctype :init:
+ line 253, "pan.___", state 7, "((i<2))"
+ line 253, "pan.___", state 7, "((i>=2))"
+ line 272, "pan.___", state 29, "((i<4))"
+ line 272, "pan.___", state 29, "((i>=4))"
+ (2 of 43 states)
+unreached in proctype :never:
+ line 306, "pan.___", state 7, "(!((events_lost!=0)))"
+ line 309, "pan.___", state 9, "-end-"
+ (2 of 9 states)
+
+pan: elapsed time 0 seconds
+Exit-Status 0
+warning: for p.o. reduction to be valid the never claim must be stutter-invariant
+(never claims generated from LTL formulae are stutter-invariant)
+depth 0: Claim reached state 5 (line 301)
+depth 0: Claim reached state 5 (line 302)
+
+(Spin Version 5.1.6 -- 9 May 2008)
+ + Partial Order Reduction
+
+Full statespace search for:
+ never claim +
+ assertion violations + (if within scope of claim)
+ acceptance cycles + (fairness disabled)
+ invalid end states - (disabled by never claim)
+
+State-vector 32 byte, depth reached 0, errors: 0
+ 1 states, stored
+ 0 states, matched
+ 1 transitions (= stored+matched)
+ 0 atomic steps
+hash conflicts: 0 (resolved)
+
+Stats on memory usage (in Megabytes):
+ 0.000 equivalent memory usage for states (stored*(State-vector + overhead))
+ 0.277 actual memory usage for states (unsuccessful compression: 604850.00%)
+ state-vector as stored = 290312 byte + 16 byte overhead
+ 2.000 memory used for hash table (-w19)
+ 0.305 memory used for DFS stack (-m10000)
+ 2.501 total actual memory usage
+
+unreached in proctype switcher
+ line 74, "pan.___", state 3, "new_off = (prev_off+size)"
+ line 80, "pan.___", state 8, "(1)"
+ line 75, "pan.___", state 9, "(((((new_off-read_off)>4)&&((new_off-read_off)<(255/2)))||(size==(4/2))))"
+ line 75, "pan.___", state 9, "else"
+ line 71, "pan.___", state 11, "prev_off = write_off"
+ line 86, "pan.___", state 15, "write_off = new_off"
+ line 83, "pan.___", state 18, "((prev_off!=write_off))"
+ line 83, "pan.___", state 18, "else"
+ line 96, "pan.___", state 21, "commit_count[((prev_off%4)/(4/2))] = tmp_commit"
+ line 102, "pan.___", state 25, "(1)"
+ line 97, "pan.___", state 26, "((((((prev_off/4)*4)/2)+(4/2))-tmp_commit))"
+ line 97, "pan.___", state 26, "else"
+ line 90, "pan.___", state 29, "tmp_commit = (commit_count[((prev_off%4)/(4/2))]+size)"
+ line 108, "pan.___", state 31, "-end-"
+ (11 of 31 states)
+unreached in proctype tracer
+ line 122, "pan.___", state 3, "prev_off = write_off"
+ line 130, "pan.___", state 7, "(1)"
+ line 126, "pan.___", state 10, "((((new_off-read_off)>4)&&((new_off-read_off)<(255/2))))"
+ line 126, "pan.___", state 10, "else"
+ line 136, "pan.___", state 14, "write_off = new_off"
+ line 142, "pan.___", state 20, "buffer_use[((prev_off+i)%4)] = 1"
+ line 143, "pan.___", state 21, "i = (i+1)"
+ line 133, "pan.___", state 27, "((prev_off!=write_off))"
+ line 133, "pan.___", state 27, "else"
+ line 156, "pan.___", state 31, "i = (i+1)"
+ line 153, "pan.___", state 34, "((i<size))"
+ line 153, "pan.___", state 34, "((i>=size))"
+ line 164, "pan.___", state 39, "commit_count[((prev_off%4)/(4/2))] = tmp_commit"
+ line 170, "pan.___", state 43, "(1)"
+ line 165, "pan.___", state 44, "((((((prev_off/4)*4)/2)+(4/2))-tmp_commit))"
+ line 165, "pan.___", state 44, "else"
+ line 151, "pan.___", state 46, "i = 0"
+ line 176, "pan.___", state 48, "events_lost = (events_lost+1)"
+ line 178, "pan.___", state 49, "refcount = (refcount-1)"
+ line 173, "pan.___", state 50, "goto end"
+ line 180, "pan.___", state 51, "-end-"
+ (17 of 51 states)
+unreached in proctype reader
+ line 206, "pan.___", state 5, "buffer_use[((read_off+i)%4)] = 1"
+ line 207, "pan.___", state 6, "i = (i+1)"
+ line 201, "pan.___", state 12, "i = 0"
+ line 220, "pan.___", state 16, "i = (i+1)"
+ line 223, "pan.___", state 22, "read_off = (read_off+(4/2))"
+ line 215, "pan.___", state 23, "i = 0"
+ line 195, "pan.___", state 26, "((((((write_off/(4/2))-(read_off/(4/2)))>0)&&(((write_off/(4/2))-(read_off/(4/2)))<(255/2)))&&(((commit_count[((read_off%4)/(4/2))]-(4/2))-(((read_off/4)*4)/2))==0)))"
+ line 195, "pan.___", state 26, "((read_off>=(4-events_lost)))"
+ line 227, "pan.___", state 29, "-end-"
+ (8 of 29 states)
+unreached in proctype cleaner
+ line 239, "pan.___", state 3, "(run switcher())"
+ line 236, "pan.___", state 5, "((refcount==0))"
+ line 235, "pan.___", state 8, "((refcount==0))"
+ line 243, "pan.___", state 9, "-end-"
+ (4 of 9 states)
+unreached in proctype :init:
+ line 256, "pan.___", state 4, "i = (i+1)"
+ line 253, "pan.___", state 7, "((i<2))"
+ line 253, "pan.___", state 7, "((i>=2))"
+ line 266, "pan.___", state 14, "i = (i+1)"
+ line 263, "pan.___", state 17, "((i<4))"
+ line 263, "pan.___", state 17, "((i>=4))"
+ line 269, "pan.___", state 20, "(run reader())"
+ line 270, "pan.___", state 21, "(run cleaner())"
+ line 275, "pan.___", state 25, "(run tracer())"
+ line 272, "pan.___", state 29, "((i<4))"
+ line 272, "pan.___", state 29, "((i>=4))"
+ line 283, "pan.___", state 35, "(run switcher())"
+ line 288, "pan.___", state 43, "-end-"
+ (10 of 43 states)
+unreached in proctype :never:
+ line 305, "pan.___", state 11, "((events_lost!=0))"
+ line 305, "pan.___", state 11, "(1)"
+ line 311, "pan.___", state 14, "-end-"
+ (2 of 14 states)
+
+pan: elapsed time 0 seconds
--- /dev/null
+model_03.spin
\ No newline at end of file
--- /dev/null
+-2:5:-2
+-4:-4:-4
+1:0:163
+2:1:120
+3:1:121
+4:1:121
+5:1:124
+6:1:131
+7:1:131
+8:1:131
+9:1:131
+10:1:134
+11:1:139
+12:1:140
+13:1:142
+14:1:144
+15:1:142
+16:1:144
+17:1:142
+18:1:144
+19:1:142
+20:1:144
+21:1:146
+22:1:152
+23:1:154
+24:1:156
+25:1:160
+26:0:167
+27:8:0
+28:8:3
+29:0:167
+30:8:29
+31:0:167
+32:8:30
+33:0:167
+34:7:31
+35:0:167
+36:7:36
+37:7:37
+38:0:167
+39:7:43
+40:7:44
+41:7:48
+42:7:52
+43:7:56
+44:0:167
+45:7:58
+46:7:59
+47:7:62
+48:7:70
+49:0:167
+50:7:77
+51:7:79
+52:0:167
+53:7:81
+54:0:167
+55:6:31
+56:0:167
+57:6:36
+58:6:37
+59:0:167
+60:6:43
+61:6:44
+62:6:48
+63:6:52
+64:6:56
+65:0:167
+66:6:58
+67:6:59
+68:6:62
+69:6:72
+70:6:73
+71:0:167
+72:6:77
+73:6:79
+74:0:167
+75:6:81
+76:0:167
+77:5:31
+78:0:167
+79:5:36
+80:5:37
+81:0:167
+82:5:43
+83:5:44
+84:5:48
+85:5:52
+86:5:56
+87:0:167
+88:5:58
+89:5:59
+90:5:62
+91:5:70
+92:0:167
+93:5:77
+94:5:79
+95:0:167
+96:5:81
+97:0:167
+98:4:31
+99:0:167
+100:4:36
+101:4:37
+102:0:167
+103:4:43
+104:4:44
+105:4:48
+106:4:52
+107:4:56
+108:0:167
+109:4:58
+110:4:59
+111:4:62
+112:4:72
+113:4:73
+114:0:167
+115:4:77
+116:4:79
+117:0:167
+118:4:81
+119:0:167
+120:3:111
+121:3:113
+122:3:117
+123:0:167
+124:4:0
+125:4:3
+126:0:167
+127:4:29
+128:0:167
+129:4:30
+130:0:167
+131:3:119
+132:0:167
+133:2:82
+134:0:167
+135:2:83
+136:2:84
+137:2:84
+138:2:88
+139:2:92
+140:0:167
+141:2:94
+142:2:95
+143:2:95
+144:2:98
+145:2:102
+146:2:103
+147:0:167
+148:2:82
+149:0:167
+150:2:83
+151:2:84
+152:2:84
+153:2:88
+154:2:92
+155:0:167
+156:2:94
+157:2:95
+158:2:95
+159:2:98
+160:2:102
+161:2:103
+162:0:167
+163:2:105
+164:0:167
+165:2:110
+166:0:167
+167:1:162
+-1:-1:-1
+168:0:167
+169:0:167
--- /dev/null
+/* LTTng ltt-tracer.c atomic lockless buffering scheme Promela model v2
+ * Created for the Spin validator.
+ * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ * October 2008
+
+ * TODO : create test cases that will generate an overflow on the offset and
+ * counter type. Counter types smaller than a byte should be used.
+
+ * Promela only has unsigned char, no signed char.
+ * Because detection of difference < 0 depends on a signed type, but we want
+ * compactness, check also for the values being higher than half of the unsigned
+ * char range (and consider them negative). The model, by design, does not use
+ * offsets or counts higher than 127 because we would then have to use a larger
+ * type (short or int).
+ */
+#define HALF_UCHAR (255/2)
+
+/* NUMPROCS 4 : causes event loss with some reader timings.
+ * e.g. 3 events, 1 switch, 1 event (lost, buffer full), read 1 subbuffer
+ */
+#define NUMPROCS 4
+
+/* NUMPROCS 3 : does not cause event loss because buffers are big enough.
+ * #define NUMPROCS 3
+ * e.g. 3 events, 1 switch, read 1 subbuffer
+ */
+
+#define NUMSWITCH 1
+#define BUFSIZE 4
+#define NR_SUBBUFS 2
+#define SUBBUF_SIZE (BUFSIZE / NR_SUBBUFS)
+
+/* Writer counters
+*/
+byte write_off = 0;
+byte commit_count[NR_SUBBUFS];
+
+/* Reader counters
+*/
+byte read_off = 0;
+
+byte events_lost = 0;
+byte refcount = 0;
+
+bool deliver = 0;
+
+/* buffer slot in-use bit. Detects racy use (more than a single process
+ * accessing a slot at any given step).
+ */
+bool buffer_use[BUFSIZE];
+
+/* Proceed to a sub-subber switch is needed.
+ * Used in a periodical timer interrupt to fill and ship the current subbuffer
+ * to the reader so we can guarantee a steady flow. If a subbuffer is
+ * completely empty, do not switch.
+ * Also used as "finalize" operation to complete the last subbuffer after
+ * all writers have finished so the last subbuffer can be read by the reader.
+ */
+proctype switcher()
+{
+ byte prev_off, new_off, tmp_commit;
+ byte size;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ size = SUBBUF_SIZE - (prev_off % SUBBUF_SIZE);
+ new_off = prev_off + size;
+ if
+ :: (new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR)
+ || size == SUBBUF_SIZE ->
+ refcount = refcount - 1;
+ goto not_needed;
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ }
+
+ atomic {
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ refcount = refcount - 1;
+ }
+not_needed:
+ skip;
+}
+
+/* tracer
+ * Writes 1 byte of information in the buffer at the current
+ * "write_off" position and then increment the commit_count of the sub-buffer
+ * the information has been written to.
+ */
+proctype tracer()
+{
+ byte size = 1;
+ byte prev_off, new_off, tmp_commit;
+ byte i, j;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ new_off = prev_off + size;
+ }
+ atomic {
+ if
+ :: new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR ->
+ goto lost
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ i = 0;
+ do
+ :: i < size ->
+ assert(buffer_use[(prev_off + i) % BUFSIZE] == 0);
+ buffer_use[(prev_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= size -> break
+ od;
+ }
+
+ /* writing to buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < size ->
+ buffer_use[(prev_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= size -> break
+ od;
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ }
+ atomic {
+ goto end;
+lost:
+ events_lost++;
+end:
+ refcount = refcount - 1;
+ }
+}
+
+/* reader
+ * Read the information sub-buffer per sub-buffer when available.
+ *
+ * Reads the information as soon as it is ready, or may be delayed by
+ * an asynchronous delivery. Being modeled as a process insures all cases
+ * (scheduled very quickly or very late, causing event loss) are covered.
+ * Only one reader per buffer (normally ensured by a mutex). This is modeled
+ * by using a single reader process.
+ */
+proctype reader()
+{
+ byte i, j;
+
+ do
+ :: (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) > 0
+ && (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) < HALF_UCHAR
+ && (commit_count[(read_off % BUFSIZE) / SUBBUF_SIZE]
+ - SUBBUF_SIZE - (((read_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS)
+ == 0) ->
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ assert(buffer_use[(read_off + i) % BUFSIZE] == 0);
+ buffer_use[(read_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ }
+
+ /* reading from buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ buffer_use[(read_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ read_off = read_off + SUBBUF_SIZE;
+ }
+ :: read_off >= (NUMPROCS - events_lost) -> break;
+ od;
+}
+
+/* Waits for all tracer and switcher processes to finish before finalizing
+ * the buffer. Only after that will the reader be allowed to read the
+ * last subbuffer.
+ */
+proctype cleaner()
+{
+ atomic {
+ do
+ :: refcount == 0 ->
+ refcount = refcount + 1;
+ run switcher(); /* Finalize the last sub-buffer so it can be read. */
+ break;
+ od;
+ }
+}
+
+init {
+ byte i = 0;
+ byte j = 0;
+ byte sum = 0;
+ byte commit_sum = 0;
+
+ atomic {
+ i = 0;
+ do
+ :: i < NR_SUBBUFS ->
+ commit_count[i] = 0;
+ i++
+ :: i >= NR_SUBBUFS -> break
+ od;
+ i = 0;
+ do
+ :: i < BUFSIZE ->
+ buffer_use[i] = 0;
+ i++
+ :: i >= BUFSIZE -> break
+ od;
+ run reader();
+ run cleaner();
+ i = 0;
+ do
+ :: i < NUMPROCS ->
+ refcount = refcount + 1;
+ run tracer();
+ i++
+ :: i >= NUMPROCS -> break
+ od;
+ i = 0;
+ do
+ :: i < NUMSWITCH ->
+ refcount = refcount + 1;
+ run switcher();
+ i++
+ :: i >= NUMSWITCH -> break
+ od;
+ }
+
+ /* Assertions.
+ */
+ atomic {
+ /* The writer head must always be superior or equal to the reader head.
+ */
+ assert(write_off - read_off >= 0 && write_off - read_off < HALF_UCHAR);
+ j = 0;
+ commit_sum = 0;
+ do
+ :: j < NR_SUBBUFS ->
+ commit_sum = commit_sum + commit_count[j];
+ /* The commit count of a particular subbuffer must always be higher
+ * or equal to the retrieve_count of this subbuffer.
+ * assert(commit_count[j] - retrieve_count[j] >= 0 &&
+ * commit_count[j] - retrieve_count[j] < HALF_UCHAR);
+ */
+ j++
+ :: j >= NR_SUBBUFS -> break
+ od;
+ /* The sum of all subbuffer commit counts must always be lower or equal
+ * to the writer head, because space must be reserved before it is
+ * written to and then committed.
+ */
+ assert(write_off - commit_sum >= 0 && write_off - commit_sum < HALF_UCHAR);
+
+ /* If we have less writers than the buffer space available, we should
+ * not lose events
+ */
+ assert(NUMPROCS + NUMSWITCH > BUFSIZE || events_lost == 0);
+ }
+}
+
--- /dev/null
+/* LTTng ltt-tracer.c atomic lockless buffering scheme Promela model v2
+ * Created for the Spin validator.
+ * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ * October 2008
+
+ * TODO : create test cases that will generate an overflow on the offset and
+ * counter type. Counter types smaller than a byte should be used.
+
+ * Promela only has unsigned char, no signed char.
+ * Because detection of difference < 0 depends on a signed type, but we want
+ * compactness, check also for the values being higher than half of the unsigned
+ * char range (and consider them negative). The model, by design, does not use
+ * offsets or counts higher than 127 because we would then have to use a larger
+ * type (short or int).
+ */
+#define HALF_UCHAR (255/2)
+
+/* NUMPROCS 4 : causes event loss with some reader timings.
+ * e.g. 3 events, 1 switch, 1 event (lost, buffer full), read 1 subbuffer
+ */
+#define NUMPROCS 4
+
+/* NUMPROCS 3 : does not cause event loss because buffers are big enough.
+ * #define NUMPROCS 3
+ * e.g. 3 events, 1 switch, read 1 subbuffer
+ */
+
+#define NUMSWITCH 1
+#define BUFSIZE 4
+#define NR_SUBBUFS 2
+#define SUBBUF_SIZE (BUFSIZE / NR_SUBBUFS)
+
+/* Writer counters
+*/
+byte write_off = 0;
+byte commit_count[NR_SUBBUFS];
+
+/* Reader counters
+*/
+byte read_off = 0;
+
+byte events_lost = 0;
+byte refcount = 0;
+
+bool deliver = 0;
+
+/* buffer slot in-use bit. Detects racy use (more than a single process
+ * accessing a slot at any given step).
+ */
+bool buffer_use[BUFSIZE];
+
+/* Proceed to a sub-subber switch is needed.
+ * Used in a periodical timer interrupt to fill and ship the current subbuffer
+ * to the reader so we can guarantee a steady flow. If a subbuffer is
+ * completely empty, do not switch.
+ * Also used as "finalize" operation to complete the last subbuffer after
+ * all writers have finished so the last subbuffer can be read by the reader.
+ */
+proctype switcher()
+{
+ byte prev_off, new_off, tmp_commit;
+ byte size;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ size = SUBBUF_SIZE - (prev_off % SUBBUF_SIZE);
+ new_off = prev_off + size;
+ if
+ :: (new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR)
+ || size == SUBBUF_SIZE ->
+ refcount = refcount - 1;
+ goto not_needed;
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ }
+
+ atomic {
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ refcount = refcount - 1;
+ }
+not_needed:
+ skip;
+}
+
+/* tracer
+ * Writes 1 byte of information in the buffer at the current
+ * "write_off" position and then increment the commit_count of the sub-buffer
+ * the information has been written to.
+ */
+proctype tracer()
+{
+ byte size = 1;
+ byte prev_off, new_off, tmp_commit;
+ byte i, j;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ new_off = prev_off + size;
+ }
+ atomic {
+ if
+ :: new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR ->
+ goto lost
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ i = 0;
+ do
+ :: i < size ->
+ assert(buffer_use[(prev_off + i) % BUFSIZE] == 0);
+ buffer_use[(prev_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= size -> break
+ od;
+ }
+
+ /* writing to buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < size ->
+ buffer_use[(prev_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= size -> break
+ od;
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ }
+ atomic {
+ goto end;
+lost:
+ events_lost++;
+end:
+ refcount = refcount - 1;
+ }
+}
+
+/* reader
+ * Read the information sub-buffer per sub-buffer when available.
+ *
+ * Reads the information as soon as it is ready, or may be delayed by
+ * an asynchronous delivery. Being modeled as a process insures all cases
+ * (scheduled very quickly or very late, causing event loss) are covered.
+ * Only one reader per buffer (normally ensured by a mutex). This is modeled
+ * by using a single reader process.
+ */
+proctype reader()
+{
+ byte i, j;
+
+ do
+ :: (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) > 0
+ && (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) < HALF_UCHAR
+ && (commit_count[(read_off % BUFSIZE) / SUBBUF_SIZE]
+ - SUBBUF_SIZE - (((read_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS)
+ == 0) ->
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ assert(buffer_use[(read_off + i) % BUFSIZE] == 0);
+ buffer_use[(read_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ }
+
+ /* reading from buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ buffer_use[(read_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ read_off = read_off + SUBBUF_SIZE;
+ }
+ :: read_off >= (NUMPROCS - events_lost) -> break;
+ od;
+}
+
+/* Waits for all tracer and switcher processes to finish before finalizing
+ * the buffer. Only after that will the reader be allowed to read the
+ * last subbuffer.
+ */
+proctype cleaner()
+{
+ atomic {
+ do
+ :: refcount == 0 ->
+ refcount = refcount + 1;
+ run switcher(); /* Finalize the last sub-buffer so it can be read. */
+ break;
+ od;
+ }
+}
+
+init {
+ byte i = 0;
+ byte j = 0;
+ byte sum = 0;
+ byte commit_sum = 0;
+
+ atomic {
+ i = 0;
+ do
+ :: i < NR_SUBBUFS ->
+ commit_count[i] = 0;
+ i++
+ :: i >= NR_SUBBUFS -> break
+ od;
+ i = 0;
+ do
+ :: i < BUFSIZE ->
+ buffer_use[i] = 0;
+ i++
+ :: i >= BUFSIZE -> break
+ od;
+ run reader();
+ run cleaner();
+ i = 0;
+ do
+ :: i < NUMPROCS ->
+ refcount = refcount + 1;
+ run tracer();
+ i++
+ :: i >= NUMPROCS -> break
+ od;
+ i = 0;
+ do
+ :: i < NUMSWITCH ->
+ refcount = refcount + 1;
+ run switcher();
+ i++
+ :: i >= NUMSWITCH -> break
+ od;
+ }
+
+ /* Assertions.
+ */
+ atomic {
+ /* The writer head must always be superior or equal to the reader head.
+ */
+ assert(write_off - read_off >= 0 && write_off - read_off < HALF_UCHAR);
+ j = 0;
+ commit_sum = 0;
+ do
+ :: j < NR_SUBBUFS ->
+ commit_sum = commit_sum + commit_count[j];
+ j++
+ :: j >= NR_SUBBUFS -> break
+ od;
+ /* The sum of all subbuffer commit counts must always be lower or equal
+ * to the writer head, because space must be reserved before it is
+ * written to and then committed.
+ */
+ assert(write_off - commit_sum >= 0 && write_off - commit_sum < HALF_UCHAR);
+
+ /* If we have less writers than the buffer space available, we should
+ * not loose events
+ */
+ assert(NUMPROCS + NUMSWITCH > BUFSIZE || events_lost == 0);
+ }
+}
+
--- /dev/null
+/* LTTng ltt-tracer.c atomic lockless buffering scheme Promela model v2
+ * Created for the Spin validator.
+ * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ * October 2008
+
+ * TODO : create test cases that will generate an overflow on the offset and
+ * counter type. Counter types smaller than a byte should be used.
+
+ * Promela only has unsigned char, no signed char.
+ * Because detection of difference < 0 depends on a signed type, but we want
+ * compactness, check also for the values being higher than half of the unsigned
+ * char range (and consider them negative). The model, by design, does not use
+ * offsets or counts higher than 127 because we would then have to use a larger
+ * type (short or int).
+ */
+#define HALF_UCHAR (255/2)
+
+/* NUMPROCS 4 : causes event loss with some reader timings.
+ * e.g. 3 events, 1 switch, 1 event (lost, buffer full), read 1 subbuffer
+ */
+#define NUMPROCS 4
+
+/* NUMPROCS 3 : does not cause event loss because buffers are big enough.
+ * #define NUMPROCS 3
+ * e.g. 3 events, 1 switch, read 1 subbuffer
+ */
+
+#define NUMSWITCH 1
+#define BUFSIZE 4
+#define NR_SUBBUFS 2
+#define SUBBUF_SIZE (BUFSIZE / NR_SUBBUFS)
+
+/* Writer counters
+*/
+byte write_off = 0;
+byte commit_count[NR_SUBBUFS];
+
+/* <formal_verif> */
+byte _commit_sum;
+/* </formal_verif> */
+
+/* Reader counters
+*/
+byte read_off = 0;
+
+byte events_lost = 0;
+byte refcount = 0;
+
+bool deliver = 0;
+
+//#ifdef RACE_TEST
+/* buffer slot in-use bit. Detects racy use (more than a single process
+ * accessing a slot at any given step).
+ */
+bool buffer_use[BUFSIZE];
+//#endif
+
+/* Proceed to a sub-subber switch is needed.
+ * Used in a periodical timer interrupt to fill and ship the current subbuffer
+ * to the reader so we can guarantee a steady flow. If a subbuffer is
+ * completely empty, do not switch.
+ * Also used as "finalize" operation to complete the last subbuffer after
+ * all writers have finished so the last subbuffer can be read by the reader.
+ */
+proctype switcher()
+{
+ byte prev_off, new_off, tmp_commit;
+ byte size;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ size = SUBBUF_SIZE - (prev_off % SUBBUF_SIZE);
+ new_off = prev_off + size;
+ if
+ :: (new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR)
+ || size == SUBBUF_SIZE ->
+ refcount = refcount - 1;
+ goto not_needed;
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ }
+
+ atomic {
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ /* <formal_verif> */
+ _commit_sum = _commit_sum - commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE]
+ + tmp_commit;
+ /* </formal_verif> */
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ refcount = refcount - 1;
+ }
+not_needed:
+ skip;
+}
+
+/* tracer
+ * Writes 1 byte of information in the buffer at the current
+ * "write_off" position and then increment the commit_count of the sub-buffer
+ * the information has been written to.
+ */
+proctype tracer()
+{
+ byte size = 1;
+ byte prev_off, new_off, tmp_commit;
+ byte i, j;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ new_off = prev_off + size;
+ }
+ atomic {
+ if
+ :: new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR ->
+ goto lost
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ i = 0;
+ do
+ :: i < size ->
+ assert(buffer_use[(prev_off + i) % BUFSIZE] == 0);
+ buffer_use[(prev_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= size -> break
+ od;
+ }
+
+ /* writing to buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < size ->
+ buffer_use[(prev_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= size -> break
+ od;
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ /* <formal_verif> */
+ _commit_sum = _commit_sum - commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE]
+ + tmp_commit;
+ /* </formal_verif> */
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ }
+ atomic {
+ goto end;
+lost:
+ events_lost++;
+end:
+ refcount = refcount - 1;
+ }
+}
+
+/* reader
+ * Read the information sub-buffer per sub-buffer when available.
+ *
+ * Reads the information as soon as it is ready, or may be delayed by
+ * an asynchronous delivery. Being modeled as a process insures all cases
+ * (scheduled very quickly or very late, causing event loss) are covered.
+ * Only one reader per buffer (normally ensured by a mutex). This is modeled
+ * by using a single reader process.
+ */
+proctype reader()
+{
+ byte i, j;
+
+ do
+ :: (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) > 0
+ && (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) < HALF_UCHAR
+ && (commit_count[(read_off % BUFSIZE) / SUBBUF_SIZE]
+ - SUBBUF_SIZE - (((read_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS)
+ == 0) ->
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ assert(buffer_use[(read_off + i) % BUFSIZE] == 0);
+ buffer_use[(read_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ }
+
+ /* reading from buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ buffer_use[(read_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ read_off = read_off + SUBBUF_SIZE;
+ }
+ :: read_off >= (NUMPROCS - events_lost) -> break;
+ od;
+}
+
+/* Waits for all tracer and switcher processes to finish before finalizing
+ * the buffer. Only after that will the reader be allowed to read the
+ * last subbuffer.
+ */
+proctype cleaner()
+{
+ atomic {
+ do
+ :: refcount == 0 ->
+ refcount = refcount + 1;
+ run switcher(); /* Finalize the last sub-buffer so it can be read. */
+ break;
+ od;
+ }
+}
+
+init {
+ byte i = 0;
+ byte j = 0;
+ byte sum = 0;
+ byte commit_sum = 0;
+
+ atomic {
+ i = 0;
+ do
+ :: i < NR_SUBBUFS ->
+ commit_count[i] = 0;
+ i++
+ :: i >= NR_SUBBUFS -> break
+ od;
+ /* <formal_verif> */
+ _commit_sum = 0;
+ /* </formal_verif> */
+ i = 0;
+ do
+ :: i < BUFSIZE ->
+ buffer_use[i] = 0;
+ i++
+ :: i >= BUFSIZE -> break
+ od;
+ run reader();
+ run cleaner();
+ i = 0;
+ do
+ :: i < NUMPROCS ->
+ refcount = refcount + 1;
+ run tracer();
+ i++
+ :: i >= NUMPROCS -> break
+ od;
+ i = 0;
+ do
+ :: i < NUMSWITCH ->
+ refcount = refcount + 1;
+ run switcher();
+ i++
+ :: i >= NUMSWITCH -> break
+ od;
+ }
+}
+
--- /dev/null
+// If we have less writers than the buffer space available, we should
+// not loose events.
+// assert(NUMPROCS + NUMSWITCH > BUFSIZE || events_lost == 0);
+
+(!buffer_large_enough) -> (<>have_events_lost)
--- /dev/null
+// If we have less writers than the buffer space available, we should
+// not loose events.
+// assert(NUMPROCS + NUMSWITCH > BUFSIZE || events_lost == 0);
+
+buffer_large_enough -> ([](!have_events_lost))
--- /dev/null
+// The sum of all subbuffer commit counts must always be lower or equal
+// to the writer head, because space must be reserved before it is
+// written to and then committed.
+// assert(write_off - _commit_sum >= 0 && write_off - _commit_sum < HALF_UCHAR);
+
+[] (wcsum1 && wcsum2)
--- /dev/null
+// The writer head must always be superior or equal to the reader head.
+// assert(write_off - read_off >= 0 && write_off - read_off < HALF_UCHAR);
+
+[] (rwoff1 && rwoff2)
--- /dev/null
+ switch (t->back) {
+ default: Uerror("bad return move");
+ case 0: goto R999; /* nothing to undo */
+
+ /* PROC :never: */
+;
+ ;
+ ;
+ ;
+ ;
+ ;
+
+ case 6: /* STATE 14 */
+ ;
+ p_restor(II);
+ ;
+ ;
+ goto R999;
+
+ /* PROC :init: */
+
+ case 7: /* STATE 1 */
+ ;
+ ((P4 *)this)->i = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 8: /* STATE 4 */
+ ;
+ ((P4 *)this)->i = trpt->bup.ovals[1];
+ now.commit_count[ Index(((P4 *)this)->i, 2) ] = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 9: /* STATE 11 */
+ ;
+ ((P4 *)this)->i = trpt->bup.ovals[2];
+ now._commit_sum = trpt->bup.ovals[1];
+ /* 0 */ ((P4 *)this)->i = trpt->bup.ovals[0];
+ ;
+ ;
+ ungrab_ints(trpt->bup.ovals, 3);
+ goto R999;
+
+ case 10: /* STATE 11 */
+ ;
+ ((P4 *)this)->i = trpt->bup.ovals[1];
+ now._commit_sum = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 11: /* STATE 14 */
+ ;
+ ((P4 *)this)->i = trpt->bup.ovals[1];
+ now.buffer_use[ Index(((P4 *)this)->i, 4) ] = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 12: /* STATE 15 */
+ ;
+ /* 0 */ ((P4 *)this)->i = trpt->bup.oval;
+ ;
+ ;
+ goto R999;
+
+ case 13: /* STATE 20 */
+ ;
+ ;
+ delproc(0, now._nr_pr-1);
+ ;
+ goto R999;
+
+ case 14: /* STATE 22 */
+ ;
+ ((P4 *)this)->i = trpt->bup.oval;
+ ;
+ delproc(0, now._nr_pr-1);
+ ;
+ goto R999;
+
+ case 15: /* STATE 24 */
+ ;
+ now.refcount = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 16: /* STATE 26 */
+ ;
+ ((P4 *)this)->i = trpt->bup.oval;
+ ;
+ delproc(0, now._nr_pr-1);
+ ;
+ goto R999;
+
+ case 17: /* STATE 32 */
+ ;
+ ((P4 *)this)->i = trpt->bup.ovals[1];
+ /* 0 */ ((P4 *)this)->i = trpt->bup.ovals[0];
+ ;
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 18: /* STATE 32 */
+ ;
+ ((P4 *)this)->i = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 19: /* STATE 34 */
+ ;
+ now.refcount = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 20: /* STATE 36 */
+ ;
+ ((P4 *)this)->i = trpt->bup.oval;
+ ;
+ delproc(0, now._nr_pr-1);
+ ;
+ goto R999;
+
+ case 21: /* STATE 37 */
+ ;
+ /* 0 */ ((P4 *)this)->i = trpt->bup.oval;
+ ;
+ ;
+ goto R999;
+
+ case 22: /* STATE 43 */
+ ;
+ p_restor(II);
+ ;
+ ;
+ goto R999;
+
+ /* PROC cleaner */
+
+ case 23: /* STATE 2 */
+ ;
+ now.refcount = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 24: /* STATE 3 */
+ ;
+ ;
+ delproc(0, now._nr_pr-1);
+ ;
+ goto R999;
+
+ case 25: /* STATE 9 */
+ ;
+ p_restor(II);
+ ;
+ ;
+ goto R999;
+
+ /* PROC reader */
+;
+ ;
+
+ case 27: /* STATE 2 */
+ ;
+ ((P2 *)this)->i = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 28: /* STATE 6 */
+ ;
+ ((P2 *)this)->i = trpt->bup.ovals[1];
+ now.buffer_use[ Index(((now.read_off+((P2 *)this)->i)%4), 4) ] = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 29: /* STATE 7 */
+ ;
+ /* 0 */ ((P2 *)this)->i = trpt->bup.oval;
+ ;
+ ;
+ goto R999;
+
+ case 30: /* STATE 16 */
+ ;
+ ((P2 *)this)->i = trpt->bup.ovals[1];
+ now.buffer_use[ Index(((now.read_off+((P2 *)this)->i)%4), 4) ] = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 31: /* STATE 17 */
+ ;
+ /* 0 */ ((P2 *)this)->i = trpt->bup.oval;
+ ;
+ ;
+ goto R999;
+
+ case 32: /* STATE 22 */
+ ;
+ now.read_off = trpt->bup.oval;
+ ;
+ goto R999;
+;
+ ;
+
+ case 34: /* STATE 29 */
+ ;
+ p_restor(II);
+ ;
+ ;
+ goto R999;
+
+ /* PROC tracer */
+
+ case 35: /* STATE 2 */
+ ;
+ ((P1 *)this)->new_off = trpt->bup.ovals[1];
+ ((P1 *)this)->prev_off = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 36: /* STATE 4 */
+ ;
+ /* 0 */ ((P1 *)this)->new_off = trpt->bup.oval;
+ ;
+ ;
+ goto R999;
+;
+
+ case 37: /* STATE 7 */
+ goto R999;
+
+ case 38: /* STATE 11 */
+ ;
+ /* 0 */ ((P1 *)this)->prev_off = trpt->bup.oval;
+ ;
+ ;
+ goto R999;
+
+ case 39: /* STATE 17 */
+ ;
+ ((P1 *)this)->i = trpt->bup.ovals[1];
+ now.write_off = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 40: /* STATE 17 */
+ ;
+ ((P1 *)this)->i = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 41: /* STATE 21 */
+ ;
+ ((P1 *)this)->i = trpt->bup.ovals[1];
+ now.buffer_use[ Index(((((P1 *)this)->prev_off+((P1 *)this)->i)%4), 4) ] = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 42: /* STATE 22 */
+ ;
+ /* 0 */ ((P1 *)this)->i = trpt->bup.oval;
+ ;
+ ;
+ goto R999;
+
+ case 43: /* STATE 28 */
+ ;
+ ((P1 *)this)->i = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 44: /* STATE 31 */
+ ;
+ ((P1 *)this)->i = trpt->bup.ovals[1];
+ now.buffer_use[ Index(((((P1 *)this)->prev_off+((P1 *)this)->i)%4), 4) ] = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 45: /* STATE 39 */
+ ;
+ now.commit_count[ Index(((((P1 *)this)->prev_off%4)/(4/2)), 2) ] = trpt->bup.ovals[3];
+ now._commit_sum = trpt->bup.ovals[2];
+ ((P1 *)this)->tmp_commit = trpt->bup.ovals[1];
+ /* 0 */ ((P1 *)this)->i = trpt->bup.ovals[0];
+ ;
+ ;
+ ungrab_ints(trpt->bup.ovals, 4);
+ goto R999;
+
+ case 46: /* STATE 39 */
+ ;
+ now.commit_count[ Index(((((P1 *)this)->prev_off%4)/(4/2)), 2) ] = trpt->bup.ovals[2];
+ now._commit_sum = trpt->bup.ovals[1];
+ ((P1 *)this)->tmp_commit = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 3);
+ goto R999;
+
+ case 47: /* STATE 41 */
+ ;
+ deliver = trpt->bup.ovals[2];
+ /* 1 */ ((P1 *)this)->tmp_commit = trpt->bup.ovals[1];
+ /* 0 */ ((P1 *)this)->prev_off = trpt->bup.ovals[0];
+ ;
+ ;
+ ungrab_ints(trpt->bup.ovals, 3);
+ goto R999;
+;
+
+ case 48: /* STATE 45 */
+ goto R999;
+;
+
+ case 49: /* STATE 43 */
+ goto R999;
+
+ case 50: /* STATE 48 */
+ ;
+ now.events_lost = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 51: /* STATE 49 */
+ ;
+ now.refcount = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 52: /* STATE 51 */
+ ;
+ p_restor(II);
+ ;
+ ;
+ goto R999;
+
+ /* PROC switcher */
+
+ case 53: /* STATE 3 */
+ ;
+ ((P0 *)this)->new_off = trpt->bup.ovals[2];
+ ((P0 *)this)->size = trpt->bup.ovals[1];
+ ((P0 *)this)->prev_off = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 3);
+ goto R999;
+
+ case 54: /* STATE 5 */
+ ;
+ now.refcount = trpt->bup.ovals[2];
+ /* 1 */ ((P0 *)this)->size = trpt->bup.ovals[1];
+ /* 0 */ ((P0 *)this)->new_off = trpt->bup.ovals[0];
+ ;
+ ;
+ ungrab_ints(trpt->bup.ovals, 3);
+ goto R999;
+;
+
+ case 55: /* STATE 8 */
+ goto R999;
+
+ case 56: /* STATE 12 */
+ ;
+ /* 0 */ ((P0 *)this)->prev_off = trpt->bup.oval;
+ ;
+ ;
+ goto R999;
+;
+
+ case 57: /* STATE 17 */
+ goto R999;
+
+ case 58: /* STATE 15 */
+ ;
+ now.write_off = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 59: /* STATE 21 */
+ ;
+ now.commit_count[ Index(((((P0 *)this)->prev_off%4)/(4/2)), 2) ] = trpt->bup.ovals[2];
+ now._commit_sum = trpt->bup.ovals[1];
+ ((P0 *)this)->tmp_commit = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 3);
+ goto R999;
+
+ case 60: /* STATE 28 */
+ ;
+ now.refcount = trpt->bup.ovals[3];
+ deliver = trpt->bup.ovals[2];
+ /* 1 */ ((P0 *)this)->tmp_commit = trpt->bup.ovals[1];
+ /* 0 */ ((P0 *)this)->prev_off = trpt->bup.ovals[0];
+ ;
+ ;
+ ungrab_ints(trpt->bup.ovals, 4);
+ goto R999;
+
+ case 61: /* STATE 28 */
+ ;
+ now.refcount = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 62: /* STATE 28 */
+ ;
+ now.refcount = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 63: /* STATE 31 */
+ ;
+ p_restor(II);
+ ;
+ ;
+ goto R999;
+ }
+
--- /dev/null
+/*** Generated by Spin Version 5.1.6 -- 9 May 2008 ***/
+/*** From source: model.spin ***/
+
+#ifdef SC
+#define _FILE_OFFSET_BITS 64
+#endif
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#if defined(WIN32) || defined(WIN64)
+#include <time.h>
+#else
+#include <unistd.h>
+#include <sys/times.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#define Offsetof(X, Y) ((unsigned long)(&(((X *)0)->Y)))
+#ifndef max
+#define max(a,b) (((a)<(b)) ? (b) : (a))
+#endif
+#ifndef PRINTF
+int Printf(const char *fmt, ...); /* prototype only */
+#endif
+#include "pan.h"
+#ifdef LOOPSTATE
+double cnt_loops;
+#endif
+State A_Root; /* seed-state for cycles */
+State now; /* the full state-vector */
+#undef C_States
+#if defined(C_States) && defined(HAS_TRACK)
+void
+c_update(uchar *p_t_r)
+{
+#ifdef VERBOSE
+ printf("c_update %u\n", p_t_r);
+#endif
+}
+void
+c_revert(uchar *p_t_r)
+{
+#ifdef VERBOSE
+ printf("c_revert %u\n", p_t_r);
+#endif
+}
+#endif
+void
+globinit(void)
+{
+}
+void
+locinit5(int h)
+{
+}
+void
+locinit4(int h)
+{
+}
+void
+locinit3(int h)
+{
+}
+void
+locinit2(int h)
+{
+}
+void
+locinit1(int h)
+{
+}
+void
+locinit0(int h)
+{
+}
+#ifdef CNTRSTACK
+#define onstack_now() (LL[trpt->j6] && LL[trpt->j7])
+#define onstack_put() LL[trpt->j6]++; LL[trpt->j7]++
+#define onstack_zap() LL[trpt->j6]--; LL[trpt->j7]--
+#endif
+#if !defined(SAFETY) && !defined(NOCOMP)
+#define V_A (((now._a_t&1)?2:1) << (now._a_t&2))
+#define A_V (((now._a_t&1)?1:2) << (now._a_t&2))
+int S_A = 0;
+#else
+#define V_A 0
+#define A_V 0
+#define S_A 0
+#endif
+#ifdef MA
+#undef onstack_now
+#undef onstack_put
+#undef onstack_zap
+#define onstack_put() ;
+#define onstack_zap() gstore((char *) &now, vsize, 4)
+#else
+#if defined(FULLSTACK) && !defined(BITSTATE)
+#define onstack_put() trpt->ostate = Lstate
+#define onstack_zap() { \
+ if (trpt->ostate) \
+ trpt->ostate->tagged = \
+ (S_A)? (trpt->ostate->tagged&~V_A) : 0; \
+ }
+#endif
+#endif
+#ifndef NO_V_PROVISO
+#define V_PROVISO
+#endif
+#if !defined(NO_RESIZE) && !defined(AUTO_RESIZE) && !defined(BITSTATE) && !defined(SPACE) && NCORE==1
+ #define AUTO_RESIZE
+#endif
+
+struct H_el {
+ struct H_el *nxt;
+#ifdef FULLSTACK
+ unsigned int tagged;
+ #if defined(BITSTATE) && !defined(NOREDUCE) && !defined(SAFETY)
+ unsigned int proviso;
+ #endif
+#endif
+#if defined(CHECK) || (defined(COLLAPSE) && !defined(FULLSTACK))
+ unsigned long st_id;
+#endif
+#if !defined(SAFETY) || defined(REACH)
+ unsigned int D;
+#endif
+#if NCORE>1
+ /* could cost 1 extra word: 4 bytes if 32-bit and 8 bytes if 64-bit */
+ #ifdef V_PROVISO
+ uchar cpu_id; /* id of cpu that created the state */
+ #endif
+#endif
+#ifdef COLLAPSE
+ #if VECTORSZ<65536
+ unsigned short ln;
+ #else
+ unsigned long ln;
+ #endif
+#endif
+#if defined(AUTO_RESIZE) && !defined(BITSTATE)
+ unsigned long m_K1;
+#endif
+ unsigned long state;
+} **H_tab, **S_Tab;
+
+typedef struct Trail {
+ int st; /* current state */
+ uchar pr; /* process id */
+ uchar tau; /* 8 bit-flags */
+ uchar o_pm; /* 8 more bit-flags */
+#if 0
+ Meaning of bit-flags:
+ tau&1 -> timeout enabled
+ tau&2 -> request to enable timeout 1 level up (in claim)
+ tau&4 -> current transition is a claim move
+ tau&8 -> current transition is an atomic move
+ tau&16 -> last move was truncated on stack
+ tau&32 -> current transition is a preselected move
+ tau&64 -> at least one next state is not on the stack
+ tau&128 -> current transition is a stutter move
+ o_pm&1 -> the current pid moved -- implements else
+ o_pm&2 -> this is an acceptance state
+ o_pm&4 -> this is a progress state
+ o_pm&8 -> fairness alg rule 1 undo mark
+ o_pm&16 -> fairness alg rule 3 undo mark
+ o_pm&32 -> fairness alg rule 2 undo mark
+ o_pm&64 -> the current proc applied rule2
+ o_pm&128 -> a fairness, dummy move - all procs blocked
+#endif
+#ifdef NSUCC
+ uchar n_succ; /* nr of successor states */
+#endif
+#if defined(FULLSTACK) && defined(MA) && !defined(BFS)
+ uchar proviso;
+#endif
+#ifndef BFS
+ uchar o_n, o_ot; /* to save locals */
+#endif
+ uchar o_m;
+#ifdef EVENT_TRACE
+#if nstates_event<256
+ uchar o_event;
+#else
+ unsigned short o_event;
+#endif
+#endif
+ int o_tt;
+#ifndef BFS
+ short o_To;
+#ifdef RANDOMIZE
+ short oo_i;
+#endif
+#endif
+#if defined(HAS_UNLESS) && !defined(BFS)
+ int e_state; /* if escape trans - state of origin */
+#endif
+#if (defined(FULLSTACK) && !defined(MA)) || defined(BFS) || (NCORE>1)
+ struct H_el *ostate; /* pointer to stored state */
+#endif
+#if defined(CNTRSTACK) && !defined(BFS)
+ long j6, j7;
+#endif
+ Trans *o_t;
+#ifdef SCHED
+ /* based on Qadeer&Rehof, Tacas 2005, LNCS 3440, pp. 93-107 */
+ #if NCORE>1
+ #error "-DSCHED cannot be combined with -DNCORE (yet)"
+ #endif
+ int sched_limit;
+#endif
+#ifdef HAS_SORTED
+ short ipt;
+#endif
+ union {
+ int oval;
+ int *ovals;
+ } bup;
+} Trail;
+Trail *trail, *trpt;
+FILE *efd;
+uchar *this;
+long maxdepth=10000;
+long omaxdepth=10000;
+#ifdef SCHED
+int sched_max = 10;
+#endif
+#ifdef PERMUTED
+ uchar permuted = 1;
+#else
+ uchar permuted = 0;
+#endif
+double quota; /* time limit */
+#if NCORE>1
+long z_handoff = -1;
+#endif
+#ifdef SC
+char *stackfile;
+#endif
+uchar *SS, *LL;
+uchar HASH_NR = 0;
+
+double memcnt = (double) 0;
+double memlim = (double) (1<<30); /* 1 GB */
+#if NCORE>1
+double mem_reserved = (double) 0;
+#endif
+
+/* for emalloc: */
+static char *have;
+static long left = 0L;
+static double fragment = (double) 0;
+static unsigned long grow;
+
+unsigned int HASH_CONST[] = {
+ /* asuming 4 bytes per int */
+ 0x88888EEF, 0x00400007,
+ 0x04c11db7, 0x100d4e63,
+ 0x0fc22f87, 0x3ff0c3ff,
+ 0x38e84cd7, 0x02b148e9,
+ 0x98b2e49d, 0xb616d379,
+ 0xa5247fd9, 0xbae92a15,
+ 0xb91c8bc5, 0x8e5880f3,
+ 0xacd7c069, 0xb4c44bb3,
+ 0x2ead1fb7, 0x8e428171,
+ 0xdbebd459, 0x828ae611,
+ 0x6cb25933, 0x86cdd651,
+ 0x9e8f5f21, 0xd5f8d8e7,
+ 0x9c4e956f, 0xb5cf2c71,
+ 0x2e805a6d, 0x33fc3a55,
+ 0xaf203ed1, 0xe31f5909,
+ 0x5276db35, 0x0c565ef7,
+ 0x273d1aa5, 0x8923b1dd,
+ 0
+};
+#if NCORE>1
+extern int core_id;
+#endif
+long mreached=0;
+int done=0, errors=0, Nrun=1;
+int c_init_done=0;
+char *c_stack_start = (char *) 0;
+double nstates=0, nlinks=0, truncs=0, truncs2=0;
+double nlost=0, nShadow=0, hcmp=0, ngrabs=0;
+#if defined(ZAPH) && defined(BITSTATE)
+double zstates = 0;
+#endif
+int c_init_run;
+#ifdef BFS
+double midrv=0, failedrv=0, revrv=0;
+#endif
+unsigned long nr_states=0; /* nodes in DFA */
+long Fa=0, Fh=0, Zh=0, Zn=0;
+long PUT=0, PROBE=0, ZAPS=0;
+long Ccheck=0, Cholds=0;
+int a_cycles=0, upto=1, strict=0, verbose = 0, signoff = 0;
+#ifdef HAS_CODE
+int gui = 0, coltrace = 0, readtrail = 0;
+int whichtrail = 0, onlyproc = -1, silent = 0;
+#endif
+int state_tables=0, fairness=0, no_rck=0, Nr_Trails=0;
+char simvals[128];
+#ifndef INLINE
+int TstOnly=0;
+#endif
+unsigned long mask, nmask;
+#ifdef BITSTATE
+int ssize=23; /* 1 Mb */
+#else
+int ssize=19; /* 512K slots */
+#endif
+int hmax=0, svmax=0, smax=0;
+int Maxbody=0, XX;
+uchar *noptr; /* used by macro Pptr(x) */
+#ifdef VAR_RANGES
+void logval(char *, int);
+void dumpranges(void);
+#endif
+#ifdef MA
+#define INLINE_REV
+extern void dfa_init(unsigned short);
+extern int dfa_member(unsigned long);
+extern int dfa_store(uchar *);
+unsigned int maxgs = 0;
+#endif
+
+#ifdef ALIGNED
+ State comp_now __attribute__ ((aligned (8)));
+ /* gcc 64-bit aligned for Itanium2 systems */
+ /* MAJOR runtime penalty if not used on those systems */
+#else
+ State comp_now; /* compressed state vector */
+#endif
+
+State comp_msk;
+uchar *Mask = (uchar *) &comp_msk;
+#ifdef COLLAPSE
+State comp_tmp;
+static char *scratch = (char *) &comp_tmp;
+#endif
+Stack *stack; /* for queues, processes */
+Svtack *svtack; /* for old state vectors */
+#ifdef BITSTATE
+static unsigned int hfns = 3; /* new default */
+#endif
+static unsigned long j1;
+static unsigned long K1, K2;
+static unsigned long j2, j3, j4;
+#ifdef BITSTATE
+static long udmem;
+#endif
+static long A_depth = 0;
+long depth = 0;
+#if NCORE>1
+long nr_handoffs = 0;
+#endif
+static uchar warned = 0, iterative = 0, exclusive = 0, like_java = 0, every_error = 0;
+static uchar noasserts = 0, noends = 0, bounded = 0;
+#if SYNC>0 && ASYNC==0
+void set_recvs(void);
+int no_recvs(int);
+#endif
+#if SYNC
+#define IfNotBlocked if (boq != -1) continue;
+#define UnBlock boq = -1
+#else
+#define IfNotBlocked /* cannot block */
+#define UnBlock /* don't bother */
+#endif
+
+#ifdef BITSTATE
+int (*bstore)(char *, int);
+int bstore_reg(char *, int);
+int bstore_mod(char *, int);
+#endif
+void active_procs(void);
+void cleanup(void);
+void do_the_search(void);
+void find_shorter(int);
+void iniglobals(void);
+void stopped(int);
+void wrapup(void);
+int *grab_ints(int);
+void ungrab_ints(int *, int);
+#ifndef NOBOUNDCHECK
+#define Index(x, y) Boundcheck(x, y, II, tt, t)
+#else
+#define Index(x, y) x
+#endif
+short Air[] = { (short) Air0, (short) Air1, (short) Air2, (short) Air3, (short) Air4, (short) Air5, (short) Air6 };
+int
+addproc(int n)
+{ int j, h = now._nr_pr;
+#ifndef NOCOMP
+ int k;
+#endif
+ uchar *o_this = this;
+
+#ifndef INLINE
+ if (TstOnly) return (h < MAXPROC);
+#endif
+#ifndef NOBOUNDCHECK
+/* redefine Index only within this procedure */
+#undef Index
+#define Index(x, y) Boundcheck(x, y, 0, 0, 0)
+#endif
+ if (h >= MAXPROC)
+ Uerror("too many processes");
+ switch (n) {
+ case 0: j = sizeof(P0); break;
+ case 1: j = sizeof(P1); break;
+ case 2: j = sizeof(P2); break;
+ case 3: j = sizeof(P3); break;
+ case 4: j = sizeof(P4); break;
+ case 5: j = sizeof(P5); break;
+ case 6: j = sizeof(P6); break;
+ default: Uerror("bad proc - addproc");
+ }
+ if (vsize%WS)
+ proc_skip[h] = WS-(vsize%WS);
+ else
+ proc_skip[h] = 0;
+#ifndef NOCOMP
+ for (k = vsize + (int) proc_skip[h]; k > vsize; k--)
+ Mask[k-1] = 1; /* align */
+#endif
+ vsize += (int) proc_skip[h];
+ proc_offset[h] = vsize;
+#ifdef SVDUMP
+ if (vprefix > 0)
+ { int dummy = 0;
+ write(svfd, (uchar *) &dummy, sizeof(int)); /* mark */
+ write(svfd, (uchar *) &h, sizeof(int));
+ write(svfd, (uchar *) &n, sizeof(int));
+#if VECTORSZ>32000
+ write(svfd, (uchar *) &proc_offset[h], sizeof(int));
+#else
+ write(svfd, (uchar *) &proc_offset[h], sizeof(short));
+#endif
+ write(svfd, (uchar *) &now, vprefix-4*sizeof(int)); /* padd */
+ }
+#endif
+ now._nr_pr += 1;
+ if (fairness && ((int) now._nr_pr + 1 >= (8*NFAIR)/2))
+ { printf("pan: error: too many processes -- current");
+ printf(" max is %d procs (-DNFAIR=%d)\n",
+ (8*NFAIR)/2 - 2, NFAIR);
+ printf("\trecompile with -DNFAIR=%d\n",
+ NFAIR+1);
+ pan_exit(1);
+ }
+ vsize += j;
+#ifndef NOVSZ
+ now._vsz = vsize;
+#endif
+#ifndef NOCOMP
+ for (k = 1; k <= Air[n]; k++)
+ Mask[vsize - k] = 1; /* pad */
+ Mask[vsize-j] = 1; /* _pid */
+#endif
+ hmax = max(hmax, vsize);
+ if (vsize >= VECTORSZ)
+ { printf("pan: error, VECTORSZ too small, recompile pan.c");
+ printf(" with -DVECTORSZ=N with N>%d\n", (int) vsize);
+ Uerror("aborting");
+ }
+ memset((char *)pptr(h), 0, j);
+ this = pptr(h);
+ if (BASE > 0 && h > 0)
+ ((P0 *)this)->_pid = h-BASE;
+ else
+ ((P0 *)this)->_pid = h;
+ switch (n) {
+ case 6: /* np_ */
+ ((P6 *)pptr(h))->_t = 6;
+ ((P6 *)pptr(h))->_p = 0;
+ reached6[0] = 1;
+ accpstate[6][1] = 1;
+ break;
+ case 5: /* :never: */
+ ((P5 *)pptr(h))->_t = 5;
+ ((P5 *)pptr(h))->_p = 5; reached5[5]=1;
+ /* params: */
+ /* locals: */
+#ifdef VAR_RANGES
+#endif
+#ifdef HAS_CODE
+ locinit5(h);
+#endif
+ break;
+ case 4: /* :init: */
+ ((P4 *)pptr(h))->_t = 4;
+ ((P4 *)pptr(h))->_p = 42; reached4[42]=1;
+ /* params: */
+ /* locals: */
+ ((P4 *)pptr(h))->i = 0;
+ ((P4 *)pptr(h))->j = 0;
+ ((P4 *)pptr(h))->sum = 0;
+ ((P4 *)pptr(h))->commit_sum = 0;
+#ifdef VAR_RANGES
+ logval(":init::i", ((P4 *)pptr(h))->i);
+ logval(":init::j", ((P4 *)pptr(h))->j);
+ logval(":init::sum", ((P4 *)pptr(h))->sum);
+ logval(":init::commit_sum", ((P4 *)pptr(h))->commit_sum);
+#endif
+#ifdef HAS_CODE
+ locinit4(h);
+#endif
+ break;
+ case 3: /* cleaner */
+ ((P3 *)pptr(h))->_t = 3;
+ ((P3 *)pptr(h))->_p = 8; reached3[8]=1;
+ /* params: */
+ /* locals: */
+#ifdef VAR_RANGES
+#endif
+#ifdef HAS_CODE
+ locinit3(h);
+#endif
+ break;
+ case 2: /* reader */
+ ((P2 *)pptr(h))->_t = 2;
+ ((P2 *)pptr(h))->_p = 26; reached2[26]=1;
+ /* params: */
+ /* locals: */
+ ((P2 *)pptr(h))->i = 0;
+ ((P2 *)pptr(h))->j = 0;
+#ifdef VAR_RANGES
+ logval("reader:i", ((P2 *)pptr(h))->i);
+ logval("reader:j", ((P2 *)pptr(h))->j);
+#endif
+#ifdef HAS_CODE
+ locinit2(h);
+#endif
+ break;
+ case 1: /* tracer */
+ ((P1 *)pptr(h))->_t = 1;
+ ((P1 *)pptr(h))->_p = 3; reached1[3]=1;
+ /* params: */
+ /* locals: */
+ ((P1 *)pptr(h))->size = 1;
+ ((P1 *)pptr(h))->prev_off = 0;
+ ((P1 *)pptr(h))->new_off = 0;
+ ((P1 *)pptr(h))->tmp_commit = 0;
+ ((P1 *)pptr(h))->i = 0;
+ ((P1 *)pptr(h))->j = 0;
+#ifdef VAR_RANGES
+ logval("tracer:size", ((P1 *)pptr(h))->size);
+ logval("tracer:prev_off", ((P1 *)pptr(h))->prev_off);
+ logval("tracer:new_off", ((P1 *)pptr(h))->new_off);
+ logval("tracer:tmp_commit", ((P1 *)pptr(h))->tmp_commit);
+ logval("tracer:i", ((P1 *)pptr(h))->i);
+ logval("tracer:j", ((P1 *)pptr(h))->j);
+#endif
+#ifdef HAS_CODE
+ locinit1(h);
+#endif
+ break;
+ case 0: /* switcher */
+ ((P0 *)pptr(h))->_t = 0;
+ ((P0 *)pptr(h))->_p = 11; reached0[11]=1;
+ /* params: */
+ /* locals: */
+ ((P0 *)pptr(h))->prev_off = 0;
+ ((P0 *)pptr(h))->new_off = 0;
+ ((P0 *)pptr(h))->tmp_commit = 0;
+ ((P0 *)pptr(h))->size = 0;
+#ifdef VAR_RANGES
+ logval("switcher:prev_off", ((P0 *)pptr(h))->prev_off);
+ logval("switcher:new_off", ((P0 *)pptr(h))->new_off);
+ logval("switcher:tmp_commit", ((P0 *)pptr(h))->tmp_commit);
+ logval("switcher:size", ((P0 *)pptr(h))->size);
+#endif
+#ifdef HAS_CODE
+ locinit0(h);
+#endif
+ break;
+ }
+ this = o_this;
+ return h-BASE;
+#ifndef NOBOUNDCHECK
+#undef Index
+#define Index(x, y) Boundcheck(x, y, II, tt, t)
+#endif
+}
+
+#if defined(BITSTATE) && defined(COLLAPSE)
+/* just to allow compilation, to generate the error */
+long col_p(int i, char *z) { return 0; }
+long col_q(int i, char *z) { return 0; }
+#endif
+#ifndef BITSTATE
+#ifdef COLLAPSE
+long
+col_p(int i, char *z)
+{ int j, k; unsigned long ordinal(char *, long, short);
+ char *x, *y;
+ P0 *ptr = (P0 *) pptr(i);
+ switch (ptr->_t) {
+ case 0: j = sizeof(P0); break;
+ case 1: j = sizeof(P1); break;
+ case 2: j = sizeof(P2); break;
+ case 3: j = sizeof(P3); break;
+ case 4: j = sizeof(P4); break;
+ case 5: j = sizeof(P5); break;
+ case 6: j = sizeof(P6); break;
+ default: Uerror("bad proctype - collapse");
+ }
+ if (z) x = z; else x = scratch;
+ y = (char *) ptr; k = proc_offset[i];
+ for ( ; j > 0; j--, y++)
+ if (!Mask[k++]) *x++ = *y;
+ for (j = 0; j < WS-1; j++)
+ *x++ = 0;
+ x -= j;
+ if (z) return (long) (x - z);
+ return ordinal(scratch, x-scratch, (short) (2+ptr->_t));
+}
+#endif
+#endif
+void
+run(void)
+{ /* int i; */
+ memset((char *)&now, 0, sizeof(State));
+ vsize = (unsigned long) (sizeof(State) - VECTORSZ);
+#ifndef NOVSZ
+ now._vsz = vsize;
+#endif
+/* optional provisioning statements, e.g. to */
+/* set hidden variables, used as constants */
+#ifdef PROV
+#include PROV
+#endif
+ settable();
+ Maxbody = max(Maxbody, ((int) sizeof(P0)));
+ Maxbody = max(Maxbody, ((int) sizeof(P1)));
+ Maxbody = max(Maxbody, ((int) sizeof(P2)));
+ Maxbody = max(Maxbody, ((int) sizeof(P3)));
+ Maxbody = max(Maxbody, ((int) sizeof(P4)));
+ Maxbody = max(Maxbody, ((int) sizeof(P5)));
+ Maxbody = max(Maxbody, ((int) sizeof(P6)));
+ reached[0] = reached0;
+ reached[1] = reached1;
+ reached[2] = reached2;
+ reached[3] = reached3;
+ reached[4] = reached4;
+ reached[5] = reached5;
+ reached[6] = reached6;
+ accpstate[0] = (uchar *) emalloc(nstates0);
+ accpstate[1] = (uchar *) emalloc(nstates1);
+ accpstate[2] = (uchar *) emalloc(nstates2);
+ accpstate[3] = (uchar *) emalloc(nstates3);
+ accpstate[4] = (uchar *) emalloc(nstates4);
+ accpstate[5] = (uchar *) emalloc(nstates5);
+ accpstate[6] = (uchar *) emalloc(nstates6);
+ progstate[0] = (uchar *) emalloc(nstates0);
+ progstate[1] = (uchar *) emalloc(nstates1);
+ progstate[2] = (uchar *) emalloc(nstates2);
+ progstate[3] = (uchar *) emalloc(nstates3);
+ progstate[4] = (uchar *) emalloc(nstates4);
+ progstate[5] = (uchar *) emalloc(nstates5);
+ progstate[6] = (uchar *) emalloc(nstates6);
+ loopstate0 = loopstate[0] = (uchar *) emalloc(nstates0);
+ loopstate1 = loopstate[1] = (uchar *) emalloc(nstates1);
+ loopstate2 = loopstate[2] = (uchar *) emalloc(nstates2);
+ loopstate3 = loopstate[3] = (uchar *) emalloc(nstates3);
+ loopstate4 = loopstate[4] = (uchar *) emalloc(nstates4);
+ loopstate5 = loopstate[5] = (uchar *) emalloc(nstates5);
+ loopstate6 = loopstate[6] = (uchar *) emalloc(nstates6);
+ stopstate[0] = (uchar *) emalloc(nstates0);
+ stopstate[1] = (uchar *) emalloc(nstates1);
+ stopstate[2] = (uchar *) emalloc(nstates2);
+ stopstate[3] = (uchar *) emalloc(nstates3);
+ stopstate[4] = (uchar *) emalloc(nstates4);
+ stopstate[5] = (uchar *) emalloc(nstates5);
+ stopstate[6] = (uchar *) emalloc(nstates6);
+ visstate[0] = (uchar *) emalloc(nstates0);
+ visstate[1] = (uchar *) emalloc(nstates1);
+ visstate[2] = (uchar *) emalloc(nstates2);
+ visstate[3] = (uchar *) emalloc(nstates3);
+ visstate[4] = (uchar *) emalloc(nstates4);
+ visstate[5] = (uchar *) emalloc(nstates5);
+ visstate[6] = (uchar *) emalloc(nstates6);
+ mapstate[0] = (short *) emalloc(nstates0 * sizeof(short));
+ mapstate[1] = (short *) emalloc(nstates1 * sizeof(short));
+ mapstate[2] = (short *) emalloc(nstates2 * sizeof(short));
+ mapstate[3] = (short *) emalloc(nstates3 * sizeof(short));
+ mapstate[4] = (short *) emalloc(nstates4 * sizeof(short));
+ mapstate[5] = (short *) emalloc(nstates5 * sizeof(short));
+ mapstate[6] = (short *) emalloc(nstates6 * sizeof(short));
+#ifdef HAS_CODE
+#ifdef HAS_CODE
+#ifdef HAS_CODE
+#ifdef HAS_CODE
+#ifdef HAS_CODE
+#ifdef HAS_CODE
+#ifdef HAS_CODE
+ NrStates[0] = nstates0;
+ NrStates[1] = nstates1;
+ NrStates[2] = nstates2;
+ NrStates[3] = nstates3;
+ NrStates[4] = nstates4;
+ NrStates[5] = nstates5;
+ NrStates[6] = nstates6;
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+ stopstate[0][endstate0] = 1;
+ stopstate[1][endstate1] = 1;
+ stopstate[2][endstate2] = 1;
+ stopstate[3][endstate3] = 1;
+ stopstate[4][endstate4] = 1;
+ stopstate[5][endstate5] = 1;
+ stopstate[6][endstate6] = 1;
+ accpstate[5][13] = 1;
+ stopstate[1][49] = 1;
+ retrans(0, nstates0, start0, src_ln0, reached0, loopstate0);
+ retrans(1, nstates1, start1, src_ln1, reached1, loopstate1);
+ retrans(2, nstates2, start2, src_ln2, reached2, loopstate2);
+ retrans(3, nstates3, start3, src_ln3, reached3, loopstate3);
+ retrans(4, nstates4, start4, src_ln4, reached4, loopstate4);
+ retrans(5, nstates5, start5, src_ln5, reached5, loopstate5);
+ if (state_tables)
+ { printf("\nTransition Type: ");
+ printf("A=atomic; D=d_step; L=local; G=global\n");
+ printf("Source-State Labels: ");
+ printf("p=progress; e=end; a=accept;\n");
+#ifdef MERGED
+ printf("Note: statement merging was used. Only the first\n");
+ printf(" stmnt executed in each merge sequence is shown\n");
+ printf(" (use spin -a -o3 to disable statement merging)\n");
+#endif
+ pan_exit(0);
+ }
+ iniglobals();
+#if defined(VERI) && !defined(NOREDUCE) && !defined(NP)
+ if (!state_tables
+#ifdef HAS_CODE
+ && !readtrail
+#endif
+#if NCORE>1
+ && core_id == 0
+#endif
+ )
+ { printf("warning: for p.o. reduction to be valid ");
+ printf("the never claim must be stutter-invariant\n");
+ printf("(never claims generated from LTL ");
+ printf("formulae are stutter-invariant)\n");
+ }
+#endif
+ UnBlock; /* disable rendez-vous */
+#ifdef BITSTATE
+ if (udmem)
+ { udmem *= 1024L*1024L;
+ #if NCORE>1
+ if (!readtrail)
+ { void init_SS(unsigned long);
+ init_SS((unsigned long) udmem);
+ } else
+ #endif
+ SS = (uchar *) emalloc(udmem);
+ bstore = bstore_mod;
+ } else
+ #if NCORE>1
+ { void init_SS(unsigned long);
+ init_SS(ONE_L<<(ssize-3));
+ }
+ #else
+ SS = (uchar *) emalloc(ONE_L<<(ssize-3));
+ #endif
+#else
+ hinit();
+#endif
+#if defined(FULLSTACK) && defined(BITSTATE)
+ onstack_init();
+#endif
+#if defined(CNTRSTACK) && !defined(BFS)
+ LL = (uchar *) emalloc(ONE_L<<(ssize-3));
+#endif
+ stack = ( Stack *) emalloc(sizeof(Stack));
+ svtack = (Svtack *) emalloc(sizeof(Svtack));
+ /* a place to point for Pptr of non-running procs: */
+ noptr = (uchar *) emalloc(Maxbody * sizeof(char));
+#ifdef SVDUMP
+ if (vprefix > 0)
+ write(svfd, (uchar *) &vprefix, sizeof(int));
+#endif
+#ifdef VERI
+ Addproc(VERI); /* never - pid = 0 */
+#endif
+ active_procs(); /* started after never */
+#ifdef EVENT_TRACE
+ now._event = start_event;
+ reached[EVENT_TRACE][start_event] = 1;
+#endif
+#ifdef HAS_CODE
+ globinit();
+#endif
+#ifdef BITSTATE
+go_again:
+#endif
+ do_the_search();
+#ifdef BITSTATE
+ if (--Nrun > 0 && HASH_CONST[++HASH_NR])
+ { printf("Run %d:\n", HASH_NR);
+ wrap_stats();
+ printf("\n");
+ memset(SS, 0, ONE_L<<(ssize-3));
+#ifdef CNTRSTACK
+ memset(LL, 0, ONE_L<<(ssize-3));
+#endif
+#ifdef FULLSTACK
+ memset((uchar *) S_Tab, 0,
+ maxdepth*sizeof(struct H_el *));
+#endif
+ nstates=nlinks=truncs=truncs2=ngrabs = 0;
+ nlost=nShadow=hcmp = 0;
+ Fa=Fh=Zh=Zn = 0;
+ PUT=PROBE=ZAPS=Ccheck=Cholds = 0;
+ goto go_again;
+ }
+#endif
+}
+#ifdef HAS_PROVIDED
+int provided(int, uchar, int, Trans *);
+#endif
+#if NCORE>1
+#define GLOBAL_LOCK (0)
+#ifndef CS_N
+#define CS_N (256*NCORE)
+#endif
+#ifdef NGQ
+#define NR_QS (NCORE)
+#define CS_NR (CS_N+1) /* 2^N + 1, nr critical sections */
+#define GQ_RD GLOBAL_LOCK
+#define GQ_WR GLOBAL_LOCK
+#define CS_ID (1 + (int) (j1 & (CS_N-1))) /* mask: 2^N - 1, zero reserved */
+#define QLOCK(n) (1+n)
+#else
+#define NR_QS (NCORE+1)
+#define CS_NR (CS_N+3)
+#define GQ_RD (1)
+#define GQ_WR (2)
+#define CS_ID (3 + (int) (j1 & (CS_N-1)))
+#define QLOCK(n) (3+n)
+#endif
+
+void e_critical(int);
+void x_critical(int);
+
+#ifndef SEP_STATE
+ #define enter_critical(w) e_critical(w)
+ #define leave_critical(w) x_critical(w)
+#else
+ #ifdef NGQ
+ #define enter_critical(w) { if (w < 1+NCORE) e_critical(w); }
+ #define leave_critical(w) { if (w < 1+NCORE) x_critical(w); }
+ #else
+ #define enter_critical(w) { if (w < 3+NCORE) e_critical(w); }
+ #define leave_critical(w) { if (w < 3+NCORE) x_critical(w); }
+ #endif
+#endif
+
+int
+cpu_printf(const char *fmt, ...)
+{ va_list args;
+ enter_critical(GLOBAL_LOCK); /* printing */
+ printf("cpu%d: ", core_id);
+ fflush(stdout);
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+ fflush(stdout);
+ leave_critical(GLOBAL_LOCK);
+ return 1;
+}
+#else
+int
+cpu_printf(const char *fmt, ...)
+{ va_list args;
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+ return 1;
+}
+#endif
+int
+Printf(const char *fmt, ...)
+{ /* Make sure the args to Printf
+ * are always evaluated (e.g., they
+ * could contain a run stmnt)
+ * but do not generate the output
+ * during verification runs
+ * unless explicitly wanted
+ * If this fails on your system
+ * compile SPIN itself -DPRINTF
+ * and this code is not generated
+ */
+#ifdef HAS_CODE
+ if (readtrail)
+ { va_list args;
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+ return 1;
+ }
+#endif
+#ifdef PRINTF
+ va_list args;
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+#endif
+ return 1;
+}
+extern void printm(int);
+#ifndef SC
+#define getframe(i) &trail[i];
+#else
+static long HHH, DDD, hiwater;
+static long CNT1, CNT2;
+static int stackwrite;
+static int stackread;
+static Trail frameptr;
+Trail *
+getframe(int d)
+{
+ if (CNT1 == CNT2)
+ return &trail[d];
+
+ if (d >= (CNT1-CNT2)*DDD)
+ return &trail[d - (CNT1-CNT2)*DDD];
+
+ if (!stackread
+ && (stackread = open(stackfile, 0)) < 0)
+ { printf("getframe: cannot open %s\n", stackfile);
+ wrapup();
+ }
+ if (lseek(stackread, d* (off_t) sizeof(Trail), SEEK_SET) == -1
+ || read(stackread, &frameptr, sizeof(Trail)) != sizeof(Trail))
+ { printf("getframe: frame read error\n");
+ wrapup();
+ }
+ return &frameptr;
+}
+#endif
+#if !defined(SAFETY) && !defined(BITSTATE)
+#if !defined(FULLSTACK) || defined(MA)
+#define depth_of(x) A_depth /* an estimate */
+#else
+int
+depth_of(struct H_el *s)
+{ Trail *t; int d;
+ for (d = 0; d <= A_depth; d++)
+ { t = getframe(d);
+ if (s == t->ostate)
+ return d;
+ }
+ printf("pan: cannot happen, depth_of\n");
+ return depthfound;
+}
+#endif
+#endif
+#if NCORE>1
+extern void cleanup_shm(int);
+volatile unsigned int *search_terminated; /* to signal early termination */
+#endif
+void
+pan_exit(int val)
+{ void stop_timer(void);
+ if (signoff)
+ { printf("--end of output--\n");
+ }
+#if NCORE>1
+ if (search_terminated != NULL)
+ { *search_terminated |= 1; /* pan_exit */
+ }
+#ifdef USE_DISK
+ { void dsk_stats(void);
+ dsk_stats();
+ }
+#endif
+ if (!state_tables && !readtrail)
+ { cleanup_shm(1);
+ }
+#endif
+ if (val == 2)
+ { val = 0;
+ } else
+ { stop_timer();
+ }
+ exit(val);
+}
+#ifdef HAS_CODE
+char *
+transmognify(char *s)
+{ char *v, *w;
+ static char buf[2][2048];
+ int i, toggle = 0;
+ if (!s || strlen(s) > 2047) return s;
+ memset(buf[0], 0, 2048);
+ memset(buf[1], 0, 2048);
+ strcpy(buf[toggle], s);
+ while ((v = strstr(buf[toggle], "{c_code")))
+ { *v = '\0'; v++;
+ strcpy(buf[1-toggle], buf[toggle]);
+ for (w = v; *w != '}' && *w != '\0'; w++) /* skip */;
+ if (*w != '}') return s;
+ *w = '\0'; w++;
+ for (i = 0; code_lookup[i].c; i++)
+ if (strcmp(v, code_lookup[i].c) == 0
+ && strlen(v) == strlen(code_lookup[i].c))
+ { if (strlen(buf[1-toggle])
+ + strlen(code_lookup[i].t)
+ + strlen(w) > 2047)
+ return s;
+ strcat(buf[1-toggle], code_lookup[i].t);
+ break;
+ }
+ strcat(buf[1-toggle], w);
+ toggle = 1 - toggle;
+ }
+ buf[toggle][2047] = '\0';
+ return buf[toggle];
+}
+#else
+char * transmognify(char *s) { return s; }
+#endif
+#ifdef HAS_CODE
+void
+add_src_txt(int ot, int tt)
+{ Trans *t;
+ char *q;
+
+ for (t = trans[ot][tt]; t; t = t->nxt)
+ { printf("\t\t");
+ q = transmognify(t->tp);
+ for ( ; q && *q; q++)
+ if (*q == '\n')
+ printf("\\n");
+ else
+ putchar(*q);
+ printf("\n");
+ }
+}
+void
+wrap_trail(void)
+{ static int wrap_in_progress = 0;
+ int i; short II;
+ P0 *z;
+
+ if (wrap_in_progress++) return;
+
+ printf("spin: trail ends after %ld steps\n", depth);
+ if (onlyproc >= 0)
+ { if (onlyproc >= now._nr_pr) { pan_exit(0); }
+ II = onlyproc;
+ z = (P0 *)pptr(II);
+ printf("%3ld: proc %d (%s) ",
+ depth, II, procname[z->_t]);
+ for (i = 0; src_all[i].src; i++)
+ if (src_all[i].tp == (int) z->_t)
+ { printf(" line %3d",
+ src_all[i].src[z->_p]);
+ break;
+ }
+ printf(" (state %2d)", z->_p);
+ if (!stopstate[z->_t][z->_p])
+ printf(" (invalid end state)");
+ printf("\n");
+ add_src_txt(z->_t, z->_p);
+ pan_exit(0);
+ }
+ printf("#processes %d:\n", now._nr_pr);
+ if (depth < 0) depth = 0;
+ for (II = 0; II < now._nr_pr; II++)
+ { z = (P0 *)pptr(II);
+ printf("%3ld: proc %d (%s) ",
+ depth, II, procname[z->_t]);
+ for (i = 0; src_all[i].src; i++)
+ if (src_all[i].tp == (int) z->_t)
+ { printf(" line %3d",
+ src_all[i].src[z->_p]);
+ break;
+ }
+ printf(" (state %2d)", z->_p);
+ if (!stopstate[z->_t][z->_p])
+ printf(" (invalid end state)");
+ printf("\n");
+ add_src_txt(z->_t, z->_p);
+ }
+ c_globals();
+ for (II = 0; II < now._nr_pr; II++)
+ { z = (P0 *)pptr(II);
+ c_locals(II, z->_t);
+ }
+#ifdef ON_EXIT
+ ON_EXIT;
+#endif
+ pan_exit(0);
+}
+FILE *
+findtrail(void)
+{ FILE *fd;
+ char fnm[512], *q;
+ char MyFile[512];
+ char MySuffix[16];
+ int try_core;
+ int candidate_files;
+
+ if (trailfilename != NULL)
+ { fd = fopen(trailfilename, "r");
+ if (fd == NULL)
+ { printf("pan: cannot find %s\n", trailfilename);
+ pan_exit(1);
+ } /* else */
+ goto success;
+ }
+talk:
+ try_core = 1;
+ candidate_files = 0;
+ tprefix = "trail";
+ strcpy(MyFile, TrailFile);
+ do { /* see if there's more than one possible trailfile */
+ if (whichtrail)
+ { sprintf(fnm, "%s%d.%s",
+ MyFile, whichtrail, tprefix);
+ fd = fopen(fnm, "r");
+ if (fd != NULL)
+ { candidate_files++;
+ if (verbose==100)
+ printf("trail%d: %s\n",
+ candidate_files, fnm);
+ fclose(fd);
+ }
+ if ((q = strchr(MyFile, '.')) != NULL)
+ { *q = '\0';
+ sprintf(fnm, "%s%d.%s",
+ MyFile, whichtrail, tprefix);
+ *q = '.';
+ fd = fopen(fnm, "r");
+ if (fd != NULL)
+ { candidate_files++;
+ if (verbose==100)
+ printf("trail%d: %s\n",
+ candidate_files, fnm);
+ fclose(fd);
+ } }
+ } else
+ { sprintf(fnm, "%s.%s", MyFile, tprefix);
+ fd = fopen(fnm, "r");
+ if (fd != NULL)
+ { candidate_files++;
+ if (verbose==100)
+ printf("trail%d: %s\n",
+ candidate_files, fnm);
+ fclose(fd);
+ }
+ if ((q = strchr(MyFile, '.')) != NULL)
+ { *q = '\0';
+ sprintf(fnm, "%s.%s", MyFile, tprefix);
+ *q = '.';
+ fd = fopen(fnm, "r");
+ if (fd != NULL)
+ { candidate_files++;
+ if (verbose==100)
+ printf("trail%d: %s\n",
+ candidate_files, fnm);
+ fclose(fd);
+ } } }
+ tprefix = MySuffix;
+ sprintf(tprefix, "cpu%d_trail", try_core++);
+ } while (try_core <= NCORE);
+
+ if (candidate_files != 1)
+ { if (verbose != 100)
+ { printf("error: there are %d trail files:\n",
+ candidate_files);
+ verbose = 100;
+ goto talk;
+ } else
+ { printf("pan: rm or mv all except one\n");
+ exit(1);
+ } }
+ try_core = 1;
+ strcpy(MyFile, TrailFile); /* restore */
+ tprefix = "trail";
+try_again:
+ if (whichtrail)
+ { sprintf(fnm, "%s%d.%s", MyFile, whichtrail, tprefix);
+ fd = fopen(fnm, "r");
+ if (fd == NULL && (q = strchr(MyFile, '.')))
+ { *q = '\0';
+ sprintf(fnm, "%s%d.%s",
+ MyFile, whichtrail, tprefix);
+ *q = '.';
+ fd = fopen(fnm, "r");
+ }
+ } else
+ { sprintf(fnm, "%s.%s", MyFile, tprefix);
+ fd = fopen(fnm, "r");
+ if (fd == NULL && (q = strchr(MyFile, '.')))
+ { *q = '\0';
+ sprintf(fnm, "%s.%s", MyFile, tprefix);
+ *q = '.';
+ fd = fopen(fnm, "r");
+ } }
+ if (fd == NULL)
+ { if (try_core < NCORE)
+ { tprefix = MySuffix;
+ sprintf(tprefix, "cpu%d_trail", try_core++);
+ goto try_again;
+ }
+ printf("pan: cannot find trailfile %s\n", fnm);
+ pan_exit(1);
+ }
+success:
+#if NCORE>1 && defined(SEP_STATE)
+ { void set_root(void); /* for partial traces from local root */
+ set_root();
+ }
+#endif
+ return fd;
+}
+
+uchar do_transit(Trans *, short);
+
+void
+getrail(void)
+{ FILE *fd;
+ char *q;
+ int i, t_id, lastnever=-1; short II;
+ Trans *t;
+ P0 *z;
+
+ fd = findtrail(); /* exits if unsuccessful */
+ while (fscanf(fd, "%ld:%d:%d\n", &depth, &i, &t_id) == 3)
+ { if (depth == -1)
+ printf("<<<<<START OF CYCLE>>>>>\n");
+ if (depth < 0)
+ continue;
+ if (i > now._nr_pr)
+ { printf("pan: Error, proc %d invalid pid ", i);
+ printf("transition %d\n", t_id);
+ break;
+ }
+ II = i;
+ z = (P0 *)pptr(II);
+ for (t = trans[z->_t][z->_p]; t; t = t->nxt)
+ if (t->t_id == (T_ID) t_id)
+ break;
+ if (!t)
+ { for (i = 0; i < NrStates[z->_t]; i++)
+ { t = trans[z->_t][i];
+ if (t && t->t_id == (T_ID) t_id)
+ { printf("\tRecovered at state %d\n", i);
+ z->_p = i;
+ goto recovered;
+ } }
+ printf("pan: Error, proc %d type %d state %d: ",
+ II, z->_t, z->_p);
+ printf("transition %d not found\n", t_id);
+ printf("pan: list of possible transitions in this process:\n");
+ if (z->_t >= 0 && z->_t <= _NP_)
+ for (t = trans[z->_t][z->_p]; t; t = t->nxt)
+ printf(" t_id %d -- case %d, [%s]\n",
+ t->t_id, t->forw, t->tp);
+ break; /* pan_exit(1); */
+ }
+recovered:
+ q = transmognify(t->tp);
+ if (gui) simvals[0] = '\0';
+ this = pptr(II);
+ trpt->tau |= 1;
+ if (!do_transit(t, II))
+ { if (onlyproc >= 0 && II != onlyproc)
+ goto moveon;
+ printf("pan: error, next transition UNEXECUTABLE on replay\n");
+ printf(" most likely causes: missing c_track statements\n");
+ printf(" or illegal side-effects in c_expr statements\n");
+ }
+ if (onlyproc >= 0 && II != onlyproc)
+ goto moveon;
+ if (verbose)
+ { printf("%3ld: proc %2d (%s) ", depth, II, procname[z->_t]);
+ for (i = 0; src_all[i].src; i++)
+ if (src_all[i].tp == (int) z->_t)
+ { printf(" line %3d \"%s\" ",
+ src_all[i].src[z->_p], PanSource);
+ break;
+ }
+ printf("(state %d) trans {%d,%d} [%s]\n",
+ z->_p, t_id, t->forw, q?q:"");
+ c_globals();
+ for (i = 0; i < now._nr_pr; i++)
+ { c_locals(i, ((P0 *)pptr(i))->_t);
+ }
+ } else
+ if (strcmp(procname[z->_t], ":never:") == 0)
+ { if (lastnever != (int) z->_p)
+ { for (i = 0; src_all[i].src; i++)
+ if (src_all[i].tp == (int) z->_t)
+ { printf("MSC: ~G %d\n",
+ src_all[i].src[z->_p]);
+ break;
+ }
+ if (!src_all[i].src)
+ printf("MSC: ~R %d\n", z->_p);
+ }
+ lastnever = z->_p;
+ goto sameas;
+ } else
+ if (strcmp(procname[z->_t], ":np_:") != 0)
+ {
+sameas: if (no_rck) goto moveon;
+ if (coltrace)
+ { printf("%ld: ", depth);
+ for (i = 0; i < II; i++)
+ printf("\t\t");
+ printf("%s(%d):", procname[z->_t], II);
+ printf("[%s]\n", q?q:"");
+ } else if (!silent)
+ { if (strlen(simvals) > 0) {
+ printf("%3ld: proc %2d (%s)",
+ depth, II, procname[z->_t]);
+ for (i = 0; src_all[i].src; i++)
+ if (src_all[i].tp == (int) z->_t)
+ { printf(" line %3d \"%s\" ",
+ src_all[i].src[z->_p], PanSource);
+ break;
+ }
+ printf("(state %d) [values: %s]\n", z->_p, simvals);
+ }
+ printf("%3ld: proc %2d (%s)",
+ depth, II, procname[z->_t]);
+ for (i = 0; src_all[i].src; i++)
+ if (src_all[i].tp == (int) z->_t)
+ { printf(" line %3d \"%s\" ",
+ src_all[i].src[z->_p], PanSource);
+ break;
+ }
+ printf("(state %d) [%s]\n", z->_p, q?q:"");
+ /* printf("\n"); */
+ } }
+moveon: z->_p = t->st;
+ }
+ wrap_trail();
+}
+#endif
+int
+f_pid(int pt)
+{ int i;
+ P0 *z;
+ for (i = 0; i < now._nr_pr; i++)
+ { z = (P0 *)pptr(i);
+ if (z->_t == (unsigned) pt)
+ return BASE+z->_pid;
+ }
+ return -1;
+}
+#ifdef VERI
+void check_claim(int);
+#endif
+
+#if !defined(HASH64) && !defined(HASH32)
+ #define HASH32
+#endif
+#if defined(HASH32) && defined(SAFETY) && !defined(SFH) && !defined(SPACE)
+ #define SFH
+#endif
+#if defined(SFH) && (defined(BITSTATE) || defined(COLLAPSE) || defined(HC) || defined(HASH64))
+ #undef SFH
+#endif
+#if defined(SFH) && !defined(NOCOMP)
+ #define NOCOMP /* go for speed */
+#endif
+#if NCORE>1 && !defined(GLOB_HEAP)
+ #define SEP_HEAP /* version 5.1.2 */
+#endif
+
+#ifdef BITSTATE
+int
+bstore_mod(char *v, int n) /* hasharray size not a power of two */
+{ unsigned long x, y;
+ unsigned int i = 1;
+
+ d_hash((uchar *) v, n); /* sets j3, j4, K1, K2 */
+ x = K1; y = j3;
+ for (;;)
+ { if (!(SS[x%udmem]&(1<<y))) break;
+ if (i == hfns) {
+#ifdef DEBUG
+ printf("Old bitstate\n");
+#endif
+ return 1;
+ }
+ x = (x + K2 + i);
+ y = (y + j4) & 7;
+ i++;
+ }
+#ifdef RANDSTOR
+ if (rand()%100 > RANDSTOR) return 0;
+#endif
+ for (;;)
+ { SS[x%udmem] |= (1<<y);
+ if (i == hfns) break;
+ x = (x + K2 + i);
+ y = (y + j4) & 7;
+ i++;
+ }
+#ifdef DEBUG
+ printf("New bitstate\n");
+#endif
+ if (now._a_t&1)
+ { nShadow++;
+ }
+ return 0;
+}
+int
+bstore_reg(char *v, int n) /* extended hashing, Peter Dillinger, 2004 */
+{ unsigned long x, y;
+ unsigned int i = 1;
+
+ d_hash((uchar *) v, n); /* sets j1-j4 */
+ x = j2; y = j3;
+ for (;;)
+ { if (!(SS[x]&(1<<y))) break;
+ if (i == hfns) {
+#ifdef DEBUG
+ printf("Old bitstate\n");
+#endif
+ return 1;
+ }
+ x = (x + j1 + i) & nmask;
+ y = (y + j4) & 7;
+ i++;
+ }
+#ifdef RANDSTOR
+ if (rand()%100 > RANDSTOR) return 0;
+#endif
+ for (;;)
+ { SS[x] |= (1<<y);
+ if (i == hfns) break;
+ x = (x + j1 + i) & nmask;
+ y = (y + j4) & 7;
+ i++;
+ }
+#ifdef DEBUG
+ printf("New bitstate\n");
+#endif
+ if (now._a_t&1)
+ { nShadow++;
+ }
+ return 0;
+}
+#endif
+unsigned long TMODE = 0666; /* file permission bits for trail files */
+
+int trcnt=1;
+char snap[64], fnm[512];
+
+int
+make_trail(void)
+{ int fd;
+ char *q;
+ char MyFile[512];
+ int w_flags = O_CREAT|O_WRONLY|O_TRUNC;
+
+ if (exclusive == 1 && iterative == 0)
+ { w_flags |= O_EXCL;
+ }
+
+ q = strrchr(TrailFile, '/');
+ if (q == NULL) q = TrailFile; else q++;
+ strcpy(MyFile, q); /* TrailFile is not a writable string */
+
+ if (iterative == 0 && Nr_Trails++ > 0)
+ { sprintf(fnm, "%s%d.%s",
+ MyFile, Nr_Trails-1, tprefix);
+ } else
+ {
+#ifdef PUTPID
+ sprintf(fnm, "%s%d.%s", MyFile, getpid(), tprefix);
+#else
+ sprintf(fnm, "%s.%s", MyFile, tprefix);
+#endif
+ }
+ if ((fd = open(fnm, w_flags, TMODE)) < 0)
+ { if ((q = strchr(MyFile, '.')))
+ { *q = '\0';
+ if (iterative == 0 && Nr_Trails-1 > 0)
+ sprintf(fnm, "%s%d.%s",
+ MyFile, Nr_Trails-1, tprefix);
+ else
+ sprintf(fnm, "%s.%s", MyFile, tprefix);
+ *q = '.';
+ fd = open(fnm, w_flags, TMODE);
+ } }
+ if (fd < 0)
+ { printf("pan: cannot create %s\n", fnm);
+ perror("cause");
+ } else
+ {
+#if NCORE>1 && (defined(SEP_STATE) || !defined(FULL_TRAIL))
+ void write_root(void);
+ write_root();
+#else
+ printf("pan: wrote %s\n", fnm);
+#endif
+ }
+ return fd;
+}
+
+#ifndef FREQ
+#define FREQ (1000000)
+#endif
+#ifdef BFS
+#define Q_PROVISO
+#ifndef INLINE_REV
+#define INLINE_REV
+#endif
+
+typedef struct SV_Hold {
+ State *sv;
+ int sz;
+ struct SV_Hold *nxt;
+} SV_Hold;
+
+typedef struct EV_Hold {
+ char *sv;
+ int sz;
+ int nrpr;
+ int nrqs;
+ char *po;
+ char *qo;
+ char *ps, *qs;
+ struct EV_Hold *nxt;
+} EV_Hold;
+
+typedef struct BFS_Trail {
+ Trail *frame;
+ SV_Hold *onow;
+ EV_Hold *omask;
+#ifdef Q_PROVISO
+ struct H_el *lstate;
+#endif
+ short boq;
+ struct BFS_Trail *nxt;
+} BFS_Trail;
+
+BFS_Trail *bfs_trail, *bfs_bot, *bfs_free;
+
+SV_Hold *svhold, *svfree;
+
+#ifdef BFS_DISK
+#ifndef BFS_LIMIT
+ #define BFS_LIMIT 100000
+#endif
+#ifndef BFS_DSK_LIMIT
+ #define BFS_DSK_LIMIT 1000000
+#endif
+#if defined(WIN32) || defined(WIN64)
+ #define RFLAGS (O_RDONLY|O_BINARY)
+ #define WFLAGS (O_CREAT|O_WRONLY|O_TRUNC|O_BINARY)
+#else
+ #define RFLAGS (O_RDONLY)
+ #define WFLAGS (O_CREAT|O_WRONLY|O_TRUNC)
+#endif
+long bfs_size_limit;
+int bfs_dsk_write = -1;
+int bfs_dsk_read = -1;
+long bfs_dsk_writes, bfs_dsk_reads;
+int bfs_dsk_seqno_w, bfs_dsk_seqno_r;
+#endif
+
+uchar do_reverse(Trans *, short, uchar);
+void snapshot(void);
+
+SV_Hold *
+getsv(int n)
+{ SV_Hold *h = (SV_Hold *) 0, *oh;
+
+ oh = (SV_Hold *) 0;
+ for (h = svfree; h; oh = h, h = h->nxt)
+ { if (n == h->sz)
+ { if (!oh)
+ svfree = h->nxt;
+ else
+ oh->nxt = h->nxt;
+ h->nxt = (SV_Hold *) 0;
+ break;
+ }
+ if (n < h->sz)
+ { h = (SV_Hold *) 0;
+ break;
+ }
+ /* else continue */
+ }
+
+ if (!h)
+ { h = (SV_Hold *) emalloc(sizeof(SV_Hold));
+ h->sz = n;
+#ifdef BFS_DISK
+ if (bfs_size_limit >= BFS_LIMIT)
+ { h->sv = (State *) 0; /* means: read disk */
+ bfs_dsk_writes++; /* count */
+ if (bfs_dsk_write < 0 /* file descriptor */
+ || bfs_dsk_writes%BFS_DSK_LIMIT == 0)
+ { char dsk_nm[32];
+ if (bfs_dsk_write >= 0)
+ { (void) close(bfs_dsk_write);
+ }
+ sprintf(dsk_nm, "pan_bfs_%d.tmp", bfs_dsk_seqno_w++);
+ bfs_dsk_write = open(dsk_nm, WFLAGS, 0644);
+ if (bfs_dsk_write < 0)
+ { Uerror("could not create tmp disk file");
+ }
+ printf("pan: created disk file %s\n", dsk_nm);
+ }
+ if (write(bfs_dsk_write, (char *) &now, n) != n)
+ { Uerror("aborting -- disk write failed (disk full?)");
+ }
+ return h; /* no memcpy */
+ }
+ bfs_size_limit++;
+#endif
+ h->sv = (State *) emalloc(sizeof(State) - VECTORSZ + n);
+ }
+
+ memcpy((char *)h->sv, (char *)&now, n);
+ return h;
+}
+
+EV_Hold *
+getsv_mask(int n)
+{ EV_Hold *h;
+ static EV_Hold *kept = (EV_Hold *) 0;
+
+ for (h = kept; h; h = h->nxt)
+ if (n == h->sz
+ && (memcmp((char *) Mask, (char *) h->sv, n) == 0)
+ && (now._nr_pr == h->nrpr)
+ && (now._nr_qs == h->nrqs)
+#if VECTORSZ>32000
+ && (memcmp((char *) proc_offset, (char *) h->po, now._nr_pr * sizeof(int)) == 0)
+ && (memcmp((char *) q_offset, (char *) h->qo, now._nr_qs * sizeof(int)) == 0)
+#else
+ && (memcmp((char *) proc_offset, (char *) h->po, now._nr_pr * sizeof(short)) == 0)
+ && (memcmp((char *) q_offset, (char *) h->qo, now._nr_qs * sizeof(short)) == 0)
+#endif
+ && (memcmp((char *) proc_skip, (char *) h->ps, now._nr_pr * sizeof(uchar)) == 0)
+ && (memcmp((char *) q_skip, (char *) h->qs, now._nr_qs * sizeof(uchar)) == 0))
+ break;
+ if (!h)
+ { h = (EV_Hold *) emalloc(sizeof(EV_Hold));
+ h->sz = n;
+ h->nrpr = now._nr_pr;
+ h->nrqs = now._nr_qs;
+
+ h->sv = (char *) emalloc(n * sizeof(char));
+ memcpy((char *) h->sv, (char *) Mask, n);
+
+ if (now._nr_pr > 0)
+ { h->ps = (char *) emalloc(now._nr_pr * sizeof(int));
+ memcpy((char *) h->ps, (char *) proc_skip, now._nr_pr * sizeof(uchar));
+#if VECTORSZ>32000
+ h->po = (char *) emalloc(now._nr_pr * sizeof(int));
+ memcpy((char *) h->po, (char *) proc_offset, now._nr_pr * sizeof(int));
+#else
+ h->po = (char *) emalloc(now._nr_pr * sizeof(short));
+ memcpy((char *) h->po, (char *) proc_offset, now._nr_pr * sizeof(short));
+#endif
+ }
+ if (now._nr_qs > 0)
+ { h->qs = (char *) emalloc(now._nr_qs * sizeof(int));
+ memcpy((char *) h->qs, (char *) q_skip, now._nr_qs * sizeof(uchar));
+#if VECTORSZ>32000
+ h->qo = (char *) emalloc(now._nr_qs * sizeof(int));
+ memcpy((char *) h->qo, (char *) q_offset, now._nr_qs * sizeof(int));
+#else
+ h->qo = (char *) emalloc(now._nr_qs * sizeof(short));
+ memcpy((char *) h->qo, (char *) q_offset, now._nr_qs * sizeof(short));
+#endif
+ }
+
+ h->nxt = kept;
+ kept = h;
+ }
+ return h;
+}
+
+void
+freesv(SV_Hold *p)
+{ SV_Hold *h, *oh;
+
+ oh = (SV_Hold *) 0;
+ for (h = svfree; h; oh = h, h = h->nxt)
+ if (h->sz >= p->sz)
+ break;
+
+ if (!oh)
+ { p->nxt = svfree;
+ svfree = p;
+ } else
+ { p->nxt = h;
+ oh->nxt = p;
+ }
+}
+
+BFS_Trail *
+get_bfs_frame(void)
+{ BFS_Trail *t;
+
+ if (bfs_free)
+ { t = bfs_free;
+ bfs_free = bfs_free->nxt;
+ t->nxt = (BFS_Trail *) 0;
+ } else
+ { t = (BFS_Trail *) emalloc(sizeof(BFS_Trail));
+ }
+ t->frame = (Trail *) emalloc(sizeof(Trail));
+ return t;
+}
+
+void
+push_bfs(Trail *f, int d)
+{ BFS_Trail *t;
+
+ t = get_bfs_frame();
+ memcpy((char *)t->frame, (char *)f, sizeof(Trail));
+ t->frame->o_tt = d; /* depth */
+
+ t->boq = boq;
+ t->onow = getsv(vsize);
+ t->omask = getsv_mask(vsize);
+#if defined(FULLSTACK) && defined(Q_PROVISO)
+ t->lstate = Lstate;
+#endif
+ if (!bfs_bot)
+ { bfs_bot = bfs_trail = t;
+ } else
+ { bfs_bot->nxt = t;
+ bfs_bot = t;
+ }
+#ifdef CHECK
+ printf("PUSH %u (%d)\n", t->frame, d);
+#endif
+}
+
+Trail *
+pop_bfs(void)
+{ BFS_Trail *t;
+
+ if (!bfs_trail)
+ return (Trail *) 0;
+
+ t = bfs_trail;
+ bfs_trail = t->nxt;
+ if (!bfs_trail)
+ bfs_bot = (BFS_Trail *) 0;
+#if defined(Q_PROVISO) && !defined(BITSTATE) && !defined(NOREDUCE)
+ if (t->lstate) t->lstate->tagged = 0;
+#endif
+
+ t->nxt = bfs_free;
+ bfs_free = t;
+
+ vsize = t->onow->sz;
+ boq = t->boq;
+#ifdef BFS_DISK
+ if (t->onow->sv == (State *) 0)
+ { char dsk_nm[32];
+ bfs_dsk_reads++; /* count */
+ if (bfs_dsk_read >= 0 /* file descriptor */
+ && bfs_dsk_reads%BFS_DSK_LIMIT == 0)
+ { (void) close(bfs_dsk_read);
+ sprintf(dsk_nm, "pan_bfs_%d.tmp", bfs_dsk_seqno_r-1);
+ (void) unlink(dsk_nm);
+ bfs_dsk_read = -1;
+ }
+ if (bfs_dsk_read < 0)
+ { sprintf(dsk_nm, "pan_bfs_%d.tmp", bfs_dsk_seqno_r++);
+ bfs_dsk_read = open(dsk_nm, RFLAGS);
+ if (bfs_dsk_read < 0)
+ { Uerror("could not open temp disk file");
+ } }
+ if (read(bfs_dsk_read, (char *) &now, vsize) != vsize)
+ { Uerror("bad bfs disk file read");
+ }
+#ifndef NOVSZ
+ if (now._vsz != vsize)
+ { Uerror("disk read vsz mismatch");
+ }
+#endif
+ } else
+#endif
+ memcpy((uchar *) &now, (uchar *) t->onow->sv, vsize);
+ memcpy((uchar *) Mask, (uchar *) t->omask->sv, vsize);
+ if (now._nr_pr > 0)
+#if VECTORSZ>32000
+ { memcpy((char *)proc_offset, (char *)t->omask->po, now._nr_pr * sizeof(int));
+#else
+ { memcpy((char *)proc_offset, (char *)t->omask->po, now._nr_pr * sizeof(short));
+#endif
+ memcpy((char *)proc_skip, (char *)t->omask->ps, now._nr_pr * sizeof(uchar));
+ }
+ if (now._nr_qs > 0)
+#if VECTORSZ>32000
+ { memcpy((uchar *)q_offset, (uchar *)t->omask->qo, now._nr_qs * sizeof(int));
+#else
+ { memcpy((uchar *)q_offset, (uchar *)t->omask->qo, now._nr_qs * sizeof(short));
+#endif
+ memcpy((uchar *)q_skip, (uchar *)t->omask->qs, now._nr_qs * sizeof(uchar));
+ }
+#ifdef BFS_DISK
+ if (t->onow->sv != (State *) 0)
+#endif
+ freesv(t->onow); /* omask not freed */
+#ifdef CHECK
+ printf("POP %u (%d)\n", t->frame, t->frame->o_tt);
+#endif
+ return t->frame;
+}
+
+void
+store_state(Trail *ntrpt, int shortcut, short oboq)
+{
+#ifdef VERI
+ Trans *t2 = (Trans *) 0;
+ uchar ot; int tt, E_state;
+ uchar o_opm = trpt->o_pm, *othis = this;
+
+ if (shortcut)
+ {
+#ifdef VERBOSE
+ printf("claim: shortcut\n");
+#endif
+ goto store_it; /* no claim move */
+ }
+
+ this = (((uchar *)&now)+proc_offset[0]); /* 0 = never claim */
+ trpt->o_pm = 0;
+
+ tt = (int) ((P0 *)this)->_p;
+ ot = (uchar) ((P0 *)this)->_t;
+
+#ifdef HAS_UNLESS
+ E_state = 0;
+#endif
+ for (t2 = trans[ot][tt]; t2; t2 = t2?t2->nxt:(Trans *)0)
+ {
+#ifdef HAS_UNLESS
+ if (E_state > 0
+ && E_state != t2->e_trans)
+ break;
+#endif
+ if (do_transit(t2, 0))
+ {
+#ifdef VERBOSE
+ if (!reached[ot][t2->st])
+ printf("depth: %d -- claim move from %d -> %d\n",
+ trpt->o_tt, ((P0 *)this)->_p, t2->st);
+#endif
+#ifdef HAS_UNLESS
+ E_state = t2->e_trans;
+#endif
+ if (t2->st > 0)
+ { ((P0 *)this)->_p = t2->st;
+ reached[ot][t2->st] = 1;
+#ifndef NOCLAIM
+ check_claim(t2->st);
+#endif
+ }
+ if (now._nr_pr == 0) /* claim terminated */
+ uerror("end state in claim reached");
+
+#ifdef PEG
+ peg[t2->forw]++;
+#endif
+ trpt->o_pm |= 1;
+ if (t2->atom&2)
+ Uerror("atomic in claim not supported in BFS mode");
+store_it:
+
+#endif
+
+#ifdef BITSTATE
+ if (!bstore((char *)&now, vsize))
+#else
+#ifdef MA
+ if (!gstore((char *)&now, vsize, 0))
+#else
+ if (!hstore((char *)&now, vsize))
+#endif
+#endif
+ { static long sdone = (long) 0; long ndone;
+ nstates++;
+#ifndef NOREDUCE
+ trpt->tau |= 64;
+#endif
+ ndone = (unsigned long) (nstates/((double) FREQ));
+ if (ndone != sdone && mreached%10 != 0)
+ { snapshot();
+ sdone = ndone;
+#if defined(AUTO_RESIZE) && !defined(BITSTATE) && !defined(MA)
+ if (nstates > ((double)(1<<(ssize+1))))
+ { void resize_hashtable(void);
+ resize_hashtable();
+ }
+#endif
+ }
+#if SYNC
+ if (boq != -1)
+ midrv++;
+ else if (oboq != -1)
+ { Trail *x;
+ x = (Trail *) trpt->ostate; /* pre-rv state */
+ if (x) x->o_pm |= 4; /* mark success */
+ }
+#endif
+ push_bfs(ntrpt, trpt->o_tt+1);
+ } else
+ { truncs++;
+#if !defined(NOREDUCE) && defined(FULLSTACK) && defined(Q_PROVISO)
+#if !defined(BITSTATE)
+ if (Lstate && Lstate->tagged) trpt->tau |= 64;
+#else
+ if (trpt->tau&32)
+ { BFS_Trail *tprov;
+ for (tprov = bfs_trail; tprov; tprov = tprov->nxt)
+ if (tprov->onow->sv != (State *) 0
+ && memcmp((uchar *)&now, (uchar *)tprov->onow->sv, vsize) == 0)
+ { trpt->tau |= 64;
+ break; /* state is in queue */
+ } }
+#endif
+#endif
+ }
+#ifdef VERI
+ ((P0 *)this)->_p = tt; /* reset claim */
+ if (t2)
+ do_reverse(t2, 0, 0);
+ else
+ break;
+ } }
+ this = othis;
+ trpt->o_pm = o_opm;
+#endif
+}
+
+Trail *ntrpt;
+
+void
+bfs(void)
+{ Trans *t; Trail *otrpt, *x;
+ uchar _n, _m, ot, nps = 0;
+ int tt, E_state;
+ short II, From = (short) (now._nr_pr-1), To = BASE;
+ short oboq = boq;
+
+ ntrpt = (Trail *) emalloc(sizeof(Trail));
+ trpt->ostate = (struct H_el *) 0;
+ trpt->tau = 0;
+
+ trpt->o_tt = -1;
+ store_state(ntrpt, 0, oboq); /* initial state */
+
+ while ((otrpt = pop_bfs())) /* also restores now */
+ { memcpy((char *) trpt, (char *) otrpt, sizeof(Trail));
+#if defined(C_States) && (HAS_TRACK==1)
+ c_revert((uchar *) &(now.c_state[0]));
+#endif
+ if (trpt->o_pm & 4)
+ {
+#ifdef VERBOSE
+ printf("Revisit of atomic not needed (%d)\n",
+ trpt->o_pm);
+#endif
+ continue;
+ }
+#ifndef NOREDUCE
+ nps = 0;
+#endif
+ if (trpt->o_pm == 8)
+ { revrv++;
+ if (trpt->tau&8)
+ {
+#ifdef VERBOSE
+ printf("Break atomic (pm:%d,tau:%d)\n",
+ trpt->o_pm, trpt->tau);
+#endif
+ trpt->tau &= ~8;
+ }
+#ifndef NOREDUCE
+ else if (trpt->tau&32)
+ {
+#ifdef VERBOSE
+ printf("Void preselection (pm:%d,tau:%d)\n",
+ trpt->o_pm, trpt->tau);
+#endif
+ trpt->tau &= ~32;
+ nps = 1; /* no preselection in repeat */
+ }
+#endif
+ }
+ trpt->o_pm &= ~(4|8);
+ if (trpt->o_tt > mreached)
+ { mreached = trpt->o_tt;
+ if (mreached%10 == 0)
+ { snapshot();
+ } }
+ depth = trpt->o_tt;
+ if (depth >= maxdepth)
+ {
+#if SYNC
+ Trail *x;
+ if (boq != -1)
+ { x = (Trail *) trpt->ostate;
+ if (x) x->o_pm |= 4; /* not failing */
+ }
+#endif
+ truncs++;
+ if (!warned)
+ { warned = 1;
+ printf("error: max search depth too small\n");
+ }
+ if (bounded)
+ uerror("depth limit reached");
+ continue;
+ }
+#ifndef NOREDUCE
+ if (boq == -1 && !(trpt->tau&8) && nps == 0)
+ for (II = now._nr_pr-1; II >= BASE; II -= 1)
+ {
+Pickup: this = pptr(II);
+ tt = (int) ((P0 *)this)->_p;
+ ot = (uchar) ((P0 *)this)->_t;
+ if (trans[ot][tt]->atom & 8)
+ { t = trans[ot][tt];
+ if (t->qu[0] != 0)
+ { Ccheck++;
+ if (!q_cond(II, t))
+ continue;
+ Cholds++;
+ }
+ From = To = II;
+ trpt->tau |= 32; /* preselect marker */
+#ifdef DEBUG
+ printf("%3d: proc %d PreSelected (tau=%d)\n",
+ depth, II, trpt->tau);
+#endif
+ goto MainLoop;
+ } }
+ trpt->tau &= ~32;
+#endif
+Repeat:
+ if (trpt->tau&8) /* atomic */
+ { From = To = (short ) trpt->pr;
+ nlinks++;
+ } else
+ { From = now._nr_pr-1;
+ To = BASE;
+ }
+MainLoop:
+ _n = _m = 0;
+ for (II = From; II >= To; II -= 1)
+ {
+ this = (((uchar *)&now)+proc_offset[II]);
+ tt = (int) ((P0 *)this)->_p;
+ ot = (uchar) ((P0 *)this)->_t;
+#if SYNC
+ /* no rendezvous with same proc */
+ if (boq != -1 && trpt->pr == II) continue;
+#endif
+ ntrpt->pr = (uchar) II;
+ ntrpt->st = tt;
+ trpt->o_pm &= ~1; /* no move yet */
+#ifdef EVENT_TRACE
+ trpt->o_event = now._event;
+#endif
+#ifdef HAS_PROVIDED
+ if (!provided(II, ot, tt, t)) continue;
+#endif
+#ifdef HAS_UNLESS
+ E_state = 0;
+#endif
+ for (t = trans[ot][tt]; t; t = t->nxt)
+ {
+#ifdef HAS_UNLESS
+ if (E_state > 0
+ && E_state != t->e_trans)
+ break;
+#endif
+ ntrpt->o_t = t;
+
+ oboq = boq;
+
+ if (!(_m = do_transit(t, II)))
+ continue;
+
+ trpt->o_pm |= 1; /* we moved */
+ (trpt+1)->o_m = _m; /* for unsend */
+#ifdef PEG
+ peg[t->forw]++;
+#endif
+#ifdef CHECK
+ printf("%3d: proc %d exec %d, ",
+ depth, II, t->forw);
+ printf("%d to %d, %s %s %s",
+ tt, t->st, t->tp,
+ (t->atom&2)?"atomic":"",
+ (boq != -1)?"rendez-vous":"");
+#ifdef HAS_UNLESS
+ if (t->e_trans)
+ printf(" (escapes to state %d)", t->st);
+#endif
+ printf(" %saccepting [tau=%d]\n",
+ (trpt->o_pm&2)?"":"non-", trpt->tau);
+#endif
+#ifdef HAS_UNLESS
+ E_state = t->e_trans;
+#if SYNC>0
+ if (t->e_trans > 0 && (boq != -1 /* || oboq != -1 */))
+ { fprintf(efd, "error: the use of rendezvous stmnt in the escape clause\n");
+ fprintf(efd, " of an unless stmnt is not compatible with -DBFS\n");
+ pan_exit(1);
+ }
+#endif
+#endif
+ if (t->st > 0) ((P0 *)this)->_p = t->st;
+
+ /* ptr to pred: */ ntrpt->ostate = (struct H_el *) otrpt;
+ ntrpt->st = tt;
+ if (boq == -1 && (t->atom&2)) /* atomic */
+ ntrpt->tau = 8; /* record for next move */
+ else
+ ntrpt->tau = 0;
+
+ store_state(ntrpt, (boq != -1 || (t->atom&2)), oboq);
+#ifdef EVENT_TRACE
+ now._event = trpt->o_event;
+#endif
+
+ /* undo move and continue */
+ trpt++; /* this is where ovals and ipt are set */
+ do_reverse(t, II, _m); /* restore now. */
+ trpt--;
+#ifdef CHECK
+ #if NCORE>1
+ enter_critical(GLOBAL_LOCK); /* in verbose mode only */
+ printf("cpu%d: ", core_id);
+ #endif
+ printf("%3d: proc %d ", depth, II);
+ printf("reverses %d, %d to %d,",
+ t->forw, tt, t->st);
+ printf(" %s [abit=%d,adepth=%d,",
+ t->tp, now._a_t, A_depth);
+ printf("tau=%d,%d]\n",
+ trpt->tau, (trpt-1)->tau);
+ #if NCORE>1
+ leave_critical(GLOBAL_LOCK);
+ #endif
+#endif
+ reached[ot][t->st] = 1;
+ reached[ot][tt] = 1;
+
+ ((P0 *)this)->_p = tt;
+ _n |= _m;
+ } }
+#ifndef NOREDUCE
+ /* preselected - no succ definitely outside stack */
+ if ((trpt->tau&32) && !(trpt->tau&64))
+ { From = now._nr_pr-1; To = BASE;
+#ifdef DEBUG
+ cpu_printf("%3d: proc %d UnSelected (_n=%d, tau=%d)\n",
+ depth, II+1, (int) _n, trpt->tau);
+#endif
+ _n = 0; trpt->tau &= ~32;
+ if (II >= BASE)
+ goto Pickup;
+ goto MainLoop;
+ }
+ trpt->tau &= ~(32|64);
+#endif
+ if (_n != 0)
+ continue;
+#ifdef DEBUG
+ printf("%3d: no move [II=%d, tau=%d, boq=%d, _nr_pr=%d]\n",
+ depth, II, trpt->tau, boq, now._nr_pr);
+#endif
+ if (boq != -1)
+ { failedrv++;
+ x = (Trail *) trpt->ostate; /* pre-rv state */
+ if (!x) continue; /* root state */
+ if ((x->tau&8) || (x->tau&32)) /* break atomic or preselect at parent */
+ { x->o_pm |= 8; /* mark failure */
+ this = (((uchar *)&now)+proc_offset[otrpt->pr]);
+#ifdef VERBOSE
+ printf("\treset state of %d from %d to %d\n",
+ otrpt->pr, ((P0 *)this)->_p, otrpt->st);
+#endif
+ ((P0 *)this)->_p = otrpt->st;
+ unsend(boq); /* retract rv offer */
+ boq = -1;
+ push_bfs(x, x->o_tt);
+#ifdef VERBOSE
+ printf("failed rv, repush with %d\n", x->o_pm);
+#endif
+ }
+#ifdef VERBOSE
+ else printf("failed rv, tau at parent: %d\n", x->tau);
+#endif
+ } else if (now._nr_pr > 0)
+ {
+ if ((trpt->tau&8)) /* atomic */
+ { trpt->tau &= ~(1|8); /* 1=timeout, 8=atomic */
+#ifdef DEBUG
+ printf("%3d: atomic step proc %d blocks\n",
+ depth, II+1);
+#endif
+ goto Repeat;
+ }
+
+ if (!(trpt->tau&1)) /* didn't try timeout yet */
+ { trpt->tau |= 1;
+#ifdef DEBUG
+ printf("%d: timeout\n", depth);
+#endif
+ goto MainLoop;
+ }
+#ifndef VERI
+ if (!noends && !a_cycles && !endstate())
+ uerror("invalid end state");
+#endif
+ } }
+}
+
+void
+putter(Trail *trpt, int fd)
+{ long j;
+
+ if (!trpt) return;
+
+ if (trpt != (Trail *) trpt->ostate)
+ putter((Trail *) trpt->ostate, fd);
+
+ if (trpt->o_t)
+ { sprintf(snap, "%d:%d:%d\n",
+ trcnt++, trpt->pr, trpt->o_t->t_id);
+ j = strlen(snap);
+ if (write(fd, snap, j) != j)
+ { printf("pan: error writing %s\n", fnm);
+ pan_exit(1);
+ } }
+}
+
+void
+nuerror(char *str)
+{ int fd = make_trail();
+ int j;
+
+ if (fd < 0) return;
+#ifdef VERI
+ sprintf(snap, "-2:%d:-2\n", VERI);
+ write(fd, snap, strlen(snap));
+#endif
+#ifdef MERGED
+ sprintf(snap, "-4:-4:-4\n");
+ write(fd, snap, strlen(snap));
+#endif
+ trcnt = 1;
+ putter(trpt, fd);
+ if (ntrpt->o_t)
+ { sprintf(snap, "%d:%d:%d\n",
+ trcnt++, ntrpt->pr, ntrpt->o_t->t_id);
+ j = strlen(snap);
+ if (write(fd, snap, j) != j)
+ { printf("pan: error writing %s\n", fnm);
+ pan_exit(1);
+ } }
+ close(fd);
+ if (errors >= upto && upto != 0)
+ { wrapup();
+ }
+}
+#endif
+#if NCORE>1
+#if defined(WIN32) || defined(WIN64)
+#ifndef _CONSOLE
+ #define _CONSOLE
+#endif
+ #ifdef WIN64
+#undef long
+ #endif
+#include <windows.h>
+
+ #ifdef WIN64
+ #define long long long
+ #endif
+#else
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+#endif
+
+/* code common to cygwin/linux and win32/win64: */
+
+#ifdef VERBOSE
+ #define VVERBOSE (1)
+#else
+ #define VVERBOSE (0)
+#endif
+
+/* the following values must be larger than 256 and must fit in an int */
+#define QUIT 1024 /* terminate now command */
+#define QUERY 512 /* termination status query message */
+#define QUERY_F 513 /* query failed, cannot quit */
+
+#define GN_FRAMES (int) (GWQ_SIZE / (double) sizeof(SM_frame))
+#define LN_FRAMES (int) (LWQ_SIZE / (double) sizeof(SM_frame))
+
+#ifndef VMAX
+ #define VMAX VECTORSZ
+#endif
+#ifndef PMAX
+ #define PMAX 64
+#endif
+#ifndef QMAX
+ #define QMAX 64
+#endif
+
+#if VECTORSZ>32000
+ #define OFFT int
+#else
+ #define OFFT short
+#endif
+
+#ifdef SET_SEG_SIZE
+ /* no longer usefule -- being recomputed for local heap size anyway */
+ double SEG_SIZE = (((double) SET_SEG_SIZE) * 1048576.);
+#else
+ double SEG_SIZE = (1048576.*1024.); /* 1GB default shared memory pool segments */
+#endif
+
+double LWQ_SIZE = 0.; /* initialized in main */
+
+#ifdef SET_WQ_SIZE
+ #ifdef NGQ
+ #warning SET_WQ_SIZE applies to global queue -- ignored
+ double GWQ_SIZE = 0.;
+ #else
+ double GWQ_SIZE = (((double) SET_WQ_SIZE) * 1048576.);
+ /* must match the value in pan_proxy.c, if used */
+ #endif
+#else
+ #ifdef NGQ
+ double GWQ_SIZE = 0.;
+ #else
+ double GWQ_SIZE = (128.*1048576.); /* 128 MB default queue sizes */
+ #endif
+#endif
+
+/* Crash Detection Parameters */
+#ifndef ONESECOND
+ #define ONESECOND (1<<25)
+#endif
+#ifndef SHORT_T
+ #define SHORT_T (0.1)
+#endif
+#ifndef LONG_T
+ #define LONG_T (600)
+#endif
+
+double OneSecond = (double) (ONESECOND); /* waiting for a free slot -- checks crash */
+double TenSeconds = 10. * (ONESECOND); /* waiting for a lock -- check for a crash */
+
+/* Termination Detection Params -- waiting for new state input in Get_Full_Frame */
+double Delay = ((double) SHORT_T) * (ONESECOND); /* termination detection trigger */
+double OneHour = ((double) LONG_T) * (ONESECOND); /* timeout termination detection */
+
+typedef struct SM_frame SM_frame;
+typedef struct SM_results SM_results;
+typedef struct sh_Allocater sh_Allocater;
+
+struct SM_frame { /* about 6K per slot */
+ volatile int m_vsize; /* 0 means free slot */
+ volatile int m_boq; /* >500 is a control message */
+#ifdef FULL_TRAIL
+ volatile struct Stack_Tree *m_stack; /* ptr to previous state */
+#endif
+ volatile uchar m_tau;
+ volatile uchar m_o_pm;
+ volatile int nr_handoffs; /* to compute real_depth */
+ volatile char m_now [VMAX];
+ volatile char m_Mask [(VMAX + 7)/8];
+ volatile OFFT m_p_offset[PMAX];
+ volatile OFFT m_q_offset[QMAX];
+ volatile uchar m_p_skip [PMAX];
+ volatile uchar m_q_skip [QMAX];
+#if defined(C_States) && (HAS_TRACK==1) && (HAS_STACK==1)
+ volatile uchar m_c_stack [StackSize];
+#endif
+};
+
+int proxy_pid; /* id of proxy if nonzero -- receive half */
+int store_proxy_pid;
+short remote_party;
+int proxy_pid_snd; /* id of proxy if nonzero -- send half */
+char o_cmdline[512]; /* to pass options to children */
+
+int iamin[CS_NR+NCORE]; /* non-shared */
+
+#if defined(WIN32) || defined(WIN64)
+int tas(volatile LONG *);
+
+HANDLE proxy_handle_snd; /* for Windows Create and Terminate */
+
+struct sh_Allocater { /* shared memory for states */
+ volatile char *dc_arena; /* to allocate states from */
+ volatile long pattern; /* to detect overruns */
+ volatile long dc_size; /* nr of bytes left */
+ volatile void *dc_start; /* where memory segment starts */
+ volatile void *dc_id; /* to attach, detach, remove shared memory segments */
+ volatile sh_Allocater *nxt; /* linked list of pools */
+};
+DWORD worker_pids[NCORE]; /* root mem of pids of all workers created */
+HANDLE worker_handles[NCORE]; /* for windows Create and Terminate */
+void * shmid [NR_QS]; /* return value from CreateFileMapping */
+void * shmid_M; /* shared mem for state allocation in hashtable */
+
+#ifdef SEP_STATE
+ void *shmid_X;
+#else
+ void *shmid_S; /* shared bitstate arena or hashtable */
+#endif
+#else
+int tas(volatile int *);
+
+struct sh_Allocater { /* shared memory for states */
+ volatile char *dc_arena; /* to allocate states from */
+ volatile long pattern; /* to detect overruns */
+ volatile long dc_size; /* nr of bytes left */
+ volatile char *dc_start; /* where memory segment starts */
+ volatile int dc_id; /* to attach, detach, remove shared memory segments */
+ volatile sh_Allocater *nxt; /* linked list of pools */
+};
+
+int worker_pids[NCORE]; /* root mem of pids of all workers created */
+int shmid [NR_QS]; /* return value from shmget */
+int nibis = 0; /* set after shared mem has been released */
+int shmid_M; /* shared mem for state allocation in hashtable */
+#ifdef SEP_STATE
+ long shmid_X;
+#else
+ int shmid_S; /* shared bitstate arena or hashtable */
+ volatile sh_Allocater *first_pool; /* of shared state memory */
+ volatile sh_Allocater *last_pool;
+#endif
+#endif
+
+struct SM_results { /* for shuttling back final stats */
+ volatile int m_vsize; /* avoid conflicts with frames */
+ volatile int m_boq; /* these 2 fields are not written in record_info */
+ /* probably not all fields really need to be volatile */
+ volatile double m_memcnt;
+ volatile double m_nstates;
+ volatile double m_truncs;
+ volatile double m_truncs2;
+ volatile double m_nShadow;
+ volatile double m_nlinks;
+ volatile double m_ngrabs;
+ volatile double m_nlost;
+ volatile double m_hcmp;
+ volatile double m_frame_wait;
+ volatile int m_hmax;
+ volatile int m_svmax;
+ volatile int m_smax;
+ volatile int m_mreached;
+ volatile int m_errors;
+ volatile int m_VMAX;
+ volatile short m_PMAX;
+ volatile short m_QMAX;
+ volatile uchar m_R; /* reached info for all proctypes */
+};
+
+int core_id = 0; /* internal process nr, to know which q to use */
+unsigned long nstates_put = 0; /* statistics */
+unsigned long nstates_get = 0;
+int query_in_progress = 0; /* termination detection */
+
+double free_wait = 0.; /* waiting for a free frame */
+double frame_wait = 0.; /* waiting for a full frame */
+double lock_wait = 0.; /* waiting for access to cs */
+double glock_wait[3]; /* waiting for access to global lock */
+
+char *sprefix = "rst";
+uchar was_interrupted, issued_kill, writing_trail;
+
+static SM_frame cur_Root; /* current root, to be safe with error trails */
+
+SM_frame *m_workq [NR_QS]; /* per cpu work queues + global q */
+char *shared_mem[NR_QS]; /* return value from shmat */
+#ifdef SEP_HEAP
+char *my_heap;
+long my_size;
+#endif
+volatile sh_Allocater *dc_shared; /* assigned at initialization */
+
+static int vmax_seen, pmax_seen, qmax_seen;
+static double gq_tries, gq_hasroom, gq_hasnoroom;
+
+volatile int *prfree;
+volatile int *prfull;
+volatile int *prcnt;
+volatile int *prmax;
+
+volatile int *sh_lock; /* mutual exclusion locks - in shared memory */
+volatile double *is_alive; /* to detect when processes crash */
+volatile int *grfree, *grfull, *grcnt, *grmax; /* access to shared global q */
+volatile double *gr_readmiss, *gr_writemiss;
+static int lrfree; /* used for temporary recording of slot */
+static int dfs_phase2;
+
+void mem_put(int); /* handoff state to other cpu */
+void mem_put_acc(void); /* liveness mode */
+void mem_get(void); /* get state from work queue */
+void sudden_stop(char *);
+#if 0
+void enter_critical(int);
+void leave_critical(int);
+#endif
+
+void
+record_info(SM_results *r)
+{ int i;
+ uchar *ptr;
+
+#ifdef SEP_STATE
+ if (0)
+ { cpu_printf("nstates %g nshadow %g -- memory %-6.3f Mb\n",
+ nstates, nShadow, memcnt/(1048576.));
+ }
+ r->m_memcnt = 0;
+#else
+ #ifdef BITSTATE
+ r->m_memcnt = 0; /* it's shared */
+ #endif
+ r->m_memcnt = memcnt;
+#endif
+ if (a_cycles && core_id == 1)
+ { r->m_nstates = nstates;
+ r->m_nShadow = nstates;
+ } else
+ { r->m_nstates = nstates;
+ r->m_nShadow = nShadow;
+ }
+ r->m_truncs = truncs;
+ r->m_truncs2 = truncs2;
+ r->m_nlinks = nlinks;
+ r->m_ngrabs = ngrabs;
+ r->m_nlost = nlost;
+ r->m_hcmp = hcmp;
+ r->m_frame_wait = frame_wait;
+ r->m_hmax = hmax;
+ r->m_svmax = svmax;
+ r->m_smax = smax;
+ r->m_mreached = mreached;
+ r->m_errors = errors;
+ r->m_VMAX = vmax_seen;
+ r->m_PMAX = (short) pmax_seen;
+ r->m_QMAX = (short) qmax_seen;
+ ptr = (uchar *) &(r->m_R);
+ for (i = 0; i <= _NP_; i++) /* all proctypes */
+ { memcpy(ptr, reached[i], NrStates[i]*sizeof(uchar));
+ ptr += NrStates[i]*sizeof(uchar);
+ }
+ if (verbose>1)
+ { cpu_printf("Put Results nstates %g (sz %d)\n", nstates, ptr - &(r->m_R));
+ }
+}
+
+void snapshot(void);
+
+void
+retrieve_info(SM_results *r)
+{ int i, j;
+ volatile uchar *ptr;
+
+ snapshot(); /* for a final report */
+
+ enter_critical(GLOBAL_LOCK);
+#ifdef SEP_HEAP
+ if (verbose)
+ { printf("cpu%d: local heap-left %ld KB (%d MB)\n",
+ core_id, (int) (my_size/1024), (int) (my_size/1048576));
+ }
+#endif
+ if (verbose && core_id == 0)
+ { printf("qmax: ");
+ for (i = 0; i < NCORE; i++)
+ { printf("%d ", prmax[i]);
+ }
+#ifndef NGQ
+ printf("G: %d", *grmax);
+#endif
+ printf("\n");
+ }
+ leave_critical(GLOBAL_LOCK);
+
+ memcnt += r->m_memcnt;
+ nstates += r->m_nstates;
+ nShadow += r->m_nShadow;
+ truncs += r->m_truncs;
+ truncs2 += r->m_truncs2;
+ nlinks += r->m_nlinks;
+ ngrabs += r->m_ngrabs;
+ nlost += r->m_nlost;
+ hcmp += r->m_hcmp;
+ /* frame_wait += r->m_frame_wait; */
+ errors += r->m_errors;
+
+ if (hmax < r->m_hmax) hmax = r->m_hmax;
+ if (svmax < r->m_svmax) svmax = r->m_svmax;
+ if (smax < r->m_smax) smax = r->m_smax;
+ if (mreached < r->m_mreached) mreached = r->m_mreached;
+
+ if (vmax_seen < r->m_VMAX) vmax_seen = r->m_VMAX;
+ if (pmax_seen < (int) r->m_PMAX) pmax_seen = (int) r->m_PMAX;
+ if (qmax_seen < (int) r->m_QMAX) qmax_seen = (int) r->m_QMAX;
+
+ ptr = &(r->m_R);
+ for (i = 0; i <= _NP_; i++) /* all proctypes */
+ { for (j = 0; j < NrStates[i]; j++)
+ { if (*(ptr + j) != 0)
+ { reached[i][j] = 1;
+ } }
+ ptr += NrStates[i]*sizeof(uchar);
+ }
+ if (verbose>1)
+ { cpu_printf("Got Results (%d)\n", ptr - &(r->m_R));
+ snapshot();
+ }
+}
+
+#if !defined(WIN32) && !defined(WIN64)
+static void
+rm_shared_segments(void)
+{ int m;
+ volatile sh_Allocater *nxt_pool;
+ /*
+ * mark all shared memory segments for removal
+ * the actual removes wont happen intil last process dies or detaches
+ * the shmctl calls can return -1 if not all procs have detached yet
+ */
+ for (m = 0; m < NR_QS; m++) /* +1 for global q */
+ { if (shmid[m] != -1)
+ { (void) shmctl(shmid[m], IPC_RMID, NULL);
+ } }
+#ifdef SEP_STATE
+ if (shmid_M != -1)
+ { (void) shmctl(shmid_M, IPC_RMID, NULL);
+ }
+#else
+ if (shmid_S != -1)
+ { (void) shmctl(shmid_S, IPC_RMID, NULL);
+ }
+ for (last_pool = first_pool; last_pool != NULL; last_pool = nxt_pool)
+ { shmid_M = (int) (last_pool->dc_id);
+ nxt_pool = last_pool->nxt; /* as a pre-caution only */
+ if (shmid_M != -1)
+ { (void) shmctl(shmid_M, IPC_RMID, NULL);
+ } }
+#endif
+}
+#endif
+
+void
+sudden_stop(char *s)
+{ char b[64];
+ int i;
+
+ printf("cpu%d: stop - %s\n", core_id, s);
+#if !defined(WIN32) && !defined(WIN64)
+ if (proxy_pid != 0)
+ { rm_shared_segments();
+ }
+#endif
+ if (search_terminated != NULL)
+ { if (*search_terminated != 0)
+ { if (verbose)
+ { printf("cpu%d: termination initiated (%d)\n",
+ core_id, *search_terminated);
+ }
+ } else
+ { if (verbose)
+ { printf("cpu%d: initiated termination\n", core_id);
+ }
+ *search_terminated |= 8; /* sudden_stop */
+ }
+ if (core_id == 0)
+ { if (((*search_terminated) & 4) /* uerror in one of the cpus */
+ && !((*search_terminated) & (8|32|128|256))) /* abnormal stop */
+ { if (errors == 0) errors++; /* we know there is at least 1 */
+ }
+ wrapup(); /* incomplete stats, but at least something */
+ }
+ return;
+ } /* else: should rarely happen, take more drastic measures */
+
+ if (core_id == 0) /* local root process */
+ { for (i = 1; i < NCORE; i++) /* not for 0 of course */
+ {
+#if defined(WIN32) || defined(WIN64)
+ DWORD dwExitCode = 0;
+ GetExitCodeProcess(worker_handles[i], &dwExitCode);
+ if (dwExitCode == STILL_ACTIVE)
+ { TerminateProcess(worker_handles[i], 0);
+ }
+ printf("cpu0: terminate %d %d\n",
+ worker_pids[i], (dwExitCode == STILL_ACTIVE));
+#else
+ sprintf(b, "kill -%d %d", SIGKILL, worker_pids[i]);
+ system(b); /* if this is a proxy: receive half */
+ printf("cpu0: %s\n", b);
+#endif
+ }
+ issued_kill++;
+ } else
+ { /* on WIN32/WIN64 -- these merely kills the root process... */
+ if (was_interrupted == 0)
+ { sprintf(b, "kill -%d %d", SIGINT, worker_pids[0]);
+ system(b); /* warn the root process */
+ printf("cpu%d: %s\n", core_id, b);
+ issued_kill++;
+ } }
+}
+
+#define iam_alive() is_alive[core_id]++
+
+extern int crash_test(double);
+extern void crash_reset(void);
+
+int
+someone_crashed(int wait_type)
+{ static double last_value = 0.0;
+ static int count = 0;
+
+ if (search_terminated == NULL
+ || *search_terminated != 0)
+ {
+ if (!(*search_terminated & (8|32|128|256)))
+ { if (count++ < 100*NCORE)
+ { return 0;
+ } }
+ return 1;
+ }
+ /* check left neighbor only */
+ if (last_value == is_alive[(core_id + NCORE - 1) % NCORE])
+ { if (count++ >= 100) /* to avoid unnecessary checks */
+ { return 1;
+ }
+ return 0;
+ }
+ last_value = is_alive[(core_id + NCORE - 1) % NCORE];
+ count = 0;
+ crash_reset();
+ return 0;
+}
+
+void
+sleep_report(void)
+{
+ enter_critical(GLOBAL_LOCK);
+ if (verbose)
+ {
+#ifdef NGQ
+ printf("cpu%d: locks: global %g\tother %g\t",
+ core_id, glock_wait[0], lock_wait - glock_wait[0]);
+#else
+ printf("cpu%d: locks: GL %g, RQ %g, WQ %g, HT %g\t",
+ core_id, glock_wait[0], glock_wait[1], glock_wait[2],
+ lock_wait - glock_wait[0] - glock_wait[1] - glock_wait[2]);
+#endif
+ printf("waits: states %g slots %g\n", frame_wait, free_wait);
+#ifndef NGQ
+ printf("cpu%d: gq [tries %g, room %g, noroom %g]\n", core_id, gq_tries, gq_hasroom, gq_hasnoroom);
+ if (core_id == 0 && (*gr_readmiss >= 1.0 || *gr_readmiss >= 1.0 || *grcnt != 0))
+ printf("cpu0: gq [readmiss: %g, writemiss: %g cnt %d]\n", *gr_readmiss, *gr_writemiss, *grcnt);
+#endif
+ }
+ if (free_wait > 1000000.)
+ #ifndef NGQ
+ if (!a_cycles)
+ { printf("hint: this search may be faster with a larger work-queue\n");
+ printf(" (-DSET_WQ_SIZE=N with N>%g), and/or with -DUSE_DISK\n",
+ GWQ_SIZE/sizeof(SM_frame));
+ printf(" or with a larger value for -zN (N>%d)\n", z_handoff);
+ #else
+ { printf("hint: this search may be faster if compiled without -DNGQ, with -DUSE_DISK, ");
+ printf("or with a larger -zN (N>%d)\n", z_handoff);
+ #endif
+ }
+ leave_critical(GLOBAL_LOCK);
+}
+
+#ifndef MAX_DSK_FILE
+ #define MAX_DSK_FILE 1000000 /* default is max 1M states per file */
+#endif
+
+void
+multi_usage(FILE *fd)
+{ static int warned = 0;
+ if (warned > 0) { return; } else { warned++; }
+ fprintf(fd, "\n");
+ fprintf(fd, "Defining multi-core mode:\n\n");
+ fprintf(fd, " -DDUAL_CORE --> same as -DNCORE=2\n");
+ fprintf(fd, " -DQUAD_CORE --> same as -DNCORE=4\n");
+ fprintf(fd, " -DNCORE=N --> enables multi_core verification if N>1\n");
+ fprintf(fd, "\n");
+ fprintf(fd, "Additional directives supported in multi-core mode:\n\n");
+ fprintf(fd, " -DSEP_STATE --> forces separate statespaces instead of a single shared state space\n");
+ fprintf(fd, " -DNUSE_DISK --> use disk for storing states when a work queue overflows\n");
+ fprintf(fd, " -DMAX_DSK_FILE --> max nr of states per diskfile (%d)\n", MAX_DSK_FILE);
+ fprintf(fd, " -DFULL_TRAIL --> support full error trails (increases memory use)\n");
+ fprintf(fd, "\n");
+ fprintf(fd, "More advanced use (should rarely need changing):\n\n");
+ fprintf(fd, " To change the nr of states that can be stored in the global queue\n");
+ fprintf(fd, " (lower numbers allow for more states to be stored, prefer multiples of 8):\n");
+ fprintf(fd, " -DVMAX=N --> upperbound on statevector for handoffs (N=%d)\n", VMAX);
+ fprintf(fd, " -DPMAX=N --> upperbound on nr of procs (default: N=%d)\n", PMAX);
+ fprintf(fd, " -DQMAX=N --> upperbound on nr of channels (default: N=%d)\n", QMAX);
+ fprintf(fd, "\n");
+ fprintf(fd, " To set the total amount of memory reserved for the global workqueue:\n");
+ fprintf(fd, " -DSET_WQ_SIZE=N --> default: N=128 (defined in MBytes)\n\n");
+ fprintf(fd, " To force the use of a single global heap, instead of separate heaps:\n");
+ fprintf(fd, " -DGLOB_HEAP\n");
+ fprintf(fd, "\n");
+ fprintf(fd, " To define a fct to initialize data before spawning processes (use quotes):\n");
+ fprintf(fd, " \"-DC_INIT=fct()\"\n");
+ fprintf(fd, "\n");
+ fprintf(fd, " Timer settings for termination and crash detection:\n");
+ fprintf(fd, " -DSHORT_T=N --> timeout for termination detection trigger (N=%g)\n", (double) SHORT_T);
+ fprintf(fd, " -DLONG_T=N --> timeout for giving up on termination detection (N=%g)\n", (double) LONG_T);
+ fprintf(fd, " -DONESECOND --> (1<<29) --> timeout waiting for a free slot -- to check for crash\n");
+ fprintf(fd, " -DT_ALERT --> collect stats on crash alert timeouts\n\n");
+ fprintf(fd, "Help with Linux/Windows/Cygwin configuration for multi-core:\n");
+ fprintf(fd, " http://spinroot.com/spin/multicore/V5_Readme.html\n");
+ fprintf(fd, "\n");
+}
+#if NCORE>1 && defined(FULL_TRAIL)
+typedef struct Stack_Tree {
+ uchar pr; /* process that made transition */
+ T_ID t_id; /* id of transition */
+ volatile struct Stack_Tree *prv; /* backward link towards root */
+} Stack_Tree;
+
+struct H_el *grab_shared(int);
+volatile Stack_Tree **stack_last; /* in shared memory */
+char *stack_cache = NULL; /* local */
+int nr_cached = 0; /* local */
+
+#ifndef CACHE_NR
+ #define CACHE_NR 1024
+#endif
+
+volatile Stack_Tree *
+stack_prefetch(void)
+{ volatile Stack_Tree *st;
+
+ if (nr_cached == 0)
+ { stack_cache = (char *) grab_shared(CACHE_NR * sizeof(Stack_Tree));
+ nr_cached = CACHE_NR;
+ }
+ st = (volatile Stack_Tree *) stack_cache;
+ stack_cache += sizeof(Stack_Tree);
+ nr_cached--;
+ return st;
+}
+
+void
+Push_Stack_Tree(short II, T_ID t_id)
+{ volatile Stack_Tree *st;
+
+ st = (volatile Stack_Tree *) stack_prefetch();
+ st->pr = II;
+ st->t_id = t_id;
+ st->prv = (Stack_Tree *) stack_last[core_id];
+ stack_last[core_id] = st;
+}
+
+void
+Pop_Stack_Tree(void)
+{ volatile Stack_Tree *cf = stack_last[core_id];
+
+ if (cf)
+ { stack_last[core_id] = cf->prv;
+ } else if (nr_handoffs * z_handoff + depth > 0)
+ { printf("cpu%d: error pop_stack_tree (depth %d)\n",
+ core_id, depth);
+ }
+}
+#endif
+
+void
+e_critical(int which)
+{ double cnt_start;
+
+ if (readtrail || iamin[which] > 0)
+ { if (!readtrail && verbose)
+ { printf("cpu%d: Double Lock on %d (now %d)\n",
+ core_id, which, iamin[which]+1);
+ fflush(stdout);
+ }
+ iamin[which]++; /* local variable */
+ return;
+ }
+
+ cnt_start = lock_wait;
+
+ while (sh_lock != NULL) /* as long as we have shared memory */
+ { int r = tas(&sh_lock[which]);
+ if (r == 0)
+ { iamin[which] = 1;
+ return; /* locked */
+ }
+
+ lock_wait++;
+#ifndef NGQ
+ if (which < 3) { glock_wait[which]++; }
+#else
+ if (which == 0) { glock_wait[which]++; }
+#endif
+ iam_alive();
+
+ if (lock_wait - cnt_start > TenSeconds)
+ { printf("cpu%d: lock timeout on %d\n", core_id, which);
+ cnt_start = lock_wait;
+ if (someone_crashed(1))
+ { sudden_stop("lock timeout");
+ pan_exit(1);
+ } } }
+}
+
+void
+x_critical(int which)
+{
+ if (iamin[which] != 1)
+ { if (iamin[which] > 1)
+ { iamin[which]--; /* this is thread-local - no races on this one */
+ if (!readtrail && verbose)
+ { printf("cpu%d: Partial Unlock on %d (%d more needed)\n",
+ core_id, which, iamin[which]);
+ fflush(stdout);
+ }
+ return;
+ } else /* iamin[which] <= 0 */
+ { if (!readtrail)
+ { printf("cpu%d: Invalid Unlock iamin[%d] = %d\n",
+ core_id, which, iamin[which]);
+ fflush(stdout);
+ }
+ return;
+ } }
+
+ if (sh_lock != NULL)
+ { iamin[which] = 0;
+ sh_lock[which] = 0; /* unlock */
+ }
+}
+
+void
+#if defined(WIN32) || defined(WIN64)
+start_proxy(char *s, DWORD r_pid)
+#else
+start_proxy(char *s, int r_pid)
+#endif
+{ char Q_arg[16], Z_arg[16], Y_arg[16];
+ char *args[32], *ptr;
+ int argcnt = 0;
+
+ sprintf(Q_arg, "-Q%d", getpid());
+ sprintf(Y_arg, "-Y%d", r_pid);
+ sprintf(Z_arg, "-Z%d", proxy_pid /* core_id */);
+
+ args[argcnt++] = "proxy";
+ args[argcnt++] = s; /* -r or -s */
+ args[argcnt++] = Q_arg;
+ args[argcnt++] = Z_arg;
+ args[argcnt++] = Y_arg;
+
+ if (strlen(o_cmdline) > 0)
+ { ptr = o_cmdline; /* assume args separated by spaces */
+ do { args[argcnt++] = ptr++;
+ if ((ptr = strchr(ptr, ' ')) != NULL)
+ { while (*ptr == ' ')
+ { *ptr++ = '\0';
+ }
+ } else
+ { break;
+ }
+ } while (argcnt < 31);
+ }
+ args[argcnt] = NULL;
+#if defined(WIN32) || defined(WIN64)
+ execvp("pan_proxy", args); /* no return */
+#else
+ execvp("./pan_proxy", args); /* no return */
+#endif
+ Uerror("pan_proxy exec failed");
+}
+/*** end of common code fragment ***/
+
+#if !defined(WIN32) && !defined(WIN64)
+void
+init_shm(void) /* initialize shared work-queues - linux/cygwin */
+{ key_t key[NR_QS];
+ int n, m;
+ int must_exit = 0;
+
+ if (core_id == 0 && verbose)
+ { printf("cpu0: step 3: allocate shared workqueues %g MB\n",
+ ((double) NCORE * LWQ_SIZE + GWQ_SIZE) / (1048576.) );
+ }
+ for (m = 0; m < NR_QS; m++) /* last q is the global q */
+ { double qsize = (m == NCORE) ? GWQ_SIZE : LWQ_SIZE;
+ key[m] = ftok(PanSource, m+1);
+ if (key[m] == -1)
+ { perror("ftok shared queues"); must_exit = 1; break;
+ }
+
+ if (core_id == 0) /* root creates */
+ { /* check for stale copy */
+ shmid[m] = shmget(key[m], (size_t) qsize, 0600);
+ if (shmid[m] != -1) /* yes there is one; remove it */
+ { printf("cpu0: removing stale q%d, status: %d\n",
+ m, shmctl(shmid[m], IPC_RMID, NULL));
+ }
+ shmid[m] = shmget(key[m], (size_t) qsize, 0600|IPC_CREAT|IPC_EXCL);
+ memcnt += qsize;
+ } else /* workers attach */
+ { shmid[m] = shmget(key[m], (size_t) qsize, 0600);
+ /* never called, since we create shm *before* we fork */
+ }
+ if (shmid[m] == -1)
+ { perror("shmget shared queues"); must_exit = 1; break;
+ }
+
+ shared_mem[m] = (char *) shmat(shmid[m], (void *) 0, 0); /* attach */
+ if (shared_mem[m] == (char *) -1)
+ { fprintf(stderr, "error: cannot attach shared wq %d (%d Mb)\n",
+ m+1, (int) (qsize/(1048576.)));
+ perror("shmat shared queues"); must_exit = 1; break;
+ }
+
+ m_workq[m] = (SM_frame *) shared_mem[m];
+ if (core_id == 0)
+ { int nframes = (m == NCORE) ? GN_FRAMES : LN_FRAMES;
+ for (n = 0; n < nframes; n++)
+ { m_workq[m][n].m_vsize = 0;
+ m_workq[m][n].m_boq = 0;
+ } } }
+
+ if (must_exit)
+ { rm_shared_segments();
+ fprintf(stderr, "pan: check './pan --' for usage details\n");
+ pan_exit(1); /* calls cleanup_shm */
+ }
+}
+
+static uchar *
+prep_shmid_S(size_t n) /* either sets SS or H_tab, linux/cygwin */
+{ char *rval;
+#ifndef SEP_STATE
+ key_t key;
+
+ if (verbose && core_id == 0)
+ {
+ #ifdef BITSTATE
+ printf("cpu0: step 1: allocate shared bitstate %g Mb\n",
+ (double) n / (1048576.));
+ #else
+ printf("cpu0: step 1: allocate shared hastable %g Mb\n",
+ (double) n / (1048576.));
+ #endif
+ }
+ #ifdef MEMLIM
+ if (memcnt + (double) n > memlim)
+ { printf("cpu0: S %8g + %d Kb exceeds memory limit of %8g Mb\n",
+ memcnt/1024., n/1024, memlim/(1048576.));
+ printf("cpu0: insufficient memory -- aborting\n");
+ exit(1);
+ }
+ #endif
+
+ key = ftok(PanSource, NCORE+2); /* different from queues */
+ if (key == -1)
+ { perror("ftok shared bitstate or hashtable");
+ fprintf(stderr, "pan: check './pan --' for usage details\n");
+ pan_exit(1);
+ }
+
+ if (core_id == 0) /* root */
+ { shmid_S = shmget(key, n, 0600);
+ if (shmid_S != -1)
+ { printf("cpu0: removing stale segment, status: %d\n",
+ shmctl(shmid_S, IPC_RMID, NULL));
+ }
+ shmid_S = shmget(key, n, 0600 | IPC_CREAT | IPC_EXCL);
+ memcnt += (double) n;
+ } else /* worker */
+ { shmid_S = shmget(key, n, 0600);
+ }
+ if (shmid_S == -1)
+ { perror("shmget shared bitstate or hashtable too large?");
+ fprintf(stderr, "pan: check './pan --' for usage details\n");
+ pan_exit(1);
+ }
+
+ rval = (char *) shmat(shmid_S, (void *) 0, 0); /* attach */
+ if ((char *) rval == (char *) -1)
+ { perror("shmat shared bitstate or hashtable");
+ fprintf(stderr, "pan: check './pan --' for usage details\n");
+ pan_exit(1);
+ }
+#else
+ rval = (char *) emalloc(n);
+#endif
+ return (uchar *) rval;
+}
+
+#define TRY_AGAIN 1
+#define NOT_AGAIN 0
+
+static char shm_prep_result;
+
+static uchar *
+prep_state_mem(size_t n) /* sets memory arena for states linux/cygwin */
+{ char *rval;
+ key_t key;
+ static int cnt = 3; /* start larger than earlier ftok calls */
+
+ shm_prep_result = NOT_AGAIN; /* default */
+ if (verbose && core_id == 0)
+ { printf("cpu0: step 2+: pre-allocate memory arena %d of %6.2g Mb\n",
+ cnt-3, (double) n / (1048576.));
+ }
+ #ifdef MEMLIM
+ if (memcnt + (double) n > memlim)
+ { printf("cpu0: error: M %.0f + %.0f Kb exceeds memory limit of %.0f Mb\n",
+ memcnt/1024.0, (double) n/1024.0, memlim/(1048576.));
+ return NULL;
+ }
+ #endif
+
+ key = ftok(PanSource, NCORE+cnt); cnt++;
+ if (key == -1)
+ { perror("ftok T");
+ printf("pan: check './pan --' for usage details\n");
+ pan_exit(1);
+ }
+
+ if (core_id == 0)
+ { shmid_M = shmget(key, n, 0600);
+ if (shmid_M != -1)
+ { printf("cpu0: removing stale memory segment %d, status: %d\n",
+ cnt-3, shmctl(shmid_M, IPC_RMID, NULL));
+ }
+ shmid_M = shmget(key, n, 0600 | IPC_CREAT | IPC_EXCL);
+ /* memcnt += (double) n; -- only amount actually used is counted */
+ } else
+ { shmid_M = shmget(key, n, 0600);
+
+ }
+ if (shmid_M == -1)
+ { if (verbose)
+ { printf("error: failed to get pool of shared memory %d of %.0f Mb\n",
+ cnt-3, ((double)n)/(1048576.));
+ perror("state mem");
+ printf("pan: check './pan --' for usage details\n");
+ }
+ shm_prep_result = TRY_AGAIN;
+ return NULL;
+ }
+ rval = (char *) shmat(shmid_M, (void *) 0, 0); /* attach */
+
+ if ((char *) rval == (char *) -1)
+ { printf("cpu%d error: failed to attach pool of shared memory %d of %.0f Mb\n",
+ core_id, cnt-3, ((double)n)/(1048576.));
+ perror("state mem");
+ return NULL;
+ }
+ return (uchar *) rval;
+}
+
+void
+init_HT(unsigned long n) /* cygwin/linux version */
+{ volatile char *x;
+ double get_mem;
+#ifndef SEP_STATE
+ volatile char *dc_mem_start;
+ double need_mem, got_mem = 0.;
+#endif
+
+#ifdef SEP_STATE
+ #ifndef MEMLIM
+ if (verbose)
+ { printf("cpu0: steps 0,1: no -DMEMLIM set\n");
+ }
+ #else
+ if (verbose)
+ { printf("cpu0: steps 0,1: -DMEMLIM=%d Mb - (hashtable %g Mb + workqueues %g Mb)\n",
+ MEMLIM, ((double)n/(1048576.)), (((double) NCORE * LWQ_SIZE) + GWQ_SIZE) /(1048576.) );
+ }
+ #endif
+ get_mem = NCORE * sizeof(double) + (1 + CS_NR) * sizeof(void *) + 4*sizeof(void *) + 2*sizeof(double);
+ /* NCORE * is_alive + search_terminated + CS_NR * sh_lock + 6 gr vars */
+ get_mem += 4 * NCORE * sizeof(void *); /* prfree, prfull, prcnt, prmax */
+ #ifdef FULL_TRAIL
+ get_mem += (NCORE) * sizeof(Stack_Tree *); /* NCORE * stack_last */
+ #endif
+ x = (volatile char *) prep_state_mem((size_t) get_mem); /* work queues and basic structs */
+ shmid_X = (long) x;
+ if (x == NULL)
+ { printf("cpu0: could not allocate shared memory, see ./pan --\n");
+ exit(1);
+ }
+ search_terminated = (volatile unsigned int *) x; /* comes first */
+ x += sizeof(void *); /* maintain alignment */
+
+ is_alive = (volatile double *) x;
+ x += NCORE * sizeof(double);
+
+ sh_lock = (volatile int *) x;
+ x += CS_NR * sizeof(void *);
+
+ grfree = (volatile int *) x;
+ x += sizeof(void *);
+ grfull = (volatile int *) x;
+ x += sizeof(void *);
+ grcnt = (volatile int *) x;
+ x += sizeof(void *);
+ grmax = (volatile int *) x;
+ x += sizeof(void *);
+ prfree = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prfull = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prcnt = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prmax = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ gr_readmiss = (volatile double *) x;
+ x += sizeof(double);
+ gr_writemiss = (volatile double *) x;
+ x += sizeof(double);
+
+ #ifdef FULL_TRAIL
+ stack_last = (volatile Stack_Tree **) x;
+ x += NCORE * sizeof(Stack_Tree *);
+ #endif
+
+ #ifndef BITSTATE
+ H_tab = (struct H_el **) emalloc(n);
+ #endif
+#else
+ #ifndef MEMLIM
+ #warning MEMLIM not set
+ #define MEMLIM (2048)
+ #endif
+
+ if (core_id == 0 && verbose)
+ { printf("cpu0: step 0: -DMEMLIM=%d Mb minus hashtable+workqs (%g + %g Mb) leaves %g Mb\n",
+ MEMLIM, ((double)n/(1048576.)), (NCORE * LWQ_SIZE + GWQ_SIZE)/(1048576.),
+ (memlim - memcnt - (double) n - (NCORE * LWQ_SIZE + GWQ_SIZE))/(1048576.));
+ }
+ #ifndef BITSTATE
+ H_tab = (struct H_el **) prep_shmid_S((size_t) n); /* hash_table */
+ #endif
+ need_mem = memlim - memcnt - ((double) NCORE * LWQ_SIZE) - GWQ_SIZE;
+ if (need_mem <= 0.)
+ { Uerror("internal error -- shared state memory");
+ }
+
+ if (core_id == 0 && verbose)
+ { printf("cpu0: step 2: pre-allocate shared state memory %g Mb\n",
+ need_mem/(1048576.));
+ }
+#ifdef SEP_HEAP
+ SEG_SIZE = need_mem / NCORE;
+ if (verbose && core_id == 0)
+ { printf("cpu0: setting segsize to %6g MB\n",
+ SEG_SIZE/(1048576.));
+ }
+ #if defined(CYGWIN) || defined(__CYGWIN__)
+ if (SEG_SIZE > 512.*1024.*1024.)
+ { printf("warning: reducing SEG_SIZE of %g MB to 512MB (exceeds max for Cygwin)\n",
+ SEG_SIZE/(1024.*1024.));
+ SEG_SIZE = 512.*1024.*1024.;
+ }
+ #endif
+#endif
+ mem_reserved = need_mem;
+ while (need_mem > 1024.)
+ { get_mem = need_mem;
+shm_more:
+ if (get_mem > (double) SEG_SIZE)
+ { get_mem = (double) SEG_SIZE;
+ }
+ if (get_mem <= 0.0) break;
+
+ /* for allocating states: */
+ x = dc_mem_start = (volatile char *) prep_state_mem((size_t) get_mem);
+ if (x == NULL)
+ { if (shm_prep_result == NOT_AGAIN
+ || first_pool != NULL
+ || SEG_SIZE < (16. * 1048576.))
+ { break;
+ }
+ SEG_SIZE /= 2.;
+ if (verbose)
+ { printf("pan: lowered segsize to 0.000000\n", SEG_SIZE);
+ }
+ if (SEG_SIZE >= 1024.)
+ { goto shm_more;
+ }
+ break;
+ }
+
+ need_mem -= get_mem;
+ got_mem += get_mem;
+ if (first_pool == NULL)
+ { search_terminated = (volatile unsigned int *) x; /* comes first */
+ x += sizeof(void *); /* maintain alignment */
+
+ is_alive = (volatile double *) x;
+ x += NCORE * sizeof(double);
+
+ sh_lock = (volatile int *) x;
+ x += CS_NR * sizeof(void *);
+
+ grfree = (volatile int *) x;
+ x += sizeof(void *);
+ grfull = (volatile int *) x;
+ x += sizeof(void *);
+ grcnt = (volatile int *) x;
+ x += sizeof(void *);
+ grmax = (volatile int *) x;
+ x += sizeof(void *);
+ prfree = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prfull = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prcnt = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prmax = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ gr_readmiss = (volatile double *) x;
+ x += sizeof(double);
+ gr_writemiss = (volatile double *) x;
+ x += sizeof(double);
+ #ifdef FULL_TRAIL
+ stack_last = (volatile Stack_Tree **) x;
+ x += NCORE * sizeof(Stack_Tree *);
+ #endif
+ if (((long)x)&(sizeof(void *)-1)) /* 64-bit word alignment */
+ { x += sizeof(void *)-(((long)x)&(sizeof(void *)-1));
+ }
+
+ #ifdef COLLAPSE
+ ncomps = (unsigned long *) x;
+ x += (256+2) * sizeof(unsigned long);
+ #endif
+ }
+
+ dc_shared = (sh_Allocater *) x; /* must be in shared memory */
+ x += sizeof(sh_Allocater);
+
+ if (core_id == 0) /* root only */
+ { dc_shared->dc_id = shmid_M;
+ dc_shared->dc_start = dc_mem_start;
+ dc_shared->dc_arena = x;
+ dc_shared->pattern = 1234567; /* protection */
+ dc_shared->dc_size = (long) get_mem - (long) (x - dc_mem_start);
+ dc_shared->nxt = (long) 0;
+
+ if (last_pool == NULL)
+ { first_pool = last_pool = dc_shared;
+ } else
+ { last_pool->nxt = dc_shared;
+ last_pool = dc_shared;
+ }
+ } else if (first_pool == NULL)
+ { first_pool = dc_shared;
+ } }
+
+ if (need_mem > 1024.)
+ { printf("cpu0: could allocate only %g Mb of shared memory (wanted %g more)\n",
+ got_mem/(1048576.), need_mem/(1048576.));
+ }
+
+ if (!first_pool)
+ { printf("cpu0: insufficient memory -- aborting.\n");
+ exit(1);
+ }
+ /* we are still single-threaded at this point, with core_id 0 */
+ dc_shared = first_pool;
+
+#endif
+}
+
+ /* Test and Set assembly code */
+
+ #if defined(i386) || defined(__i386__) || defined(__x86_64__)
+ int
+ tas(volatile int *s) /* tested */
+ { int r;
+ __asm__ __volatile__(
+ "xchgl %0, %1 \n\t"
+ : "=r"(r), "=m"(*s)
+ : "0"(1), "m"(*s)
+ : "memory");
+
+ return r;
+ }
+ #elif defined(__arm__)
+ int
+ tas(volatile int *s) /* not tested */
+ { int r = 1;
+ __asm__ __volatile__(
+ "swpb %0, %0, [%3] \n"
+ : "=r"(r), "=m"(*s)
+ : "0"(r), "r"(s));
+
+ return r;
+ }
+ #elif defined(sparc) || defined(__sparc__)
+ int
+ tas(volatile int *s) /* not tested */
+ { int r = 1;
+ __asm__ __volatile__(
+ " ldstub [%2], %0 \n"
+ : "=r"(r), "=m"(*s)
+ : "r"(s));
+
+ return r;
+ }
+ #elif defined(ia64) || defined(__ia64__)
+ /* Intel Itanium */
+ int
+ tas(volatile int *s) /* tested */
+ { long int r;
+ __asm__ __volatile__(
+ " xchg4 %0=%1,%2 \n"
+ : "=r"(r), "+m"(*s)
+ : "r"(1)
+ : "memory");
+ return (int) r;
+ }
+ #else
+ #error missing definition of test and set operation for this platform
+ #endif
+
+void
+cleanup_shm(int val)
+{ volatile sh_Allocater *nxt_pool;
+ unsigned long cnt = 0;
+ int m;
+
+ if (nibis != 0)
+ { printf("cpu%d: Redundant call to cleanup_shm(%d)\n", core_id, val);
+ return;
+ } else
+ { nibis = 1;
+ }
+ if (search_terminated != NULL)
+ { *search_terminated |= 16; /* cleanup_shm */
+ }
+
+ for (m = 0; m < NR_QS; m++)
+ { if (shmdt((void *) shared_mem[m]) > 0)
+ { perror("shmdt detaching from shared queues");
+ } }
+
+#ifdef SEP_STATE
+ if (shmdt((void *) shmid_X) != 0)
+ { perror("shmdt detaching from shared state memory");
+ }
+#else
+ #ifdef BITSTATE
+ if (SS > 0 && shmdt((void *) SS) != 0)
+ { if (verbose)
+ { perror("shmdt detaching from shared bitstate arena");
+ } }
+ #else
+ if (core_id == 0)
+ { /* before detaching: */
+ for (nxt_pool = dc_shared; nxt_pool != NULL; nxt_pool = nxt_pool->nxt)
+ { cnt += nxt_pool->dc_size;
+ }
+ if (verbose)
+ { printf("cpu0: done, %ld Mb of shared state memory left\n",
+ cnt / (long)(1048576));
+ } }
+
+ if (shmdt((void *) H_tab) != 0)
+ { perror("shmdt detaching from shared hashtable");
+ }
+
+ for (last_pool = first_pool; last_pool != NULL; last_pool = nxt_pool)
+ { nxt_pool = last_pool->nxt;
+ if (shmdt((void *) last_pool->dc_start) != 0)
+ { perror("shmdt detaching from shared state memory");
+ } }
+ first_pool = last_pool = NULL; /* precaution */
+ #endif
+#endif
+ /* detached from shared memory - so cannot use cpu_printf */
+ if (verbose)
+ { printf("cpu%d: done -- got %d states from queue\n",
+ core_id, nstates_get);
+ }
+}
+
+extern void give_up(int);
+extern void Read_Queue(int);
+
+void
+mem_get(void)
+{ SM_frame *f;
+ int is_parent;
+
+#if defined(MA) && !defined(SEP_STATE)
+ #error MA without SEP_STATE is not supported with multi-core
+#endif
+#ifdef BFS
+ #error BFS is not supported with multi-core
+#endif
+#ifdef SC
+ #error SC is not supported with multi-core
+#endif
+ init_shm(); /* we are single threaded when this starts */
+
+ if (core_id == 0 && verbose)
+ { printf("cpu0: step 4: calling fork()\n");
+ }
+ fflush(stdout);
+
+/* if NCORE > 1 the child or the parent should fork N-1 more times
+ * the parent is the only process with core_id == 0 and is_parent > 0
+ * the workers have is_parent = 0 and core_id = 1..NCORE-1
+ */
+ if (core_id == 0)
+ { worker_pids[0] = getpid(); /* for completeness */
+ while (++core_id < NCORE) /* first worker sees core_id = 1 */
+ { is_parent = fork();
+ if (is_parent == -1)
+ { Uerror("fork failed");
+ }
+ if (is_parent == 0) /* this is a worker process */
+ { if (proxy_pid == core_id) /* always non-zero */
+ { start_proxy("-r", 0); /* no return */
+ }
+ goto adapt; /* root process continues spawning */
+ }
+ worker_pids[core_id] = is_parent;
+ }
+ /* note that core_id is now NCORE */
+ if (proxy_pid > 0 && proxy_pid < NCORE)
+ { proxy_pid_snd = fork();
+ if (proxy_pid_snd == -1)
+ { Uerror("proxy fork failed");
+ }
+ if (proxy_pid_snd == 0)
+ { start_proxy("-s", worker_pids[proxy_pid]); /* no return */
+ } } /* else continue */
+ if (is_parent > 0)
+ { core_id = 0; /* reset core_id for root process */
+ }
+ } else /* worker */
+ { static char db0[16]; /* good for up to 10^6 cores */
+ static char db1[16];
+adapt: tprefix = db0; sprefix = db1;
+ sprintf(tprefix, "cpu%d_trail", core_id);
+ sprintf(sprefix, "cpu%d_rst", core_id);
+ memcnt = 0; /* count only additionally allocated memory */
+ }
+ signal(SIGINT, give_up);
+
+ if (proxy_pid == 0) /* not in a cluster setup, pan_proxy must attach */
+ { rm_shared_segments(); /* mark all shared segments for removal on exit */
+ }
+ if (verbose)
+ { cpu_printf("starting core_id %d -- pid %d\n", core_id, getpid());
+ }
+#if defined(SEP_HEAP) && !defined(SEP_STATE)
+ { int i;
+ volatile sh_Allocater *ptr;
+ ptr = first_pool;
+ for (i = 0; i < NCORE && ptr != NULL; i++)
+ { if (i == core_id)
+ { my_heap = (char *) ptr->dc_arena;
+ my_size = (long) ptr->dc_size;
+ if (verbose)
+ cpu_printf("local heap %ld MB\n", my_size/(1048576));
+ break;
+ }
+ ptr = ptr->nxt; /* local */
+ }
+ if (my_heap == NULL)
+ { printf("cpu%d: no local heap\n", core_id);
+ pan_exit(1);
+ } /* else */
+ #if defined(CYGWIN) || defined(__CYGWIN__)
+ ptr = first_pool;
+ for (i = 0; i < NCORE && ptr != NULL; i++)
+ { ptr = ptr->nxt; /* local */
+ }
+ dc_shared = ptr; /* any remainder */
+ #else
+ dc_shared = NULL; /* used all mem for local heaps */
+ #endif
+ }
+#endif
+ if (core_id == 0 && !remote_party)
+ { new_state(); /* cpu0 explores root */
+ if (verbose)
+ cpu_printf("done with 1st dfs, nstates %g (put %d states), read q\n",
+ nstates, nstates_put);
+ dfs_phase2 = 1;
+ }
+ Read_Queue(core_id); /* all cores */
+
+ if (verbose)
+ { cpu_printf("put %6d states into queue -- got %6d\n",
+ nstates_put, nstates_get);
+ }
+ if (proxy_pid != 0)
+ { rm_shared_segments();
+ }
+ done = 1;
+ wrapup();
+ exit(0);
+}
+
+#else
+int unpack_state(SM_frame *, int);
+#endif
+
+struct H_el *
+grab_shared(int n)
+{
+#ifndef SEP_STATE
+ char *rval = (char *) 0;
+
+ if (n == 0)
+ { printf("cpu%d: grab shared zero\n", core_id); fflush(stdout);
+ return (struct H_el *) rval;
+ } else if (n&(sizeof(void *)-1))
+ { n += sizeof(void *)-(n&(sizeof(void *)-1)); /* alignment */
+ }
+
+#ifdef SEP_HEAP
+ /* no locking */
+ if (my_heap != NULL && my_size > n)
+ { rval = my_heap;
+ my_heap += n;
+ my_size -= n;
+ goto done;
+ }
+#endif
+
+ if (!dc_shared)
+ { sudden_stop("pan: out of memory");
+ }
+
+ /* another lock is always already in effect when this is called */
+ /* but not always the same lock -- i.e., on different parts of the hashtable */
+ enter_critical(GLOBAL_LOCK); /* this must be independently mutex */
+#if defined(SEP_HEAP) && !defined(WIN32) && !defined(WIN64)
+ { static int noted = 0;
+ if (!noted)
+ { noted = 1;
+ printf("cpu%d: global heap has %ld bytes left, needed %d\n",
+ core_id, dc_shared?dc_shared->dc_size:0, n);
+ } }
+#endif
+#if 0
+ if (dc_shared->pattern != 1234567)
+ { leave_critical(GLOBAL_LOCK);
+ Uerror("overrun -- memory corruption");
+ }
+#endif
+ if (dc_shared->dc_size < n)
+ { if (verbose)
+ { printf("Next Pool %g Mb + %d\n", memcnt/(1048576.), n);
+ }
+ if (dc_shared->nxt == NULL
+ || dc_shared->nxt->dc_arena == NULL
+ || dc_shared->nxt->dc_size < n)
+ { printf("cpu%d: memcnt %g Mb + wanted %d bytes more\n",
+ core_id, memcnt / (1048576.), n);
+ leave_critical(GLOBAL_LOCK);
+ sudden_stop("out of memory -- aborting");
+ wrapup(); /* exits */
+ } else
+ { dc_shared = (sh_Allocater *) dc_shared->nxt;
+ } }
+
+ rval = (char *) dc_shared->dc_arena;
+ dc_shared->dc_arena += n;
+ dc_shared->dc_size -= (long) n;
+#if 0
+ if (VVERBOSE)
+ printf("cpu%d grab shared (%d bytes) -- %ld left\n",
+ core_id, n, dc_shared->dc_size);
+#endif
+ leave_critical(GLOBAL_LOCK);
+done:
+ memset(rval, 0, n);
+ memcnt += (double) n;
+
+ return (struct H_el *) rval;
+#else
+ return (struct H_el *) emalloc(n);
+#endif
+}
+
+SM_frame *
+Get_Full_Frame(int n)
+{ SM_frame *f;
+ double cnt_start = frame_wait;
+
+ f = &m_workq[n][prfull[n]];
+ while (f->m_vsize == 0) /* await full slot LOCK : full frame */
+ { iam_alive();
+#ifndef NGQ
+ #ifndef SAFETY
+ if (!a_cycles || core_id != 0)
+ #endif
+ if (*grcnt > 0) /* accessed outside lock, but safe even if wrong */
+ { enter_critical(GQ_RD); /* gq - read access */
+ if (*grcnt > 0) /* could have changed */
+ { f = &m_workq[NCORE][*grfull]; /* global q */
+ if (f->m_vsize == 0)
+ { /* writer is still filling the slot */
+ *gr_writemiss++;
+ f = &m_workq[n][prfull[n]]; /* reset */
+ } else
+ { *grfull = (*grfull+1) % (GN_FRAMES);
+ enter_critical(GQ_WR);
+ *grcnt = *grcnt - 1;
+ leave_critical(GQ_WR);
+ leave_critical(GQ_RD);
+ return f;
+ } }
+ leave_critical(GQ_RD);
+ }
+#endif
+ if (frame_wait++ - cnt_start > Delay)
+ { if (0)
+ { cpu_printf("timeout on q%d -- %u -- query %d\n",
+ n, f, query_in_progress);
+ }
+ return (SM_frame *) 0; /* timeout */
+ } }
+ iam_alive();
+ if (VVERBOSE) cpu_printf("got frame from q%d\n", n);
+ prfull[n] = (prfull[n] + 1) % (LN_FRAMES);
+ enter_critical(QLOCK(n));
+ prcnt[n]--; /* lock out increments */
+ leave_critical(QLOCK(n));
+ return f;
+}
+
+SM_frame *
+Get_Free_Frame(int n)
+{ SM_frame *f;
+ double cnt_start = free_wait;
+
+ if (VVERBOSE) { cpu_printf("get free frame from q%d\n", n); }
+
+ if (n == NCORE) /* global q */
+ { f = &(m_workq[n][lrfree]);
+ } else
+ { f = &(m_workq[n][prfree[n]]);
+ }
+ while (f->m_vsize != 0) /* await free slot LOCK : free slot */
+ { iam_alive();
+ if (free_wait++ - cnt_start > OneSecond)
+ { if (verbose)
+ { cpu_printf("timeout waiting for free slot q%d\n", n);
+ }
+ cnt_start = free_wait;
+ if (someone_crashed(1))
+ { printf("cpu%d: search terminated\n", core_id);
+ sudden_stop("get free frame");
+ pan_exit(1);
+ } } }
+ if (n != NCORE)
+ { prfree[n] = (prfree[n] + 1) % (LN_FRAMES);
+ enter_critical(QLOCK(n));
+ prcnt[n]++; /* lock out decrements */
+ if (prmax[n] < prcnt[n])
+ { prmax[n] = prcnt[n];
+ }
+ leave_critical(QLOCK(n));
+ }
+ return f;
+}
+#ifndef NGQ
+int
+GlobalQ_HasRoom(void)
+{ int rval = 0;
+
+ gq_tries++;
+ if (*grcnt < GN_FRAMES) /* there seems to be room */
+ { enter_critical(GQ_WR); /* gq write access */
+ if (*grcnt < GN_FRAMES)
+ { if (m_workq[NCORE][*grfree].m_vsize != 0)
+ { /* can happen if reader is slow emptying slot */
+ *gr_readmiss++;
+ goto out; /* dont wait: release lock and return */
+ }
+ lrfree = *grfree; /* Get_Free_Frame use lrfree in this mode */
+ *grfree = (*grfree + 1) % GN_FRAMES;
+ *grcnt = *grcnt + 1; /* count nr of slots filled -- no additional lock needed */
+ if (*grmax < *grcnt) *grmax = *grcnt;
+ leave_critical(GQ_WR); /* for short lock duration */
+ gq_hasroom++;
+ mem_put(NCORE); /* copy state into reserved slot */
+ rval = 1; /* successfull handoff */
+ } else
+ { gq_hasnoroom++;
+out: leave_critical(GQ_WR);
+ } }
+ return rval;
+}
+#endif
+
+int
+unpack_state(SM_frame *f, int from_q)
+{ int i, j;
+ static struct H_el D_State;
+
+ if (f->m_vsize > 0)
+ { boq = f->m_boq;
+ if (boq > 256)
+ { cpu_printf("saw control %d, expected state\n", boq);
+ return 0;
+ }
+ vsize = f->m_vsize;
+correct:
+ memcpy((uchar *) &now, (uchar *) f->m_now, vsize);
+ for (i = j = 0; i < VMAX; i++, j = (j+1)%8)
+ { Mask[i] = (f->m_Mask[i/8] & (1<<j)) ? 1 : 0;
+ }
+ if (now._nr_pr > 0)
+ { memcpy((uchar *) proc_offset, (uchar *) f->m_p_offset, now._nr_pr * sizeof(OFFT));
+ memcpy((uchar *) proc_skip, (uchar *) f->m_p_skip, now._nr_pr * sizeof(uchar));
+ }
+ if (now._nr_qs > 0)
+ { memcpy((uchar *) q_offset, (uchar *) f->m_q_offset, now._nr_qs * sizeof(OFFT));
+ memcpy((uchar *) q_skip, (uchar *) f->m_q_skip, now._nr_qs * sizeof(uchar));
+ }
+#ifndef NOVSZ
+ if (vsize != now._vsz)
+ { cpu_printf("vsize %d != now._vsz %d (type %d) %d\n",
+ vsize, now._vsz, f->m_boq, f->m_vsize);
+ vsize = now._vsz;
+ goto correct; /* rare event: a race */
+ }
+#endif
+ hmax = max(hmax, vsize);
+
+ if (f != &cur_Root)
+ { memcpy((uchar *) &cur_Root, (uchar *) f, sizeof(SM_frame));
+ }
+
+ if (((now._a_t) & 1) == 1) /* i.e., when starting nested DFS */
+ { A_depth = depthfound = 0;
+ memcpy((uchar *)&A_Root, (uchar *)&now, vsize);
+ }
+ nr_handoffs = f->nr_handoffs;
+ } else
+ { cpu_printf("pan: state empty\n");
+ }
+
+ depth = 0;
+ trpt = &trail[1];
+ trpt->tau = f->m_tau;
+ trpt->o_pm = f->m_o_pm;
+
+ (trpt-1)->ostate = &D_State; /* stub */
+ trpt->ostate = &D_State;
+
+#ifdef FULL_TRAIL
+ if (upto > 0)
+ { stack_last[core_id] = (Stack_Tree *) f->m_stack;
+ }
+ #if defined(VERBOSE)
+ if (stack_last[core_id])
+ { cpu_printf("%d: UNPACK -- SET m_stack %u (%d,%d)\n",
+ depth, stack_last[core_id], stack_last[core_id]->pr,
+ stack_last[core_id]->t_id);
+ }
+ #endif
+#endif
+
+ if (!trpt->o_t)
+ { static Trans D_Trans;
+ trpt->o_t = &D_Trans;
+ }
+
+ #ifdef VERI
+ if ((trpt->tau & 4) != 4)
+ { trpt->tau |= 4; /* the claim moves first */
+ cpu_printf("warning: trpt was not up to date\n");
+ }
+ #endif
+
+ for (i = 0; i < (int) now._nr_pr; i++)
+ { P0 *ptr = (P0 *) pptr(i);
+ #ifndef NP
+ if (accpstate[ptr->_t][ptr->_p])
+ { trpt->o_pm |= 2;
+ }
+ #else
+ if (progstate[ptr->_t][ptr->_p])
+ { trpt->o_pm |= 4;
+ }
+ #endif
+ }
+
+ #ifdef EVENT_TRACE
+ #ifndef NP
+ if (accpstate[EVENT_TRACE][now._event])
+ { trpt->o_pm |= 2;
+ }
+ #else
+ if (progstate[EVENT_TRACE][now._event])
+ { trpt->o_pm |= 4;
+ }
+ #endif
+ #endif
+
+ #if defined(C_States) && (HAS_TRACK==1)
+ /* restore state of tracked C objects */
+ c_revert((uchar *) &(now.c_state[0]));
+ #if (HAS_STACK==1)
+ c_unstack((uchar *) f->m_c_stack); /* unmatched tracked data */
+ #endif
+ #endif
+ return 1;
+}
+
+void
+write_root(void) /* for trail file */
+{ int fd;
+
+ if (iterative == 0 && Nr_Trails > 1)
+ sprintf(fnm, "%s%d.%s", TrailFile, Nr_Trails-1, sprefix);
+ else
+ sprintf(fnm, "%s.%s", TrailFile, sprefix);
+
+ if (cur_Root.m_vsize == 0)
+ { (void) unlink(fnm); /* remove possible old copy */
+ return; /* its the default initial state */
+ }
+
+ if ((fd = creat(fnm, TMODE)) < 0)
+ { char *q;
+ if ((q = strchr(TrailFile, '.')))
+ { *q = '\0'; /* strip .pml */
+ if (iterative == 0 && Nr_Trails-1 > 0)
+ sprintf(fnm, "%s%d.%s", TrailFile, Nr_Trails-1, sprefix);
+ else
+ sprintf(fnm, "%s.%s", TrailFile, sprefix);
+ *q = '.';
+ fd = creat(fnm, TMODE);
+ }
+ if (fd < 0)
+ { cpu_printf("pan: cannot create %s\n", fnm);
+ perror("cause");
+ return;
+ } }
+
+ if (write(fd, &cur_Root, sizeof(SM_frame)) != sizeof(SM_frame))
+ { cpu_printf("pan: error writing %s\n", fnm);
+ } else
+ { cpu_printf("pan: wrote %s\n", fnm);
+ }
+ close(fd);
+}
+
+void
+set_root(void)
+{ int fd;
+ char *q;
+ char MyFile[512];
+ char MySuffix[16];
+ char *ssuffix = "rst";
+ int try_core = 1;
+
+ strcpy(MyFile, TrailFile);
+try_again:
+ if (whichtrail > 0)
+ { sprintf(fnm, "%s%d.%s", MyFile, whichtrail, ssuffix);
+ fd = open(fnm, O_RDONLY, 0);
+ if (fd < 0 && (q = strchr(MyFile, '.')))
+ { *q = '\0'; /* strip .pml */
+ sprintf(fnm, "%s%d.%s", MyFile, whichtrail, ssuffix);
+ *q = '.';
+ fd = open(fnm, O_RDONLY, 0);
+ }
+ } else
+ { sprintf(fnm, "%s.%s", MyFile, ssuffix);
+ fd = open(fnm, O_RDONLY, 0);
+ if (fd < 0 && (q = strchr(MyFile, '.')))
+ { *q = '\0'; /* strip .pml */
+ sprintf(fnm, "%s.%s", MyFile, ssuffix);
+ *q = '.';
+ fd = open(fnm, O_RDONLY, 0);
+ } }
+
+ if (fd < 0)
+ { if (try_core < NCORE)
+ { ssuffix = MySuffix;
+ sprintf(ssuffix, "cpu%d_rst", try_core++);
+ goto try_again;
+ }
+ cpu_printf("no file '%s.rst' or '%s' (not an error)\n", MyFile, fnm);
+ } else
+ { if (read(fd, &cur_Root, sizeof(SM_frame)) != sizeof(SM_frame))
+ { cpu_printf("read error %s\n", fnm);
+ close(fd);
+ pan_exit(1);
+ }
+ close(fd);
+ (void) unpack_state(&cur_Root, -2);
+#ifdef SEP_STATE
+ cpu_printf("partial trail -- last few steps only\n");
+#endif
+ cpu_printf("restored root from '%s'\n", fnm);
+ printf("=====State:=====\n");
+ { int i, j; P0 *z;
+ for (i = 0; i < now._nr_pr; i++)
+ { z = (P0 *)pptr(i);
+ printf("proc %2d (%s) ", i, procname[z->_t]);
+ for (j = 0; src_all[j].src; j++)
+ if (src_all[j].tp == (int) z->_t)
+ { printf(" line %3d \"%s\" ",
+ src_all[j].src[z->_p], PanSource);
+ break;
+ }
+ printf("(state %d)\n", z->_p);
+ c_locals(i, z->_t);
+ }
+ c_globals();
+ }
+ printf("================\n");
+ }
+}
+
+#ifdef USE_DISK
+unsigned long dsk_written, dsk_drained;
+void mem_drain(void);
+#endif
+
+void
+m_clear_frame(SM_frame *f)
+{ int i, clr_sz = sizeof(SM_results);
+
+ for (i = 0; i <= _NP_; i++) /* all proctypes */
+ { clr_sz += NrStates[i]*sizeof(uchar);
+ }
+ memset(f, 0, clr_sz);
+ /* caution if sizeof(SM_results) > sizeof(SM_frame) */
+}
+
+#define TargetQ_Full(n) (m_workq[n][prfree[n]].m_vsize != 0)
+#define TargetQ_NotFull(n) (m_workq[n][prfree[n]].m_vsize == 0)
+
+int
+AllQueuesEmpty(void)
+{ int q;
+#ifndef NGQ
+ if (*grcnt != 0)
+ { return 0;
+ }
+#endif
+ for (q = 0; q < NCORE; q++)
+ { if (prcnt[q] != 0)
+ { return 0;
+ } }
+ return 1;
+}
+
+void
+Read_Queue(int q)
+{ SM_frame *f, *of;
+ int remember, target_q;
+ SM_results *r;
+ double patience = 0.0;
+
+ target_q = (q + 1) % NCORE;
+
+ for (;;)
+ { f = Get_Full_Frame(q);
+ if (!f) /* 1 second timeout -- and trigger for Query */
+ { if (someone_crashed(2))
+ { printf("cpu%d: search terminated [code %d]\n",
+ core_id, search_terminated?*search_terminated:-1);
+ sudden_stop("");
+ pan_exit(1);
+ }
+#ifdef TESTING
+ /* to profile with cc -pg and gprof pan.exe -- set handoff depth beyond maxdepth */
+ exit(0);
+#endif
+ remember = *grfree;
+ if (core_id == 0 /* root can initiate termination */
+ && remote_party == 0 /* and only the original root */
+ && query_in_progress == 0 /* unless its already in progress */
+ && AllQueuesEmpty())
+ { f = Get_Free_Frame(target_q);
+ query_in_progress = 1; /* only root process can do this */
+ if (!f) { Uerror("Fatal1: no free slot"); }
+ f->m_boq = QUERY; /* initiate Query */
+ if (verbose)
+ { cpu_printf("snd QUERY to q%d (%d) into slot %d\n",
+ target_q, nstates_get + 1, prfree[target_q]-1);
+ }
+ f->m_vsize = remember + 1;
+ /* number will not change unless we receive more states */
+ } else if (patience++ > OneHour) /* one hour watchdog timer */
+ { cpu_printf("timeout -- giving up\n");
+ sudden_stop("queue timeout");
+ pan_exit(1);
+ }
+ if (0) cpu_printf("timed out -- try again\n");
+ continue;
+ }
+ patience = 0.0; /* reset watchdog */
+
+ if (f->m_boq == QUERY)
+ { if (verbose)
+ { cpu_printf("got QUERY on q%d (%d <> %d) from slot %d\n",
+ q, f->m_vsize, nstates_put + 1, prfull[q]-1);
+ snapshot();
+ }
+ remember = f->m_vsize;
+ f->m_vsize = 0; /* release slot */
+
+ if (core_id == 0 && remote_party == 0) /* original root cpu0 */
+ { if (query_in_progress == 1 /* didn't send more states in the interim */
+ && *grfree + 1 == remember) /* no action on global queue meanwhile */
+ { if (verbose) cpu_printf("Termination detected\n");
+ if (TargetQ_Full(target_q))
+ { if (verbose)
+ cpu_printf("warning: target q is full\n");
+ }
+ f = Get_Free_Frame(target_q);
+ if (!f) { Uerror("Fatal2: no free slot"); }
+ m_clear_frame(f);
+ f->m_boq = QUIT; /* send final Quit, collect stats */
+ f->m_vsize = 111; /* anything non-zero will do */
+ if (verbose)
+ cpu_printf("put QUIT on q%d\n", target_q);
+ } else
+ { if (verbose) cpu_printf("Stale Query\n");
+#ifdef USE_DISK
+ mem_drain();
+#endif
+ }
+ query_in_progress = 0;
+ } else
+ { if (TargetQ_Full(target_q))
+ { if (verbose)
+ cpu_printf("warning: forward query - target q full\n");
+ }
+ f = Get_Free_Frame(target_q);
+ if (verbose)
+ cpu_printf("snd QUERY response to q%d (%d <> %d) in slot %d\n",
+ target_q, remember, *grfree + 1, prfree[target_q]-1);
+ if (!f) { Uerror("Fatal4: no free slot"); }
+
+ if (*grfree + 1 == remember) /* no action on global queue */
+ { f->m_boq = QUERY; /* forward query, to root */
+ f->m_vsize = remember;
+ } else
+ { f->m_boq = QUERY_F; /* no match -- busy */
+ f->m_vsize = 112; /* anything non-zero */
+#ifdef USE_DISK
+ if (dsk_written != dsk_drained)
+ { mem_drain();
+ }
+#endif
+ } }
+ continue;
+ }
+
+ if (f->m_boq == QUERY_F)
+ { if (verbose)
+ { cpu_printf("got QUERY_F on q%d from slot %d\n", q, prfull[q]-1);
+ }
+ f->m_vsize = 0; /* release slot */
+
+ if (core_id == 0 && remote_party == 0) /* original root cpu0 */
+ { if (verbose) cpu_printf("No Match on Query\n");
+ query_in_progress = 0;
+ } else
+ { if (TargetQ_Full(target_q))
+ { if (verbose) cpu_printf("warning: forwarding query_f, target queue full\n");
+ }
+ f = Get_Free_Frame(target_q);
+ if (verbose) cpu_printf("forward QUERY_F to q%d into slot %d\n",
+ target_q, prfree[target_q]-1);
+ if (!f) { Uerror("Fatal5: no free slot"); }
+ f->m_boq = QUERY_F; /* cannot terminate yet */
+ f->m_vsize = 113; /* anything non-zero */
+ }
+#ifdef USE_DISK
+ if (dsk_written != dsk_drained)
+ { mem_drain();
+ }
+#endif
+ continue;
+ }
+
+ if (f->m_boq == QUIT)
+ { if (0) cpu_printf("done -- local memcnt %g Mb\n", memcnt/(1048576.));
+ retrieve_info((SM_results *) f); /* collect and combine stats */
+ if (verbose)
+ { cpu_printf("received Quit\n");
+ snapshot();
+ }
+ f->m_vsize = 0; /* release incoming slot */
+ if (core_id != 0)
+ { f = Get_Free_Frame(target_q); /* new outgoing slot */
+ if (!f) { Uerror("Fatal6: no free slot"); }
+ m_clear_frame(f); /* start with zeroed stats */
+ record_info((SM_results *) f);
+ f->m_boq = QUIT; /* forward combined results */
+ f->m_vsize = 114; /* anything non-zero */
+ if (verbose>1)
+ cpu_printf("fwd Results to q%d\n", target_q);
+ }
+ break; /* successful termination */
+ }
+
+ /* else: 0<= boq <= 255, means STATE transfer */
+ if (unpack_state(f, q) != 0)
+ { nstates_get++;
+ f->m_vsize = 0; /* release slot */
+ if (VVERBOSE) cpu_printf("Got state\n");
+
+ if (search_terminated != NULL
+ && *search_terminated == 0)
+ { new_state(); /* explore successors */
+ memset((uchar *) &cur_Root, 0, sizeof(SM_frame)); /* avoid confusion */
+ } else
+ { pan_exit(0);
+ }
+ } else
+ { pan_exit(0);
+ } }
+ if (verbose) cpu_printf("done got %d put %d\n", nstates_get, nstates_put);
+ sleep_report();
+}
+
+void
+give_up(int unused_x)
+{
+ if (search_terminated != NULL)
+ { *search_terminated |= 32; /* give_up */
+ }
+ if (!writing_trail)
+ { was_interrupted = 1;
+ snapshot();
+ cpu_printf("Give Up\n");
+ sleep_report();
+ pan_exit(1);
+ } else /* we are already terminating */
+ { cpu_printf("SIGINT\n");
+ }
+}
+
+void
+check_overkill(void)
+{
+ vmax_seen = (vmax_seen + 7)/ 8;
+ vmax_seen *= 8; /* round up to a multiple of 8 */
+
+ if (core_id == 0
+ && !remote_party
+ && nstates_put > 0
+ && VMAX - vmax_seen > 8)
+ {
+#ifdef BITSTATE
+ printf("cpu0: max VMAX value seen in this run: ");
+#else
+ printf("cpu0: recommend recompiling with ");
+#endif
+ printf("-DVMAX=%d\n", vmax_seen);
+ }
+}
+
+void
+mem_put(int q) /* handoff state to other cpu, workq q */
+{ SM_frame *f;
+ int i, j;
+
+ if (vsize > VMAX)
+ { vsize = (vsize + 7)/8; vsize *= 8; /* round up */
+ printf("pan: recompile with -DVMAX=N with N >= %d\n", vsize);
+ Uerror("aborting");
+ }
+ if (now._nr_pr > PMAX)
+ { printf("pan: recompile with -DPMAX=N with N >= %d\n", now._nr_pr);
+ Uerror("aborting");
+ }
+ if (now._nr_qs > QMAX)
+ { printf("pan: recompile with -DQMAX=N with N >= %d\n", now._nr_qs);
+ Uerror("aborting");
+ }
+ if (vsize > vmax_seen) vmax_seen = vsize;
+ if (now._nr_pr > pmax_seen) pmax_seen = now._nr_pr;
+ if (now._nr_qs > qmax_seen) qmax_seen = now._nr_qs;
+
+ f = Get_Free_Frame(q); /* not called in likely deadlock states */
+ if (!f) { Uerror("Fatal3: no free slot"); }
+
+ if (VVERBOSE) cpu_printf("putting state into q%d\n", q);
+
+ memcpy((uchar *) f->m_now, (uchar *) &now, vsize);
+ memset((uchar *) f->m_Mask, 0, (VMAX+7)/8 * sizeof(char));
+ for (i = j = 0; i < VMAX; i++, j = (j+1)%8)
+ { if (Mask[i])
+ { f->m_Mask[i/8] |= (1<<j);
+ } }
+
+ if (now._nr_pr > 0)
+ { memcpy((uchar *) f->m_p_offset, (uchar *) proc_offset, now._nr_pr * sizeof(OFFT));
+ memcpy((uchar *) f->m_p_skip, (uchar *) proc_skip, now._nr_pr * sizeof(uchar));
+ }
+ if (now._nr_qs > 0)
+ { memcpy((uchar *) f->m_q_offset, (uchar *) q_offset, now._nr_qs * sizeof(OFFT));
+ memcpy((uchar *) f->m_q_skip, (uchar *) q_skip, now._nr_qs * sizeof(uchar));
+ }
+#if defined(C_States) && (HAS_TRACK==1) && (HAS_STACK==1)
+ c_stack((uchar *) f->m_c_stack); /* save unmatched tracked data */
+#endif
+#ifdef FULL_TRAIL
+ f->m_stack = stack_last[core_id];
+#endif
+ f->nr_handoffs = nr_handoffs+1;
+ f->m_tau = trpt->tau;
+ f->m_o_pm = trpt->o_pm;
+ f->m_boq = boq;
+ f->m_vsize = vsize; /* must come last - now the other cpu can see it */
+
+ if (query_in_progress == 1)
+ query_in_progress = 2; /* make sure we know, if a query makes the rounds */
+ nstates_put++;
+}
+
+#ifdef USE_DISK
+int Dsk_W_Nr, Dsk_R_Nr;
+int dsk_file = -1, dsk_read = -1;
+unsigned long dsk_written, dsk_drained;
+char dsk_name[512];
+
+#ifndef BFS_DISK
+#if defined(WIN32) || defined(WIN64)
+ #define RFLAGS (O_RDONLY|O_BINARY)
+ #define WFLAGS (O_CREAT|O_WRONLY|O_TRUNC|O_BINARY)
+#else
+ #define RFLAGS (O_RDONLY)
+ #define WFLAGS (O_CREAT|O_WRONLY|O_TRUNC)
+#endif
+#endif
+
+void
+dsk_stats(void)
+{ int i;
+
+ if (dsk_written > 0)
+ { cpu_printf("dsk_written %d states in %d files\ncpu%d: dsk_drained %6d states\n",
+ dsk_written, Dsk_W_Nr, core_id, dsk_drained);
+ close(dsk_read);
+ close(dsk_file);
+ for (i = 0; i < Dsk_W_Nr; i++)
+ { sprintf(dsk_name, "Q%.3d_%.3d.tmp", i, core_id);
+ unlink(dsk_name);
+ } }
+}
+
+void
+mem_drain(void)
+{ SM_frame *f, g;
+ int q = (core_id + 1) % NCORE; /* target q */
+ int sz;
+
+ if (dsk_read < 0
+ || dsk_written <= dsk_drained)
+ { return;
+ }
+
+ while (dsk_written > dsk_drained
+ && TargetQ_NotFull(q))
+ { f = Get_Free_Frame(q);
+ if (!f) { Uerror("Fatal: unhandled condition"); }
+
+ if ((dsk_drained+1)%MAX_DSK_FILE == 0) /* 100K states max per file */
+ { (void) close(dsk_read); /* close current read handle */
+ sprintf(dsk_name, "Q%.3d_%.3d.tmp", Dsk_R_Nr++, core_id);
+ (void) unlink(dsk_name); /* remove current file */
+ sprintf(dsk_name, "Q%.3d_%.3d.tmp", Dsk_R_Nr, core_id);
+ cpu_printf("reading %s\n", dsk_name);
+ dsk_read = open(dsk_name, RFLAGS); /* open next file */
+ if (dsk_read < 0)
+ { Uerror("could not open dsk file");
+ } }
+ if (read(dsk_read, &g, sizeof(SM_frame)) != sizeof(SM_frame))
+ { Uerror("bad dsk file read");
+ }
+ sz = g.m_vsize;
+ g.m_vsize = 0;
+ memcpy(f, &g, sizeof(SM_frame));
+ f->m_vsize = sz; /* last */
+
+ dsk_drained++;
+ }
+}
+
+void
+mem_file(void)
+{ SM_frame f;
+ int i, j, q = (core_id + 1) % NCORE; /* target q */
+
+ if (vsize > VMAX)
+ { printf("pan: recompile with -DVMAX=N with N >= %d\n", vsize);
+ Uerror("aborting");
+ }
+ if (now._nr_pr > PMAX)
+ { printf("pan: recompile with -DPMAX=N with N >= %d\n", now._nr_pr);
+ Uerror("aborting");
+ }
+ if (now._nr_qs > QMAX)
+ { printf("pan: recompile with -DQMAX=N with N >= %d\n", now._nr_qs);
+ Uerror("aborting");
+ }
+
+ if (VVERBOSE) cpu_printf("filing state for q%d\n", q);
+
+ memcpy((uchar *) f.m_now, (uchar *) &now, vsize);
+ memset((uchar *) f.m_Mask, 0, (VMAX+7)/8 * sizeof(char));
+ for (i = j = 0; i < VMAX; i++, j = (j+1)%8)
+ { if (Mask[i])
+ { f.m_Mask[i/8] |= (1<<j);
+ } }
+
+ if (now._nr_pr > 0)
+ { memcpy((uchar *)f.m_p_offset, (uchar *)proc_offset, now._nr_pr*sizeof(OFFT));
+ memcpy((uchar *)f.m_p_skip, (uchar *)proc_skip, now._nr_pr*sizeof(uchar));
+ }
+ if (now._nr_qs > 0)
+ { memcpy((uchar *) f.m_q_offset, (uchar *) q_offset, now._nr_qs*sizeof(OFFT));
+ memcpy((uchar *) f.m_q_skip, (uchar *) q_skip, now._nr_qs*sizeof(uchar));
+ }
+#if defined(C_States) && (HAS_TRACK==1) && (HAS_STACK==1)
+ c_stack((uchar *) f.m_c_stack); /* save unmatched tracked data */
+#endif
+#ifdef FULL_TRAIL
+ f.m_stack = stack_last[core_id];
+#endif
+ f.nr_handoffs = nr_handoffs+1;
+ f.m_tau = trpt->tau;
+ f.m_o_pm = trpt->o_pm;
+ f.m_boq = boq;
+ f.m_vsize = vsize;
+
+ if (query_in_progress == 1)
+ { query_in_progress = 2;
+ }
+ if (dsk_file < 0)
+ { sprintf(dsk_name, "Q%.3d_%.3d.tmp", Dsk_W_Nr, core_id);
+ dsk_file = open(dsk_name, WFLAGS, 0644);
+ dsk_read = open(dsk_name, RFLAGS);
+ if (dsk_file < 0 || dsk_read < 0)
+ { cpu_printf("File: <%s>\n", dsk_name);
+ Uerror("cannot open diskfile");
+ }
+ Dsk_W_Nr++; /* nr of next file to open */
+ cpu_printf("created temporary diskfile %s\n", dsk_name);
+ } else if ((dsk_written+1)%MAX_DSK_FILE == 0)
+ { close(dsk_file); /* close write handle */
+ sprintf(dsk_name, "Q%.3d_%.3d.tmp", Dsk_W_Nr++, core_id);
+ dsk_file = open(dsk_name, WFLAGS, 0644);
+ if (dsk_file < 0)
+ { cpu_printf("File: <%s>\n", dsk_name);
+ Uerror("aborting: cannot open new diskfile");
+ }
+ cpu_printf("created temporary diskfile %s\n", dsk_name);
+ }
+ if (write(dsk_file, &f, sizeof(SM_frame)) != sizeof(SM_frame))
+ { Uerror("aborting -- disk write failed (disk full?)");
+ }
+ nstates_put++;
+ dsk_written++;
+}
+#endif
+
+int
+mem_hand_off(void)
+{
+ if (search_terminated == NULL
+ || *search_terminated != 0) /* not a full crash check */
+ { pan_exit(0);
+ }
+ iam_alive(); /* on every transition of Down */
+#ifdef USE_DISK
+ mem_drain(); /* maybe call this also on every Up */
+#endif
+ if (depth > z_handoff /* above handoff limit */
+#ifndef SAFETY
+ && !a_cycles /* not in liveness mode */
+#endif
+#if SYNC
+ && boq == -1 /* not mid-rv */
+#endif
+#ifdef VERI
+ && (trpt->tau&4) /* claim moves first */
+ && !((trpt-1)->tau&128) /* not a stutter move */
+#endif
+ && !(trpt->tau&8)) /* not an atomic move */
+ { int q = (core_id + 1) % NCORE; /* circular handoff */
+ #ifdef GENEROUS
+ if (prcnt[q] < LN_FRAMES)
+ #else
+ if (TargetQ_NotFull(q)
+ && (dfs_phase2 == 0 || prcnt[core_id] > 0))
+ #endif
+ { mem_put(q);
+ return 1;
+ }
+ { int rval;
+ #ifndef NGQ
+ rval = GlobalQ_HasRoom();
+ #else
+ rval = 0;
+ #endif
+ #ifdef USE_DISK
+ if (rval == 0)
+ { void mem_file(void);
+ mem_file();
+ rval = 1;
+ }
+ #endif
+ return rval;
+ }
+ }
+ return 0; /* i.e., no handoff */
+}
+
+void
+mem_put_acc(void) /* liveness mode */
+{ int q = (core_id + 1) % NCORE;
+
+ if (search_terminated == NULL
+ || *search_terminated != 0)
+ { pan_exit(0);
+ }
+#ifdef USE_DISK
+ mem_drain();
+#endif
+ /* some tortured use of preprocessing: */
+#if !defined(NGQ) || defined(USE_DISK)
+ if (TargetQ_Full(q))
+ {
+#endif
+#ifndef NGQ
+ if (GlobalQ_HasRoom())
+ { return;
+ }
+#endif
+#ifdef USE_DISK
+ mem_file();
+ } else
+#else
+ #if !defined(NGQ) || defined(USE_DISK)
+ }
+ #endif
+#endif
+ { mem_put(q);
+ }
+}
+
+#if defined(WIN32) || defined(WIN64)
+void
+init_shm(void) /* initialize shared work-queues */
+{ char key[512];
+ int n, m;
+ int must_exit = 0;
+
+ if (core_id == 0 && verbose)
+ { printf("cpu0: step 3: allocate shared work-queues %g Mb\n",
+ ((double) NCORE * LWQ_SIZE + GWQ_SIZE) / (1048576.));
+ }
+ for (m = 0; m < NR_QS; m++) /* last q is global 1 */
+ { double qsize = (m == NCORE) ? GWQ_SIZE : LWQ_SIZE;
+ sprintf(key, "Global\\pan_%s_%.3d", PanSource, m);
+ if (core_id == 0)
+ { shmid[m] = CreateFileMapping(
+ INVALID_HANDLE_VALUE, /* use paging file */
+ NULL, /* default security */
+ PAGE_READWRITE, /* access permissions */
+ 0, /* high-order 4 bytes */
+ qsize, /* low-order bytes, size in bytes */
+ key); /* name */
+ } else /* worker nodes just open these segments */
+ { shmid[m] = OpenFileMapping(
+ FILE_MAP_ALL_ACCESS, /* read/write access */
+ FALSE, /* children do not inherit handle */
+ key);
+ }
+ if (shmid[m] == NULL)
+ { fprintf(stderr, "cpu%d: could not create or open shared queues\n",
+ core_id);
+ must_exit = 1;
+ break;
+ }
+ /* attach: */
+ shared_mem[m] = (char *) MapViewOfFile(shmid[m], FILE_MAP_ALL_ACCESS, 0, 0, 0);
+ if (shared_mem[m] == NULL)
+ { fprintf(stderr, "cpu%d: cannot attach shared q%d (%d Mb)\n",
+ core_id, m+1, (int) (qsize/(1048576.)));
+ must_exit = 1;
+ break;
+ }
+
+ memcnt += qsize;
+
+ m_workq[m] = (SM_frame *) shared_mem[m];
+ if (core_id == 0)
+ { int nframes = (m == NCORE) ? GN_FRAMES : LN_FRAMES;
+ for (n = 0; n < nframes; n++)
+ { m_workq[m][n].m_vsize = 0;
+ m_workq[m][n].m_boq = 0;
+ } } }
+
+ if (must_exit)
+ { fprintf(stderr, "pan: check './pan --' for usage details\n");
+ pan_exit(1); /* calls cleanup_shm */
+ }
+}
+
+static uchar *
+prep_shmid_S(size_t n) /* either sets SS or H_tab, WIN32/WIN64 */
+{ char *rval;
+#ifndef SEP_STATE
+ char key[512];
+
+ if (verbose && core_id == 0)
+ {
+ #ifdef BITSTATE
+ printf("cpu0: step 1: allocate shared bitstate %g Mb\n",
+ (double) n / (1048576.));
+ #else
+ printf("cpu0: step 1: allocate shared hastable %g Mb\n",
+ (double) n / (1048576.));
+ #endif
+ }
+ #ifdef MEMLIM
+ if (memcnt + (double) n > memlim)
+ { printf("cpu%d: S %8g + %d Kb exceeds memory limit of %8g Mb\n",
+ core_id, memcnt/1024., n/1024, memlim/(1048576.));
+ printf("cpu%d: insufficient memory -- aborting\n", core_id);
+ exit(1);
+ }
+ #endif
+
+ /* make key different from queues: */
+ sprintf(key, "Global\\pan_%s_%.3d", PanSource, NCORE+2); /* different from qs */
+
+ if (core_id == 0) /* root */
+ { shmid_S = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
+#ifdef WIN64
+ PAGE_READWRITE, (n>>32), (n & 0xffffffff), key);
+#else
+ PAGE_READWRITE, 0, n, key);
+#endif
+ memcnt += (double) n;
+ } else /* worker */
+ { shmid_S = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, key);
+ }
+ if (shmid_S == NULL)
+ {
+ #ifdef BITSTATE
+ fprintf(stderr, "cpu%d: cannot %s shared bitstate",
+ core_id, core_id?"open":"create");
+ #else
+ fprintf(stderr, "cpu%d: cannot %s shared hashtable",
+ core_id, core_id?"open":"create");
+ #endif
+ fprintf(stderr, "pan: check './pan --' for usage details\n");
+ pan_exit(1);
+ }
+
+ rval = (char *) MapViewOfFile(shmid_S, FILE_MAP_ALL_ACCESS, 0, 0, 0); /* attach */
+ if ((char *) rval == NULL)
+ { fprintf(stderr, "cpu%d: cannot attach shared bitstate or hashtable\n", core_id);
+ fprintf(stderr, "pan: check './pan --' for usage details\n");
+ pan_exit(1);
+ }
+#else
+ rval = (char *) emalloc(n);
+#endif
+ return (uchar *) rval;
+}
+
+static uchar *
+prep_state_mem(size_t n) /* WIN32/WIN64 sets memory arena for states */
+{ char *rval;
+ char key[512];
+ static int cnt = 3; /* start larger than earlier ftok calls */
+
+ if (verbose && core_id == 0)
+ { printf("cpu0: step 2+: pre-allocate memory arena %d of %g Mb\n",
+ cnt-3, (double) n / (1048576.));
+ }
+ #ifdef MEMLIM
+ if (memcnt + (double) n > memlim)
+ { printf("cpu%d: error: M %.0f + %.0f exceeds memory limit of %.0f Kb\n",
+ core_id, memcnt/1024.0, (double) n/1024.0, memlim/1024.0);
+ return NULL;
+ }
+ #endif
+
+ sprintf(key, "Global\\pan_%s_%.3d", PanSource, NCORE+cnt); cnt++;
+
+ if (core_id == 0)
+ { shmid_M = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
+#ifdef WIN64
+ PAGE_READWRITE, (n>>32), (n & 0xffffffff), key);
+#else
+ PAGE_READWRITE, 0, n, key);
+#endif
+ } else
+ { shmid_M = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, key);
+ }
+ if (shmid_M == NULL)
+ { printf("cpu%d: failed to get pool of shared memory nr %d of size %d\n",
+ core_id, cnt-3, n);
+ printf("pan: check './pan --' for usage details\n");
+ return NULL;
+ }
+ rval = (char *) MapViewOfFile(shmid_M, FILE_MAP_ALL_ACCESS, 0, 0, 0); /* attach */
+
+ if (rval == NULL)
+ { printf("cpu%d: failed to attach pool of shared memory nr %d of size %d\n",
+ core_id, cnt-3, n);
+ return NULL;
+ }
+ return (uchar *) rval;
+}
+
+void
+init_HT(unsigned long n) /* WIN32/WIN64 version */
+{ volatile char *x;
+ double get_mem;
+#ifndef SEP_STATE
+ char *dc_mem_start;
+#endif
+ if (verbose) printf("cpu%d: initialization for Windows\n", core_id);
+
+#ifdef SEP_STATE
+ #ifndef MEMLIM
+ if (verbose)
+ { printf("cpu0: steps 0,1: no -DMEMLIM set\n");
+ }
+ #else
+ if (verbose)
+ printf("cpu0: steps 0,1: -DMEMLIM=%d Mb - (hashtable %g Mb + workqueues %g Mb)\n",
+ MEMLIM, ((double)n/(1048576.)), ((double) NCORE * LWQ_SIZE + GWQ_SIZE)/(1048576.));
+#endif
+ get_mem = NCORE * sizeof(double) + (1 + CS_NR) * sizeof(void *)+ 4*sizeof(void *) + 2*sizeof(double);
+ /* NCORE * is_alive + search_terminated + CS_NR * sh_lock + 6 gr vars */
+ get_mem += 4 * NCORE * sizeof(void *);
+ #ifdef FULL_TRAIL
+ get_mem += (NCORE) * sizeof(Stack_Tree *);
+ /* NCORE * stack_last */
+ #endif
+ x = (volatile char *) prep_state_mem((size_t) get_mem);
+ shmid_X = (void *) x;
+ if (x == NULL)
+ { printf("cpu0: could not allocate shared memory, see ./pan --\n");
+ exit(1);
+ }
+ search_terminated = (volatile unsigned int *) x; /* comes first */
+ x += sizeof(void *); /* maintain alignment */
+
+ is_alive = (volatile double *) x;
+ x += NCORE * sizeof(double);
+
+ sh_lock = (volatile int *) x;
+ x += CS_NR * sizeof(void *); /* allow 1 word per entry */
+
+ grfree = (volatile int *) x;
+ x += sizeof(void *);
+ grfull = (volatile int *) x;
+ x += sizeof(void *);
+ grcnt = (volatile int *) x;
+ x += sizeof(void *);
+ grmax = (volatile int *) x;
+ x += sizeof(void *);
+ prfree = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prfull = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prcnt = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prmax = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ gr_readmiss = (volatile double *) x;
+ x += sizeof(double);
+ gr_writemiss = (volatile double *) x;
+ x += sizeof(double);
+
+ #ifdef FULL_TRAIL
+ stack_last = (volatile Stack_Tree **) x;
+ x += NCORE * sizeof(Stack_Tree *);
+ #endif
+
+ #ifndef BITSTATE
+ H_tab = (struct H_el **) emalloc(n);
+ #endif
+#else
+ #ifndef MEMLIM
+ #warning MEMLIM not set
+ #define MEMLIM (2048)
+ #endif
+
+ if (core_id == 0 && verbose)
+ printf("cpu0: step 0: -DMEMLIM=%d Mb - (hashtable %g Mb + workqueues %g Mb) = %g Mb for state storage\n",
+ MEMLIM, ((double)n/(1048576.)), ((double) NCORE * LWQ_SIZE + GWQ_SIZE)/(1048576.),
+ (memlim - memcnt - (double) n - ((double) NCORE * LWQ_SIZE + GWQ_SIZE))/(1048576.));
+ #ifndef BITSTATE
+ H_tab = (struct H_el **) prep_shmid_S((size_t) n); /* hash_table */
+ #endif
+ get_mem = memlim - memcnt - ((double) NCORE) * LWQ_SIZE - GWQ_SIZE;
+ if (get_mem <= 0)
+ { Uerror("internal error -- shared state memory");
+ }
+
+ if (core_id == 0 && verbose)
+ { printf("cpu0: step 2: shared state memory %g Mb\n",
+ get_mem/(1048576.));
+ }
+ x = dc_mem_start = (char *) prep_state_mem((size_t) get_mem); /* for states */
+ if (x == NULL)
+ { printf("cpu%d: insufficient memory -- aborting\n", core_id);
+ exit(1);
+ }
+
+ search_terminated = (volatile unsigned int *) x; /* comes first */
+ x += sizeof(void *); /* maintain alignment */
+
+ is_alive = (volatile double *) x;
+ x += NCORE * sizeof(double);
+
+ sh_lock = (volatile int *) x;
+ x += CS_NR * sizeof(int);
+
+ grfree = (volatile int *) x;
+ x += sizeof(void *);
+ grfull = (volatile int *) x;
+ x += sizeof(void *);
+ grcnt = (volatile int *) x;
+ x += sizeof(void *);
+ grmax = (volatile int *) x;
+ x += sizeof(void *);
+ prfree = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prfull = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prcnt = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prmax = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ gr_readmiss = (volatile double *) x;
+ x += sizeof(double);
+ gr_writemiss = (volatile double *) x;
+ x += sizeof(double);
+
+ #ifdef FULL_TRAIL
+ stack_last = (volatile Stack_Tree **) x;
+ x += NCORE * sizeof(Stack_Tree *);
+ #endif
+ if (((long)x)&(sizeof(void *)-1)) /* word alignment */
+ { x += sizeof(void *)-(((long)x)&(sizeof(void *)-1)); /* 64-bit align */
+ }
+
+ #ifdef COLLAPSE
+ ncomps = (unsigned long *) x;
+ x += (256+2) * sizeof(unsigned long);
+ #endif
+
+ dc_shared = (sh_Allocater *) x; /* in shared memory */
+ x += sizeof(sh_Allocater);
+
+ if (core_id == 0) /* root only */
+ { dc_shared->dc_id = shmid_M;
+ dc_shared->dc_start = (void *) dc_mem_start;
+ dc_shared->dc_arena = x;
+ dc_shared->pattern = 1234567;
+ dc_shared->dc_size = (long) get_mem - (long) (x - dc_mem_start);
+ dc_shared->nxt = NULL;
+ }
+#endif
+}
+
+#if defined(WIN32) || defined(WIN64) || defined(__i386__) || defined(__x86_64__)
+extern BOOLEAN InterlockedBitTestAndSet(LONG volatile* Base, LONG Bit);
+int
+tas(volatile LONG *s)
+{ return InterlockedBitTestAndSet(s, 1);
+}
+#else
+ #error missing definition of test and set operation for this platform
+#endif
+
+void
+cleanup_shm(int val)
+{ int m;
+ static int nibis = 0;
+
+ if (nibis != 0)
+ { printf("cpu%d: Redundant call to cleanup_shm(%d)\n", core_id, val);
+ return;
+ } else
+ { nibis = 1;
+ }
+ if (search_terminated != NULL)
+ { *search_terminated |= 16; /* cleanup_shm */
+ }
+
+ for (m = 0; m < NR_QS; m++)
+ { if (shmid[m] != NULL)
+ { UnmapViewOfFile((char *) shared_mem[m]);
+ CloseHandle(shmid[m]);
+ } }
+#ifdef SEP_STATE
+ UnmapViewOfFile((void *) shmid_X);
+ CloseHandle((void *) shmid_M);
+#else
+ #ifdef BITSTATE
+ if (shmid_S != NULL)
+ { UnmapViewOfFile(SS);
+ CloseHandle(shmid_S);
+ }
+ #else
+ if (core_id == 0 && verbose)
+ { printf("cpu0: done, %ld Mb of shared state memory left\n",
+ dc_shared->dc_size / (long)(1048576));
+ }
+ if (shmid_S != NULL)
+ { UnmapViewOfFile(H_tab);
+ CloseHandle(shmid_S);
+ }
+ shmid_M = (void *) (dc_shared->dc_id);
+ UnmapViewOfFile((char *) dc_shared->dc_start);
+ CloseHandle(shmid_M);
+ #endif
+#endif
+ /* detached from shared memory - so cannot use cpu_printf */
+ if (verbose)
+ { printf("cpu%d: done -- got %d states from queue\n",
+ core_id, nstates_get);
+ }
+}
+
+void
+mem_get(void)
+{ SM_frame *f;
+ int is_parent;
+
+#if defined(MA) && !defined(SEP_STATE)
+ #error MA requires SEP_STATE in multi-core mode
+#endif
+#ifdef BFS
+ #error BFS is not supported in multi-core mode
+#endif
+#ifdef SC
+ #error SC is not supported in multi-core mode
+#endif
+ init_shm(); /* we are single threaded when this starts */
+ signal(SIGINT, give_up); /* windows control-c interrupt */
+
+ if (core_id == 0 && verbose)
+ { printf("cpu0: step 4: creating additional workers (proxy %d)\n",
+ proxy_pid);
+ }
+#if 0
+ if NCORE > 1 the child or the parent should fork N-1 more times
+ the parent is the only process with core_id == 0 and is_parent > 0
+ the others (workers) have is_parent = 0 and core_id = 1..NCORE-1
+#endif
+ if (core_id == 0) /* root starts up the workers */
+ { worker_pids[0] = (DWORD) getpid(); /* for completeness */
+ while (++core_id < NCORE) /* first worker sees core_id = 1 */
+ { char cmdline[64];
+ STARTUPINFO si = { sizeof(si) };
+ PROCESS_INFORMATION pi;
+
+ if (proxy_pid == core_id) /* always non-zero */
+ { sprintf(cmdline, "pan_proxy.exe -r %s-Q%d -Z%d",
+ o_cmdline, getpid(), core_id);
+ } else
+ { sprintf(cmdline, "pan.exe %s-Q%d -Z%d",
+ o_cmdline, getpid(), core_id);
+ }
+ if (verbose) printf("cpu%d: spawn %s\n", core_id, cmdline);
+
+ is_parent = CreateProcess(0, cmdline, 0, 0, FALSE, 0, 0, 0, &si, &pi);
+ if (is_parent == 0)
+ { Uerror("fork failed");
+ }
+ worker_pids[core_id] = pi.dwProcessId;
+ worker_handles[core_id] = pi.hProcess;
+ if (verbose)
+ { cpu_printf("created core %d, pid %d\n",
+ core_id, pi.dwProcessId);
+ }
+ if (proxy_pid == core_id) /* we just created the receive half */
+ { /* add proxy send, store pid in proxy_pid_snd */
+ sprintf(cmdline, "pan_proxy.exe -s %s-Q%d -Z%d -Y%d",
+ o_cmdline, getpid(), core_id, worker_pids[proxy_pid]);
+ if (verbose) printf("cpu%d: spawn %s\n", core_id, cmdline);
+ is_parent = CreateProcess(0, cmdline, 0,0, FALSE, 0,0,0, &si, &pi);
+ if (is_parent == 0)
+ { Uerror("fork failed");
+ }
+ proxy_pid_snd = pi.dwProcessId;
+ proxy_handle_snd = pi.hProcess;
+ if (verbose)
+ { cpu_printf("created core %d, pid %d (send proxy)\n",
+ core_id, pi.dwProcessId);
+ } } }
+ core_id = 0; /* reset core_id for root process */
+ } else /* worker */
+ { static char db0[16]; /* good for up to 10^6 cores */
+ static char db1[16];
+ tprefix = db0; sprefix = db1;
+ sprintf(tprefix, "cpu%d_trail", core_id); /* avoid conflicts on file access */
+ sprintf(sprefix, "cpu%d_rst", core_id);
+ memcnt = 0; /* count only additionally allocated memory */
+ }
+ if (verbose)
+ { cpu_printf("starting core_id %d -- pid %d\n", core_id, getpid());
+ }
+ if (core_id == 0 && !remote_party)
+ { new_state(); /* root starts the search */
+ if (verbose)
+ cpu_printf("done with 1st dfs, nstates %g (put %d states), start reading q\n",
+ nstates, nstates_put);
+ dfs_phase2 = 1;
+ }
+ Read_Queue(core_id); /* all cores */
+
+ if (verbose)
+ { cpu_printf("put %6d states into queue -- got %6d\n",
+ nstates_put, nstates_get);
+ }
+ done = 1;
+ wrapup();
+ exit(0);
+}
+#endif
+
+#ifdef BITSTATE
+void
+init_SS(unsigned long n)
+{
+ SS = (uchar *) prep_shmid_S((size_t) n);
+ init_HT(0L);
+}
+#endif
+
+#endif
+clock_t start_time;
+#if NCORE>1
+clock_t crash_stamp;
+#endif
+#if !defined(WIN32) && !defined(WIN64)
+struct tms start_tm;
+#endif
+
+void
+start_timer(void)
+{
+#if defined(WIN32) || defined(WIN64)
+ start_time = clock();
+#else
+ start_time = times(&start_tm);
+#endif
+}
+
+void
+stop_timer(void)
+{ clock_t stop_time;
+ double delta_time;
+#if !defined(WIN32) && !defined(WIN64)
+ struct tms stop_tm;
+ stop_time = times(&stop_tm);
+ delta_time = ((double) (stop_time - start_time)) / ((double) sysconf(_SC_CLK_TCK));
+#else
+ stop_time = clock();
+ delta_time = ((double) (stop_time - start_time)) / ((double) CLOCKS_PER_SEC);
+#endif
+ if (readtrail || delta_time < 0.00) return;
+#if NCORE>1
+ if (core_id == 0 && nstates > (double) 0)
+ { printf("\ncpu%d: elapsed time %.3g seconds (%g states visited)\n", core_id, delta_time, nstates);
+ if (delta_time > 0.01)
+ { printf("cpu%d: rate %g states/second\n", core_id, nstates/delta_time);
+ }
+ { void check_overkill(void);
+ check_overkill();
+ } }
+#else
+ printf("\npan: elapsed time %.3g seconds\n", delta_time);
+ if (delta_time > 0.01)
+ { printf("pan: rate %9.8g states/second\n", nstates/delta_time);
+ if (verbose)
+ { printf("pan: avg transition delay %.5g usec\n",
+ delta_time/(nstates+truncs));
+ } }
+#endif
+}
+
+#if NCORE>1
+#ifdef T_ALERT
+double t_alerts[17];
+
+void
+crash_report(void)
+{ int i;
+ printf("crash alert intervals:\n");
+ for (i = 0; i < 17; i++)
+ { printf("%d\t%g\n", i, t_alerts[i]);
+} }
+#endif
+
+void
+crash_reset(void)
+{ /* false alarm */
+ if (crash_stamp != (clock_t) 0)
+ {
+#ifdef T_ALERT
+ double delta_time;
+ int i;
+#if defined(WIN32) || defined(WIN64)
+ delta_time = ((double) (clock() - crash_stamp)) / ((double) CLOCKS_PER_SEC);
+#else
+ delta_time = ((double) (times(&start_tm) - crash_stamp)) / ((double) sysconf(_SC_CLK_TCK));
+#endif
+ for (i = 0; i < 16; i++)
+ { if (delta_time <= (i*30))
+ { t_alerts[i] = delta_time;
+ break;
+ } }
+ if (i == 16) t_alerts[i] = delta_time;
+#endif
+ if (verbose)
+ printf("cpu%d: crash alert off\n", core_id);
+ }
+ crash_stamp = (clock_t) 0;
+}
+
+int
+crash_test(double maxtime)
+{ double delta_time;
+ if (crash_stamp == (clock_t) 0)
+ { /* start timing */
+#if defined(WIN32) || defined(WIN64)
+ crash_stamp = clock();
+#else
+ crash_stamp = times(&start_tm);
+#endif
+ if (verbose)
+ { printf("cpu%d: crash detection\n", core_id);
+ }
+ return 0;
+ }
+#if defined(WIN32) || defined(WIN64)
+ delta_time = ((double) (clock() - crash_stamp)) / ((double) CLOCKS_PER_SEC);
+#else
+ delta_time = ((double) (times(&start_tm) - crash_stamp)) / ((double) sysconf(_SC_CLK_TCK));
+#endif
+ return (delta_time >= maxtime);
+}
+#endif
+
+void
+do_the_search(void)
+{ int i;
+ depth = mreached = 0;
+ trpt = &trail[0];
+#ifdef VERI
+ trpt->tau |= 4; /* the claim moves first */
+#endif
+ for (i = 0; i < (int) now._nr_pr; i++)
+ { P0 *ptr = (P0 *) pptr(i);
+#ifndef NP
+ if (!(trpt->o_pm&2)
+ && accpstate[ptr->_t][ptr->_p])
+ { trpt->o_pm |= 2;
+ }
+#else
+ if (!(trpt->o_pm&4)
+ && progstate[ptr->_t][ptr->_p])
+ { trpt->o_pm |= 4;
+ }
+#endif
+ }
+#ifdef EVENT_TRACE
+#ifndef NP
+ if (accpstate[EVENT_TRACE][now._event])
+ { trpt->o_pm |= 2;
+ }
+#else
+ if (progstate[EVENT_TRACE][now._event])
+ { trpt->o_pm |= 4;
+ }
+#endif
+#endif
+#ifndef NOCOMP
+ Mask[0] = Mask[1] = 1; /* _nr_pr, _nr_qs */
+ if (!a_cycles)
+ { i = &(now._a_t) - (uchar *) &now;
+ Mask[i] = 1; /* _a_t */
+ }
+#ifndef NOFAIR
+ if (!fairness)
+ { int j = 0;
+ i = &(now._cnt[0]) - (uchar *) &now;
+ while (j++ < NFAIR)
+ Mask[i++] = 1; /* _cnt[] */
+ }
+#endif
+#endif
+#ifndef NOFAIR
+ if (fairness
+ && (a_cycles && (trpt->o_pm&2)))
+ { now._a_t = 2; /* set the A-bit */
+ now._cnt[0] = now._nr_pr + 1;
+#ifdef VERBOSE
+ printf("%3d: fairness Rule 1, cnt=%d, _a_t=%d\n",
+ depth, now._cnt[now._a_t&1], now._a_t);
+#endif
+ }
+#endif
+ c_stack_start = (char *) &i; /* meant to be read-only */
+#if defined(HAS_CODE) && defined (C_INIT)
+ C_INIT; /* initialization of data that must precede fork() */
+ c_init_done++;
+#endif
+#if defined(C_States) && (HAS_TRACK==1)
+ /* capture initial state of tracked C objects */
+ c_update((uchar *) &(now.c_state[0]));
+#endif
+#ifdef HAS_CODE
+ if (readtrail) getrail(); /* no return */
+#endif
+ start_timer();
+#ifdef BFS
+ bfs();
+#else
+#if defined(C_States) && defined(HAS_STACK) && (HAS_TRACK==1)
+ /* initial state of tracked & unmatched objects */
+ c_stack((uchar *) &(svtack->c_stack[0]));
+#endif
+#ifdef RANDOMIZE
+ #if RANDOMIZE>0
+ srand(RANDOMIZE);
+ #else
+ srand(123);
+ #endif
+#endif
+#if NCORE>1
+ mem_get();
+#else
+ new_state(); /* start 1st DFS */
+#endif
+#endif
+}
+#ifdef INLINE_REV
+uchar
+do_reverse(Trans *t, short II, uchar M)
+{ uchar _m = M;
+ int tt = (int) ((P0 *)this)->_p;
+#include REVERSE_MOVES
+R999: return _m;
+}
+#endif
+#ifndef INLINE
+#ifdef EVENT_TRACE
+static char _tp = 'n'; static int _qid = 0;
+#endif
+uchar
+do_transit(Trans *t, short II)
+{ uchar _m = 0;
+ int tt = (int) ((P0 *)this)->_p;
+#ifdef M_LOSS
+ uchar delta_m = 0;
+#endif
+#ifdef EVENT_TRACE
+ short oboq = boq;
+ uchar ot = (uchar) ((P0 *)this)->_t;
+ if (ot == EVENT_TRACE) boq = -1;
+#define continue { boq = oboq; return 0; }
+#else
+#define continue return 0
+#ifdef SEPARATE
+ uchar ot = (uchar) ((P0 *)this)->_t;
+#endif
+#endif
+#include FORWARD_MOVES
+P999:
+#ifdef EVENT_TRACE
+ if (ot == EVENT_TRACE) boq = oboq;
+#endif
+ return _m;
+#undef continue
+}
+#ifdef EVENT_TRACE
+void
+require(char tp, int qid)
+{ Trans *t;
+ _tp = tp; _qid = qid;
+
+ if (now._event != endevent)
+ for (t = trans[EVENT_TRACE][now._event]; t; t = t->nxt)
+ { if (do_transit(t, EVENT_TRACE))
+ { now._event = t->st;
+ reached[EVENT_TRACE][t->st] = 1;
+#ifdef VERBOSE
+ printf(" event_trace move to -> %d\n", t->st);
+#endif
+#ifndef BFS
+#ifndef NP
+ if (accpstate[EVENT_TRACE][now._event])
+ (trpt+1)->o_pm |= 2;
+#else
+ if (progstate[EVENT_TRACE][now._event])
+ (trpt+1)->o_pm |= 4;
+#endif
+#endif
+#ifdef NEGATED_TRACE
+ if (now._event == endevent)
+ {
+#ifndef BFS
+ depth++; trpt++;
+#endif
+ uerror("event_trace error (all events matched)");
+#ifndef BFS
+ trpt--; depth--;
+#endif
+ break;
+ }
+#endif
+ for (t = t->nxt; t; t = t->nxt)
+ { if (do_transit(t, EVENT_TRACE))
+ Uerror("non-determinism in event-trace");
+ }
+ return;
+ }
+#ifdef VERBOSE
+ else
+ printf(" event_trace miss '%c' -- %d, %d, %d\n",
+ tp, qid, now._event, t->forw);
+#endif
+ }
+#ifdef NEGATED_TRACE
+ now._event = endevent; /* only 1st try will count -- fixed 4.2.6 */
+#else
+#ifndef BFS
+ depth++; trpt++;
+#endif
+ uerror("event_trace error (no matching event)");
+#ifndef BFS
+ trpt--; depth--;
+#endif
+#endif
+}
+#endif
+int
+enabled(int iam, int pid)
+{ Trans *t; uchar *othis = this;
+ int res = 0; int tt; uchar ot;
+#ifdef VERI
+ /* if (pid > 0) */ pid++;
+#endif
+ if (pid == iam)
+ Uerror("used: enabled(pid=thisproc)");
+ if (pid < 0 || pid >= (int) now._nr_pr)
+ return 0;
+ this = pptr(pid);
+ TstOnly = 1;
+ tt = (int) ((P0 *)this)->_p;
+ ot = (uchar) ((P0 *)this)->_t;
+ for (t = trans[ot][tt]; t; t = t->nxt)
+ if (do_transit(t, (short) pid))
+ { res = 1;
+ break;
+ }
+ TstOnly = 0;
+ this = othis;
+ return res;
+}
+#endif
+void
+snap_time(void)
+{ clock_t stop_time;
+ double delta_time;
+#if !defined(WIN32) && !defined(WIN64)
+ struct tms stop_tm;
+ stop_time = times(&stop_tm);
+ delta_time = ((double) (stop_time - start_time)) / ((double) sysconf(_SC_CLK_TCK));
+#else
+ stop_time = clock();
+ delta_time = ((double) (stop_time - start_time)) / ((double) CLOCKS_PER_SEC);
+#endif
+ if (delta_time > 0.01)
+ { printf("t= %6.3g ", delta_time);
+ printf("R= %7.0g", nstates/delta_time);
+ }
+ printf("\n");
+ if (quota > 0.1 && delta_time > quota)
+ { printf("Time limit of %6.3g minutes exceeded\n", quota/60.0);
+#if NCORE>1
+ fflush(stdout);
+ leave_critical(GLOBAL_LOCK);
+ sudden_stop("time-limit");
+ exit(1);
+#endif
+ wrapup();
+ }
+}
+void
+snapshot(void)
+{
+#if NCORE>1
+ enter_critical(GLOBAL_LOCK); /* snapshot */
+ printf("cpu%d: ", core_id);
+#endif
+ printf("Depth= %7ld States= %8.3g ",
+#if NCORE>1
+ (long) (nr_handoffs * z_handoff) +
+#endif
+ mreached, nstates);
+ printf("Transitions= %8.3g ", nstates+truncs);
+#ifdef MA
+ printf("Nodes= %7d ", nr_states);
+#endif
+ printf("Memory= %9.3f\t", memcnt/1048576.);
+ snap_time();
+ fflush(stdout);
+#if NCORE>1
+ leave_critical(GLOBAL_LOCK);
+#endif
+}
+#ifdef SC
+void
+stack2disk(void)
+{
+ if (!stackwrite
+ && (stackwrite = creat(stackfile, TMODE)) < 0)
+ Uerror("cannot create stackfile");
+
+ if (write(stackwrite, trail, DDD*sizeof(Trail))
+ != DDD*sizeof(Trail))
+ Uerror("stackfile write error -- disk is full?");
+
+ memmove(trail, &trail[DDD], (HHH-DDD+2)*sizeof(Trail));
+ memset(&trail[HHH-DDD+2], 0, (omaxdepth - HHH + DDD - 2)*sizeof(Trail));
+ CNT1++;
+}
+void
+disk2stack(void)
+{ long have;
+
+ CNT2++;
+ memmove(&trail[DDD], trail, (HHH-DDD+2)*sizeof(Trail));
+
+ if (!stackwrite
+ || lseek(stackwrite, -DDD* (off_t) sizeof(Trail), SEEK_CUR) == -1)
+ Uerror("disk2stack lseek error");
+
+ if (!stackread
+ && (stackread = open(stackfile, 0)) < 0)
+ Uerror("cannot open stackfile");
+
+ if (lseek(stackread, (CNT1-CNT2)*DDD* (off_t) sizeof(Trail), SEEK_SET) == -1)
+ Uerror("disk2stack lseek error");
+
+ have = read(stackread, trail, DDD*sizeof(Trail));
+ if (have != DDD*sizeof(Trail))
+ Uerror("stackfile read error");
+}
+#endif
+uchar *
+Pptr(int x)
+{ if (x < 0 || x >= MAXPROC || !proc_offset[x])
+ return noptr;
+ else
+ return (uchar *) pptr(x);
+}
+int qs_empty(void);
+/*
+ * new_state() is the main DFS search routine in the verifier
+ * it has a lot of code ifdef-ed together to support
+ * different search modes, which makes it quite unreadable.
+ * if you are studying the code, first use the C preprocessor
+ * to generate a specific version from the pan.c source,
+ * e.g. by saying:
+ * gcc -E -DNOREDUCE -DBITSTATE pan.c > ppan.c
+ * and then study the resulting file, rather than this one
+ */
+#if !defined(BFS) && (!defined(BITSTATE) || !defined(MA))
+
+#ifdef NSUCC
+int N_succ[512];
+void
+tally_succ(int cnt)
+{ if (cnt < 512) N_succ[cnt]++;
+ else printf("tally_succ: cnt %d exceeds range\n", cnt);
+}
+
+void
+dump_succ(void)
+{ int i; double sum = 0.0;
+ double w_avg = 0.0;
+ printf("Successor counts:\n");
+ for (i = 0; i < 512; i++)
+ { sum += (double) N_succ[i];
+ }
+ for (i = 0; i < 512; i++)
+ { if (N_succ[i] > 0)
+ { printf("%3d %10d (%.4g %% of total)\n",
+ i, N_succ[i], (100.0 * (double) N_succ[i])/sum);
+ w_avg += (double) i * (double) N_succ[i];
+ } }
+ if (sum > N_succ[0])
+ printf("mean %.4g (without 0: %.4g)\n", w_avg / sum, w_avg / (sum - (double) N_succ[0]));
+}
+#endif
+
+void
+new_state(void)
+{ Trans *t;
+ uchar _n, _m, ot;
+#ifdef RANDOMIZE
+ short ooi, eoi;
+#endif
+#ifdef M_LOSS
+ uchar delta_m = 0;
+#endif
+ short II, JJ = 0, kk;
+ int tt;
+#ifdef REVERSE
+ short From = BASE, To = now._nr_pr-1;
+#else
+ short From = now._nr_pr-1, To = BASE;
+#endif
+Down:
+#ifdef CHECK
+ cpu_printf("%d: Down - %s %saccepting [pids %d-%d]\n",
+ depth, (trpt->tau&4)?"claim":"program",
+ (trpt->o_pm&2)?"":"non-", From, To);
+#endif
+#ifdef SCHED
+ if (depth > 0)
+ { trpt->sched_limit = (trpt-1)->sched_limit;
+ } else
+ { trpt->sched_limit = 0;
+ }
+#endif
+#ifdef SC
+ if (depth > hiwater)
+ { stack2disk();
+ maxdepth += DDD;
+ hiwater += DDD;
+ trpt -= DDD;
+ if(verbose)
+ printf("zap %d: %d (maxdepth now %d)\n",
+ CNT1, hiwater, maxdepth);
+ }
+#endif
+ trpt->tau &= ~(16|32|64); /* make sure these are off */
+#if defined(FULLSTACK) && defined(MA)
+ trpt->proviso = 0;
+#endif
+#ifdef NSUCC
+ trpt->n_succ = 0;
+#endif
+#if NCORE>1
+ if (mem_hand_off())
+ {
+#if SYNC
+ (trpt+1)->o_n = 1; /* not a deadlock: as below */
+#endif
+#ifndef LOOPSTATE
+ (trpt-1)->tau |= 16; /* worstcase guess: as below */
+#endif
+#if NCORE>1 && defined(FULL_TRAIL)
+ if (upto > 0)
+ { Pop_Stack_Tree();
+ }
+#endif
+ goto Up;
+ }
+#endif
+ if (depth >= maxdepth)
+ { if (!warned)
+ { warned = 1;
+ printf("error: max search depth too small\n");
+ }
+ if (bounded)
+ { uerror("depth limit reached");
+ }
+ truncs++;
+#if SYNC
+ (trpt+1)->o_n = 1; /* not a deadlock */
+#endif
+#ifndef LOOPSTATE
+ (trpt-1)->tau |= 16; /* worstcase guess */
+#endif
+#if NCORE>1 && defined(FULL_TRAIL)
+ if (upto > 0)
+ { Pop_Stack_Tree();
+ }
+#endif
+ goto Up;
+ }
+AllOver:
+#if (defined(FULLSTACK) && !defined(MA)) || NCORE>1
+ /* if atomic or rv move, carry forward previous state */
+ trpt->ostate = (trpt-1)->ostate;
+#endif
+#ifdef VERI
+ if ((trpt->tau&4) || ((trpt-1)->tau&128))
+#endif
+ if (boq == -1) { /* if not mid-rv */
+#ifndef SAFETY
+ /* this check should now be redundant
+ * because the seed state also appears
+ * on the 1st dfs stack and would be
+ * matched in hstore below
+ */
+ if ((now._a_t&1) && depth > A_depth)
+ { if (!memcmp((char *)&A_Root,
+ (char *)&now, vsize))
+ {
+ depthfound = A_depth;
+#ifdef CHECK
+ printf("matches seed\n");
+#endif
+#ifdef NP
+ uerror("non-progress cycle");
+#else
+ uerror("acceptance cycle");
+#endif
+#if NCORE>1 && defined(FULL_TRAIL)
+ if (upto > 0)
+ { Pop_Stack_Tree();
+ }
+#endif
+ goto Up;
+ }
+#ifdef CHECK
+ printf("not seed\n");
+#endif
+ }
+#endif
+ if (!(trpt->tau&8)) /* if no atomic move */
+ {
+#ifdef BITSTATE
+#ifdef CNTRSTACK
+ II = bstore((char *)&now, vsize);
+ trpt->j6 = j1; trpt->j7 = j2;
+ JJ = LL[j1] && LL[j2];
+#else
+#ifdef FULLSTACK
+ JJ = onstack_now();
+#else
+#ifndef NOREDUCE
+ JJ = II; /* worstcase guess for p.o. */
+#endif
+#endif
+ II = bstore((char *)&now, vsize);
+#endif
+#else
+#ifdef MA
+ II = gstore((char *)&now, vsize, 0);
+#ifndef FULLSTACK
+ JJ = II;
+#else
+ JJ = (II == 2)?1:0;
+#endif
+#else
+ II = hstore((char *)&now, vsize);
+#ifdef FULLSTACK
+ JJ = (II == 2)?1:0;
+#endif
+#endif
+#endif
+ kk = (II == 1 || II == 2);
+#ifndef SAFETY
+#if NCORE==1 || defined (SEP_STATE)
+ if (II == 2 && ((trpt->o_pm&2) || ((trpt-1)->o_pm&2)))
+ #ifndef NOFAIR
+#if 0
+ if (!fairness || ((now._a_t&1) && now._cnt[1] == 1)) /* 5.1.4 */
+#else
+ if (a_cycles && !fairness) /* 5.1.6 -- example by Hirofumi Watanabe */
+#endif
+ #endif
+ {
+ II = 3; /* Schwoon & Esparza 2005, Gastin&Moro 2004 */
+#ifdef VERBOSE
+ printf("state match on dfs stack\n");
+#endif
+ goto same_case;
+ }
+#endif
+#if defined(FULLSTACK) && defined(BITSTATE)
+ if (!JJ && (now._a_t&1) && depth > A_depth)
+ { int oj1 = j1;
+ uchar o_a_t = now._a_t;
+ now._a_t &= ~(1|16|32);
+ if (onstack_now())
+ { II = 3;
+#ifdef VERBOSE
+ printf("state match on 1st dfs stack\n");
+#endif
+ }
+ now._a_t = o_a_t;
+ j1 = oj1;
+ }
+#endif
+ if (II == 3 && a_cycles && (now._a_t&1))
+ {
+#ifndef NOFAIR
+ if (fairness && now._cnt[1] > 1) /* was != 0 */
+ {
+#ifdef VERBOSE
+ printf(" fairness count non-zero\n");
+#endif
+ II = 0;
+ } else
+#endif
+ {
+#ifndef BITSTATE
+ nShadow--;
+#endif
+same_case: if (Lstate) depthfound = Lstate->D;
+#ifdef NP
+ uerror("non-progress cycle");
+#else
+ uerror("acceptance cycle");
+#endif
+#if NCORE>1 && defined(FULL_TRAIL)
+ if (upto > 0)
+ { Pop_Stack_Tree();
+ }
+#endif
+ goto Up;
+ }
+ }
+#endif
+#ifndef NOREDUCE
+#ifndef SAFETY
+#if NCORE>1 && !defined(SEP_STATE) && defined(V_PROVISO)
+ if (II != 0 && (!Lstate || Lstate->cpu_id < core_id))
+ { (trpt-1)->tau |= 16;
+ }
+#endif
+ if ((II && JJ) || (II == 3))
+ { /* marker for liveness proviso */
+#ifndef LOOPSTATE
+ (trpt-1)->tau |= 16;
+#endif
+ truncs2++;
+ }
+#else
+#if NCORE>1 && !defined(SEP_STATE) && defined(V_PROVISO)
+ if (!(II != 0 && (!Lstate || Lstate->cpu_id < core_id)))
+ { /* treat as stack state */
+ (trpt-1)->tau |= 16;
+ } else
+ { /* treat as non-stack state */
+ (trpt-1)->tau |= 64;
+ }
+#endif
+ if (!II || !JJ)
+ { /* successor outside stack */
+ (trpt-1)->tau |= 64;
+ }
+#endif
+#endif
+ if (II)
+ { truncs++;
+#if NCORE>1 && defined(FULL_TRAIL)
+ if (upto > 0)
+ { Pop_Stack_Tree();
+ if (depth == 0)
+ { return;
+ } }
+#endif
+ goto Up;
+ }
+ if (!kk)
+ { static long sdone = (long) 0; long ndone;
+ nstates++;
+#if defined(ZAPH) && defined(BITSTATE)
+ zstates += (double) hfns;
+#endif
+ ndone = (unsigned long) (nstates/((double) FREQ));
+ if (ndone != sdone)
+ { snapshot();
+ sdone = ndone;
+#if defined(AUTO_RESIZE) && !defined(BITSTATE) && !defined(MA)
+ if (nstates > ((double)(ONE_L<<(ssize+1))))
+ { void resize_hashtable(void);
+ resize_hashtable();
+ }
+#endif
+#if defined(ZAPH) && defined(BITSTATE)
+ if (zstates > ((double)(ONE_L<<(ssize-2))))
+ { /* more than half the bits set */
+ void zap_hashtable(void);
+ zap_hashtable();
+ zstates = 0;
+ }
+#endif
+ }
+#ifdef SVDUMP
+ if (vprefix > 0)
+ if (write(svfd, (uchar *) &now, vprefix) != vprefix)
+ { fprintf(efd, "writing %s.svd failed\n", PanSource);
+ wrapup();
+ }
+#endif
+#if defined(MA) && defined(W_XPT)
+ if ((unsigned long) nstates%W_XPT == 0)
+ { void w_xpoint(void);
+ w_xpoint();
+ }
+#endif
+ }
+#if defined(FULLSTACK) || defined(CNTRSTACK)
+ onstack_put();
+#ifdef DEBUG2
+#if defined(FULLSTACK) && !defined(MA)
+ printf("%d: putting %u (%d)\n", depth,
+ trpt->ostate,
+ (trpt->ostate)?trpt->ostate->tagged:0);
+#else
+ printf("%d: putting\n", depth);
+#endif
+#endif
+#else
+ #if NCORE>1
+ trpt->ostate = Lstate;
+ #endif
+#endif
+ } }
+ if (depth > mreached)
+ mreached = depth;
+#ifdef VERI
+ if (trpt->tau&4)
+#endif
+ trpt->tau &= ~(1|2); /* timeout and -request off */
+ _n = 0;
+#if SYNC
+ (trpt+1)->o_n = 0;
+#endif
+#ifdef VERI
+ if (now._nr_pr == 0) /* claim terminated */
+ uerror("end state in claim reached");
+ check_claim(((P0 *)pptr(0))->_p);
+Stutter:
+ if (trpt->tau&4) /* must make a claimmove */
+ {
+#ifndef NOFAIR
+ if ((now._a_t&2) /* A-bit set */
+ && now._cnt[now._a_t&1] == 1)
+ { now._a_t &= ~2;
+ now._cnt[now._a_t&1] = 0;
+ trpt->o_pm |= 16;
+#ifdef DEBUG
+ printf("%3d: fairness Rule 3.: _a_t = %d\n",
+ depth, now._a_t);
+#endif
+ }
+#endif
+ II = 0; /* never */
+ goto Veri0;
+ }
+#endif
+#ifndef NOREDUCE
+ /* Look for a process with only safe transitions */
+ /* (special rules apply in the 2nd dfs) */
+ if (boq == -1 && From != To
+
+#ifdef SAFETY
+ #if NCORE>1
+ && (depth < z_handoff)
+ #endif
+ )
+#else
+ #if NCORE>1
+ && ((a_cycles) || (!a_cycles && depth < z_handoff))
+ #endif
+ && (!(now._a_t&1)
+ || (a_cycles &&
+ #ifndef BITSTATE
+#ifdef MA
+#ifdef VERI
+ !((trpt-1)->proviso))
+#else
+ !(trpt->proviso))
+#endif
+#else
+#ifdef VERI
+ (trpt-1)->ostate &&
+ !(((char *)&((trpt-1)->ostate->state))[0] & 128))
+#else
+ !(((char *)&(trpt->ostate->state))[0] & 128))
+#endif
+#endif
+ #else
+#ifdef VERI
+ (trpt-1)->ostate &&
+ (trpt-1)->ostate->proviso == 0)
+#else
+ trpt->ostate->proviso == 0)
+#endif
+ #endif
+ ))
+#endif
+
+#ifdef REVERSE
+ for (II = From; II <= To; II++)
+#else
+ for (II = From; II >= To; II--)
+#endif
+ {
+Resume: /* pick up here if preselect fails */
+ this = pptr(II);
+ tt = (int) ((P0 *)this)->_p;
+ ot = (uchar) ((P0 *)this)->_t;
+ if (trans[ot][tt]->atom & 8)
+ { t = trans[ot][tt];
+ if (t->qu[0] != 0)
+ { Ccheck++;
+ if (!q_cond(II, t))
+ continue;
+ Cholds++;
+ }
+ From = To = II; /* the process preselected */
+#ifdef NIBIS
+ t->om = 0;
+#endif
+ trpt->tau |= 32; /* preselect marker */
+#ifdef DEBUG
+#ifdef NIBIS
+ printf("%3d: proc %d Pre", depth, II);
+ printf("Selected (om=%d, tau=%d)\n",
+ t->om, trpt->tau);
+#else
+ printf("%3d: proc %d PreSelected (tau=%d)\n",
+ depth, II, trpt->tau);
+#endif
+#endif
+ goto Again;
+ }
+ }
+ trpt->tau &= ~32;
+#endif
+#if !defined(NOREDUCE) || (defined(ETIM) && !defined(VERI))
+Again:
+#endif
+ /* The Main Expansion Loop over Processes */
+ trpt->o_pm &= ~(8|16|32|64); /* fairness-marks */
+#ifndef NOFAIR
+ if (fairness && boq == -1
+#ifdef VERI
+ && (!(trpt->tau&4) && !((trpt-1)->tau&128))
+#endif
+ && !(trpt->tau&8))
+ { /* A_bit = 1; Cnt = N in acc states with A_bit 0 */
+ if (!(now._a_t&2))
+ {
+ if (a_cycles && (trpt->o_pm&2))
+ { /* Accepting state */
+ now._a_t |= 2;
+ now._cnt[now._a_t&1] = now._nr_pr + 1;
+ trpt->o_pm |= 8;
+#ifdef DEBUG
+ printf("%3d: fairness Rule 1: cnt=%d, _a_t=%d\n",
+ depth, now._cnt[now._a_t&1], now._a_t);
+#endif
+ }
+ } else
+ { /* A_bit = 0 when Cnt 0 */
+ if (now._cnt[now._a_t&1] == 1)
+ { now._a_t &= ~2;
+ now._cnt[now._a_t&1] = 0;
+ trpt->o_pm |= 16;
+#ifdef DEBUG
+ printf("%3d: fairness Rule 3: _a_t = %d\n",
+ depth, now._a_t);
+#endif
+ } } }
+#endif
+
+#ifdef REVERSE
+ for (II = From; II <= To; II++)
+#else
+ for (II = From; II >= To; II--)
+#endif
+ {
+#if SYNC
+ /* no rendezvous with same proc */
+ if (boq != -1 && trpt->pr == II) continue;
+#endif
+#ifdef SCHED
+ /* limit max nr of interleavings */
+ if (From != To
+ && depth > 0
+ #ifdef VERI
+ && II != 0
+ #endif
+ && (trpt-1)->pr != II
+ && trpt->sched_limit >= sched_max)
+ { continue;
+ }
+#endif
+#ifdef VERI
+Veri0:
+#endif
+ this = pptr(II);
+ tt = (int) ((P0 *)this)->_p;
+ ot = (uchar) ((P0 *)this)->_t;
+#ifdef NIBIS
+ /* don't repeat a previous preselected expansion */
+ /* could hit this if reduction proviso was false */
+ t = trans[ot][tt];
+ if (!(trpt->tau&4)
+ && !(trpt->tau&1)
+ && !(trpt->tau&32)
+ && (t->atom & 8)
+ && boq == -1
+ && From != To)
+ { if (t->qu[0] == 0
+ || q_cond(II, t))
+ { _m = t->om;
+ if (_m>_n||(_n>3&&_m!=0)) _n=_m;
+ continue; /* did it before */
+ } }
+#endif
+ trpt->o_pm &= ~1; /* no move in this pid yet */
+#ifdef EVENT_TRACE
+ (trpt+1)->o_event = now._event;
+#endif
+ /* Fairness: Cnt++ when Cnt == II */
+#ifndef NOFAIR
+ trpt->o_pm &= ~64; /* didn't apply rule 2 */
+ if (fairness
+ && boq == -1
+ && !(trpt->o_pm&32)
+ && (now._a_t&2)
+ && now._cnt[now._a_t&1] == II+2)
+ { now._cnt[now._a_t&1] -= 1;
+#ifdef VERI
+ /* claim need not participate */
+ if (II == 1)
+ now._cnt[now._a_t&1] = 1;
+#endif
+#ifdef DEBUG
+ printf("%3d: proc %d fairness ", depth, II);
+ printf("Rule 2: --cnt to %d (%d)\n",
+ now._cnt[now._a_t&1], now._a_t);
+#endif
+ trpt->o_pm |= (32|64);
+ }
+#endif
+#ifdef HAS_PROVIDED
+ if (!provided(II, ot, tt, t)) continue;
+#endif
+ /* check all trans of proc II - escapes first */
+#ifdef HAS_UNLESS
+ trpt->e_state = 0;
+#endif
+ (trpt+1)->pr = (uchar) II;
+ (trpt+1)->st = tt;
+#ifdef RANDOMIZE
+ for (ooi = eoi = 0, t = trans[ot][tt]; t; t = t->nxt, ooi++)
+ { if (strcmp(t->tp, "else") == 0)
+ { eoi++;
+ break;
+ } }
+ if (eoi > 0)
+ { t = trans[ot][tt];
+ #ifdef VERBOSE
+ printf("randomizer: suppressed, saw else\n");
+ #endif
+ } else
+ { eoi = rand()%ooi;
+ #ifdef VERBOSE
+ printf("randomizer: skip %d in %d\n", eoi, ooi);
+ #endif
+ for (t = trans[ot][tt]; t; t = t->nxt)
+ if (eoi-- <= 0) break;
+ }
+domore:
+ for ( ; t && ooi > 0; t = t->nxt, ooi--)
+#else
+ for (t = trans[ot][tt]; t; t = t->nxt)
+#endif
+ {
+#ifdef HAS_UNLESS
+ /* exploring all transitions from
+ * a single escape state suffices
+ */
+ if (trpt->e_state > 0
+ && trpt->e_state != t->e_trans)
+ {
+#ifdef DEBUG
+ printf("skip 2nd escape %d (did %d before)\n",
+ t->e_trans, trpt->e_state);
+#endif
+ break;
+ }
+#endif
+ (trpt+1)->o_t = t;
+#ifdef INLINE
+#include FORWARD_MOVES
+P999: /* jumps here when move succeeds */
+#else
+ if (!(_m = do_transit(t, II))) continue;
+#endif
+#ifdef SCHED
+ if (depth > 0
+ #ifdef VERI
+ && II != 0
+ #endif
+ && (trpt-1)->pr != II)
+ { trpt->sched_limit = 1 + (trpt-1)->sched_limit;
+ }
+#endif
+ if (boq == -1)
+#ifdef CTL
+ /* for branching-time, can accept reduction only if */
+ /* the persistent set contains just 1 transition */
+ { if ((trpt->tau&32) && (trpt->o_pm&1))
+ trpt->tau |= 16;
+ trpt->o_pm |= 1; /* we moved */
+ }
+#else
+ trpt->o_pm |= 1; /* we moved */
+#endif
+#ifdef LOOPSTATE
+ if (loopstate[ot][tt])
+ {
+#ifdef VERBOSE
+ printf("exiting from loopstate:\n");
+#endif
+ trpt->tau |= 16;
+ cnt_loops++;
+ }
+#endif
+#ifdef PEG
+ peg[t->forw]++;
+#endif
+#if defined(VERBOSE) || defined(CHECK)
+#if defined(SVDUMP)
+ cpu_printf("%3d: proc %d exec %d \n", depth, II, t->t_id);
+#else
+ cpu_printf("%3d: proc %d exec %d, %d to %d, %s %s %s %saccepting [tau=%d]\n",
+ depth, II, t->forw, tt, t->st, t->tp,
+ (t->atom&2)?"atomic":"",
+ (boq != -1)?"rendez-vous":"",
+ (trpt->o_pm&2)?"":"non-", trpt->tau);
+#ifdef HAS_UNLESS
+ if (t->e_trans)
+ cpu_printf("\t(escape to state %d)\n", t->st);
+#endif
+#endif
+#ifdef RANDOMIZE
+ cpu_printf("\t(randomizer %d)\n", ooi);
+#endif
+#endif
+#ifdef HAS_LAST
+#ifdef VERI
+ if (II != 0)
+#endif
+ now._last = II - BASE;
+#endif
+#ifdef HAS_UNLESS
+ trpt->e_state = t->e_trans;
+#endif
+ depth++; trpt++;
+ trpt->pr = (uchar) II;
+ trpt->st = tt;
+ trpt->o_pm &= ~(2|4);
+ if (t->st > 0)
+ { ((P0 *)this)->_p = t->st;
+/* moved down reached[ot][t->st] = 1; */
+ }
+#ifndef SAFETY
+ if (a_cycles)
+ {
+#if (ACCEPT_LAB>0 && !defined(NP)) || (PROG_LAB>0 && defined(HAS_NP))
+ int ii;
+#endif
+#define P__Q ((P0 *)pptr(ii))
+#if ACCEPT_LAB>0
+#ifdef NP
+ /* state 1 of np_ claim is accepting */
+ if (((P0 *)pptr(0))->_p == 1)
+ trpt->o_pm |= 2;
+#else
+ for (ii = 0; ii < (int) now._nr_pr; ii++)
+ { if (accpstate[P__Q->_t][P__Q->_p])
+ { trpt->o_pm |= 2;
+ break;
+ } }
+#endif
+#endif
+#if defined(HAS_NP) && PROG_LAB>0
+ for (ii = 0; ii < (int) now._nr_pr; ii++)
+ { if (progstate[P__Q->_t][P__Q->_p])
+ { trpt->o_pm |= 4;
+ break;
+ } }
+#endif
+#undef P__Q
+ }
+#endif
+ trpt->o_t = t; trpt->o_n = _n;
+ trpt->o_ot = ot; trpt->o_tt = tt;
+ trpt->o_To = To; trpt->o_m = _m;
+ trpt->tau = 0;
+#ifdef RANDOMIZE
+ trpt->oo_i = ooi;
+#endif
+ if (boq != -1 || (t->atom&2))
+ { trpt->tau |= 8;
+#ifdef VERI
+ /* atomic sequence in claim */
+ if((trpt-1)->tau&4)
+ trpt->tau |= 4;
+ else
+ trpt->tau &= ~4;
+ } else
+ { if ((trpt-1)->tau&4)
+ trpt->tau &= ~4;
+ else
+ trpt->tau |= 4;
+ }
+ /* if claim allowed timeout, so */
+ /* does the next program-step: */
+ if (((trpt-1)->tau&1) && !(trpt->tau&4))
+ trpt->tau |= 1;
+#else
+ } else
+ trpt->tau &= ~8;
+#endif
+ if (boq == -1 && (t->atom&2))
+ { From = To = II; nlinks++;
+ } else
+#ifdef REVERSE
+ { From = BASE; To = now._nr_pr-1;
+#else
+ { From = now._nr_pr-1; To = BASE;
+#endif
+ }
+#if NCORE>1 && defined(FULL_TRAIL)
+ if (upto > 0)
+ { Push_Stack_Tree(II, t->t_id);
+ }
+#endif
+ goto Down; /* pseudo-recursion */
+Up:
+#ifdef CHECK
+ cpu_printf("%d: Up - %s\n", depth,
+ (trpt->tau&4)?"claim":"program");
+#endif
+#if NCORE>1
+ iam_alive();
+ #ifdef USE_DISK
+ mem_drain();
+ #endif
+#endif
+#if defined(MA) || NCORE>1
+ if (depth <= 0) return;
+ /* e.g., if first state is old, after a restart */
+#endif
+#ifdef SC
+ if (CNT1 > CNT2
+ && depth < hiwater - (HHH-DDD) + 2)
+ {
+ trpt += DDD;
+ disk2stack();
+ maxdepth -= DDD;
+ hiwater -= DDD;
+ if(verbose)
+ printf("unzap %d: %d\n", CNT2, hiwater);
+ }
+#endif
+#ifndef NOFAIR
+ if (trpt->o_pm&128) /* fairness alg */
+ { now._cnt[now._a_t&1] = trpt->bup.oval;
+ _n = 1; trpt->o_pm &= ~128;
+ depth--; trpt--;
+#if defined(VERBOSE) || defined(CHECK)
+ printf("%3d: reversed fairness default move\n", depth);
+#endif
+ goto Q999;
+ }
+#endif
+#ifdef HAS_LAST
+#ifdef VERI
+ { int d; Trail *trl;
+ now._last = 0;
+ for (d = 1; d < depth; d++)
+ { trl = getframe(depth-d); /* was (trpt-d) */
+ if (trl->pr != 0)
+ { now._last = trl->pr - BASE;
+ break;
+ } } }
+#else
+ now._last = (depth<1)?0:(trpt-1)->pr;
+#endif
+#endif
+#ifdef EVENT_TRACE
+ now._event = trpt->o_event;
+#endif
+#ifndef SAFETY
+ if ((now._a_t&1) && depth <= A_depth)
+ return; /* to checkcycles() */
+#endif
+ t = trpt->o_t; _n = trpt->o_n;
+ ot = trpt->o_ot; II = trpt->pr;
+ tt = trpt->o_tt; this = pptr(II);
+ To = trpt->o_To; _m = trpt->o_m;
+#ifdef RANDOMIZE
+ ooi = trpt->oo_i;
+#endif
+#ifdef INLINE_REV
+ _m = do_reverse(t, II, _m);
+#else
+#include REVERSE_MOVES
+R999: /* jumps here when done */
+#endif
+#ifdef VERBOSE
+ cpu_printf("%3d: proc %d reverses %d, %d to %d\n",
+ depth, II, t->forw, tt, t->st);
+ cpu_printf("\t%s [abit=%d,adepth=%d,tau=%d,%d]\n",
+ t->tp, now._a_t, A_depth, trpt->tau, (trpt-1)->tau);
+#endif
+#ifndef NOREDUCE
+ /* pass the proviso tags */
+ if ((trpt->tau&8) /* rv or atomic */
+ && (trpt->tau&16))
+ (trpt-1)->tau |= 16;
+#ifdef SAFETY
+ if ((trpt->tau&8) /* rv or atomic */
+ && (trpt->tau&64))
+ (trpt-1)->tau |= 64;
+#endif
+#endif
+ depth--; trpt--;
+
+#ifdef NSUCC
+ trpt->n_succ++;
+#endif
+#ifdef NIBIS
+ (trans[ot][tt])->om = _m; /* head of list */
+#endif
+ /* i.e., not set if rv fails */
+ if (_m)
+ {
+#if defined(VERI) && !defined(NP)
+ if (II == 0 && verbose && !reached[ot][t->st])
+ {
+ printf("depth %d: Claim reached state %d (line %d)\n",
+ depth, t->st, src_claim [t->st]);
+ fflush(stdout);
+ }
+#endif
+ reached[ot][t->st] = 1;
+ reached[ot][tt] = 1;
+ }
+#ifdef HAS_UNLESS
+ else trpt->e_state = 0; /* undo */
+#endif
+ if (_m>_n||(_n>3&&_m!=0)) _n=_m;
+ ((P0 *)this)->_p = tt;
+ } /* all options */
+#ifdef RANDOMIZE
+ if (!t && ooi > 0)
+ { t = trans[ot][tt];
+ #ifdef VERBOSE
+ printf("randomizer: continue for %d more\n", ooi);
+ #endif
+ goto domore;
+ }
+ #ifdef VERBOSE
+ else
+ printf("randomizer: done\n");
+ #endif
+#endif
+#ifndef NOFAIR
+ /* Fairness: undo Rule 2 */
+ if ((trpt->o_pm&32)
+ && (trpt->o_pm&64))
+ { if (trpt->o_pm&1)
+ {
+#ifdef VERI
+ if (now._cnt[now._a_t&1] == 1)
+ now._cnt[now._a_t&1] = 2;
+#endif
+ now._cnt[now._a_t&1] += 1;
+#ifdef VERBOSE
+ printf("%3d: proc %d fairness ", depth, II);
+ printf("undo Rule 2, cnt=%d, _a_t=%d\n",
+ now._cnt[now._a_t&1], now._a_t);
+#endif
+ trpt->o_pm &= ~(32|64);
+ } else
+ { if (_n > 0)
+ {
+ trpt->o_pm &= ~64;
+#ifdef REVERSE
+ II = From-1;
+#else
+ II = From+1;
+#endif
+ } } }
+#endif
+#ifdef VERI
+ if (II == 0) break; /* never claim */
+#endif
+ } /* all processes */
+#ifdef NSUCC
+ tally_succ(trpt->n_succ);
+#endif
+#ifdef SCHED
+ if (_n == 0 /* no process could move */
+ #ifdef VERI
+ && II != 0
+ #endif
+ && depth > 0
+ && trpt->sched_limit >= sched_max)
+ { _n = 1; /* not a deadlock */
+ }
+#endif
+#ifndef NOFAIR
+ /* Fairness: undo Rule 2 */
+ if (trpt->o_pm&32) /* remains if proc blocked */
+ {
+#ifdef VERI
+ if (now._cnt[now._a_t&1] == 1)
+ now._cnt[now._a_t&1] = 2;
+#endif
+ now._cnt[now._a_t&1] += 1;
+#ifdef VERBOSE
+ printf("%3d: proc -- fairness ", depth);
+ printf("undo Rule 2, cnt=%d, _a_t=%d\n",
+ now._cnt[now._a_t&1], now._a_t);
+#endif
+ trpt->o_pm &= ~32;
+ }
+#ifndef NP
+ if (fairness
+ && _n == 0 /* nobody moved */
+#ifdef VERI
+ && !(trpt->tau&4) /* in program move */
+#endif
+ && !(trpt->tau&8) /* not an atomic one */
+#ifdef OTIM
+ && ((trpt->tau&1) || endstate())
+#else
+#ifdef ETIM
+ && (trpt->tau&1) /* already tried timeout */
+#endif
+#endif
+#ifndef NOREDUCE
+ /* see below */
+ && !((trpt->tau&32) && (_n == 0 || (trpt->tau&16)))
+#endif
+ && now._cnt[now._a_t&1] > 0) /* needed more procs */
+ { depth++; trpt++;
+ trpt->o_pm |= 128 | ((trpt-1)->o_pm&(2|4));
+ trpt->bup.oval = now._cnt[now._a_t&1];
+ now._cnt[now._a_t&1] = 1;
+#ifdef VERI
+ trpt->tau = 4;
+#else
+ trpt->tau = 0;
+#endif
+#ifdef REVERSE
+ From = BASE; To = now._nr_pr-1;
+#else
+ From = now._nr_pr-1; To = BASE;
+#endif
+#if defined(VERBOSE) || defined(CHECK)
+ printf("%3d: fairness default move ", depth);
+ printf("(all procs block)\n");
+#endif
+ goto Down;
+ }
+#endif
+Q999: /* returns here with _n>0 when done */;
+ if (trpt->o_pm&8)
+ { now._a_t &= ~2;
+ now._cnt[now._a_t&1] = 0;
+ trpt->o_pm &= ~8;
+#ifdef VERBOSE
+ printf("%3d: fairness undo Rule 1, _a_t=%d\n",
+ depth, now._a_t);
+#endif
+ }
+ if (trpt->o_pm&16)
+ { now._a_t |= 2;
+ now._cnt[now._a_t&1] = 1;
+ trpt->o_pm &= ~16;
+#ifdef VERBOSE
+ printf("%3d: fairness undo Rule 3, _a_t=%d\n",
+ depth, now._a_t);
+#endif
+ }
+#endif
+#ifndef NOREDUCE
+#ifdef SAFETY
+#ifdef LOOPSTATE
+ /* at least one move that was preselected at this */
+ /* level, blocked or was a loop control flow point */
+ if ((trpt->tau&32) && (_n == 0 || (trpt->tau&16)))
+#else
+ /* preselected move - no successors outside stack */
+ if ((trpt->tau&32) && !(trpt->tau&64))
+#endif
+#ifdef REVERSE
+ { From = BASE; To = now._nr_pr-1;
+#else
+ { From = now._nr_pr-1; To = BASE;
+#endif
+#ifdef DEBUG
+ printf("%3d: proc %d UnSelected (_n=%d, tau=%d)\n",
+ depth, II+1, _n, trpt->tau);
+#endif
+ _n = 0; trpt->tau &= ~(16|32|64);
+#ifdef REVERSE
+ if (II <= To) /* II already decremented */
+#else
+ if (II >= BASE) /* II already decremented */
+#endif
+ goto Resume;
+ else
+ goto Again;
+ }
+#else
+ /* at least one move that was preselected at this */
+ /* level, blocked or truncated at the next level */
+/* implied: #ifdef FULLSTACK */
+ if ((trpt->tau&32) && (_n == 0 || (trpt->tau&16)))
+ {
+#ifdef DEBUG
+ printf("%3d: proc %d UnSelected (_n=%d, tau=%d)\n",
+ depth, II+1, (int) _n, trpt->tau);
+#endif
+ if (a_cycles && (trpt->tau&16))
+ { if (!(now._a_t&1))
+ {
+#ifdef DEBUG
+ printf("%3d: setting proviso bit\n", depth);
+#endif
+#ifndef BITSTATE
+#ifdef MA
+#ifdef VERI
+ (trpt-1)->proviso = 1;
+#else
+ trpt->proviso = 1;
+#endif
+#else
+#ifdef VERI
+ if ((trpt-1)->ostate)
+ ((char *)&((trpt-1)->ostate->state))[0] |= 128;
+#else
+ ((char *)&(trpt->ostate->state))[0] |= 128;
+#endif
+#endif
+#else
+#ifdef VERI
+ if ((trpt-1)->ostate)
+ (trpt-1)->ostate->proviso = 1;
+#else
+ trpt->ostate->proviso = 1;
+#endif
+#endif
+#ifdef REVERSE
+ From = BASE; To = now._nr_pr-1;
+#else
+ From = now._nr_pr-1; To = BASE;
+#endif
+ _n = 0; trpt->tau &= ~(16|32|64);
+ goto Again; /* do full search */
+ } /* else accept reduction */
+ } else
+#ifdef REVERSE
+ { From = BASE; To = now._nr_pr-1;
+#else
+ { From = now._nr_pr-1; To = BASE;
+#endif
+ _n = 0; trpt->tau &= ~(16|32|64);
+#ifdef REVERSE
+ if (II <= To) /* already decremented */
+#else
+ if (II >= BASE) /* already decremented */
+#endif
+ goto Resume;
+ else
+ goto Again;
+ } }
+/* #endif */
+#endif
+#endif
+ if (_n == 0 || ((trpt->tau&4) && (trpt->tau&2)))
+ {
+#ifdef DEBUG
+ cpu_printf("%3d: no move [II=%d, tau=%d, boq=%d]\n",
+ depth, II, trpt->tau, boq);
+#endif
+#if SYNC
+ /* ok if a rendez-vous fails: */
+ if (boq != -1) goto Done;
+#endif
+ /* ok if no procs or we're at maxdepth */
+ if ((now._nr_pr == 0 && (!strict || qs_empty()))
+#ifdef OTIM
+ || endstate()
+#endif
+ || depth >= maxdepth-1) goto Done;
+ if ((trpt->tau&8) && !(trpt->tau&4))
+ { trpt->tau &= ~(1|8);
+ /* 1=timeout, 8=atomic */
+#ifdef REVERSE
+ From = BASE; To = now._nr_pr-1;
+#else
+ From = now._nr_pr-1; To = BASE;
+#endif
+#ifdef DEBUG
+ cpu_printf("%3d: atomic step proc %d unexecutable\n", depth, II+1);
+#endif
+#ifdef VERI
+ trpt->tau |= 4; /* switch to claim */
+#endif
+ goto AllOver;
+ }
+#ifdef ETIM
+ if (!(trpt->tau&1)) /* didn't try timeout yet */
+ {
+#ifdef VERI
+ if (trpt->tau&4)
+ {
+#ifndef NTIM
+ if (trpt->tau&2) /* requested */
+#endif
+ { trpt->tau |= 1;
+ trpt->tau &= ~2;
+#ifdef DEBUG
+ cpu_printf("%d: timeout\n", depth);
+#endif
+ goto Stutter;
+ } }
+ else
+ { /* only claim can enable timeout */
+ if ((trpt->tau&8)
+ && !((trpt-1)->tau&4))
+/* blocks inside an atomic */ goto BreakOut;
+#ifdef DEBUG
+ cpu_printf("%d: req timeout\n",
+ depth);
+#endif
+ (trpt-1)->tau |= 2; /* request */
+#if NCORE>1 && defined(FULL_TRAIL)
+ if (upto > 0)
+ { Pop_Stack_Tree();
+ }
+#endif
+ goto Up;
+ }
+#else
+#ifdef DEBUG
+ cpu_printf("%d: timeout\n", depth);
+#endif
+ trpt->tau |= 1;
+ goto Again;
+#endif
+ }
+#endif
+#ifdef VERI
+BreakOut:
+#ifndef NOSTUTTER
+ if (!(trpt->tau&4))
+ { trpt->tau |= 4; /* claim stuttering */
+ trpt->tau |= 128; /* stutter mark */
+#ifdef DEBUG
+ cpu_printf("%d: claim stutter\n", depth);
+#endif
+ goto Stutter;
+ }
+#else
+ ;
+#endif
+#else
+ if (!noends && !a_cycles && !endstate())
+ { depth--; trpt--; /* new 4.2.3 */
+ uerror("invalid end state");
+ depth++; trpt++;
+ }
+#ifndef NOSTUTTER
+ else if (a_cycles && (trpt->o_pm&2)) /* new 4.2.4 */
+ { depth--; trpt--;
+ uerror("accept stutter");
+ depth++; trpt++;
+ }
+#endif
+#endif
+ }
+Done:
+ if (!(trpt->tau&8)) /* not in atomic seqs */
+ {
+#ifndef SAFETY
+ if (_n != 0
+#ifdef VERI
+ /* --after-- a program-step, i.e., */
+ /* after backtracking a claim-step */
+ && (trpt->tau&4)
+ /* with at least one running process */
+ /* unless in a stuttered accept state */
+ && ((now._nr_pr > 1) || (trpt->o_pm&2))
+#endif
+ && !(now._a_t&1))
+ {
+#ifndef NOFAIR
+ if (fairness)
+ {
+#ifdef VERBOSE
+ cpu_printf("Consider check %d %d...\n",
+ now._a_t, now._cnt[0]);
+#endif
+ if ((now._a_t&2) /* A-bit */
+ && (now._cnt[0] == 1))
+ checkcycles();
+ } else
+#endif
+ if (a_cycles && (trpt->o_pm&2))
+ checkcycles();
+ }
+#endif
+#ifndef MA
+#if defined(FULLSTACK) || defined(CNTRSTACK)
+#ifdef VERI
+ if (boq == -1
+ && (((trpt->tau&4) && !(trpt->tau&128))
+ || ( (trpt-1)->tau&128)))
+#else
+ if (boq == -1)
+#endif
+ {
+#ifdef DEBUG2
+#if defined(FULLSTACK)
+ printf("%d: zapping %u (%d)\n",
+ depth, trpt->ostate,
+ (trpt->ostate)?trpt->ostate->tagged:0);
+#endif
+#endif
+ onstack_zap();
+ }
+#endif
+#else
+#ifdef VERI
+ if (boq == -1
+ && (((trpt->tau&4) && !(trpt->tau&128))
+ || ( (trpt-1)->tau&128)))
+#else
+ if (boq == -1)
+#endif
+ {
+#ifdef DEBUG
+ printf("%d: zapping\n", depth);
+#endif
+ onstack_zap();
+#ifndef NOREDUCE
+ if (trpt->proviso)
+ gstore((char *) &now, vsize, 1);
+#endif
+ }
+#endif
+ }
+ if (depth > 0)
+ {
+#if NCORE>1 && defined(FULL_TRAIL)
+ if (upto > 0)
+ { Pop_Stack_Tree();
+ }
+#endif
+ goto Up;
+ }
+}
+
+#else
+void new_state(void) { /* place holder */ }
+#endif
+
+void
+assert(int a, char *s, int ii, int tt, Trans *t)
+{
+ if (!a && !noasserts)
+ { char bad[1024];
+ strcpy(bad, "assertion violated ");
+ if (strlen(s) > 1000)
+ { strncpy(&bad[19], (const char *) s, 1000);
+ bad[1019] = '\0';
+ } else
+ strcpy(&bad[19], s);
+ uerror(bad);
+ }
+}
+#ifndef NOBOUNDCHECK
+int
+Boundcheck(int x, int y, int a1, int a2, Trans *a3)
+{
+ assert((x >= 0 && x < y), "- invalid array index",
+ a1, a2, a3);
+ return x;
+}
+#endif
+void
+wrap_stats(void)
+{
+ if (nShadow>0)
+ printf("%9.8g states, stored (%g visited)\n",
+ nstates - nShadow, nstates);
+ else
+ printf("%9.8g states, stored\n", nstates);
+#ifdef BFS
+#if SYNC
+ printf(" %8g nominal states (- rv and atomic)\n", nstates-midrv-nlinks+revrv);
+ printf(" %8g rvs succeeded\n", midrv-failedrv);
+#else
+ printf(" %8g nominal states (stored-atomic)\n", nstates-nlinks);
+#endif
+#ifdef DEBUG
+ printf(" %8g midrv\n", midrv);
+ printf(" %8g failedrv\n", failedrv);
+ printf(" %8g revrv\n", revrv);
+#endif
+#endif
+ printf("%9.8g states, matched\n", truncs);
+#ifdef CHECK
+ printf("%9.8g matches within stack\n",truncs2);
+#endif
+ if (nShadow>0)
+ printf("%9.8g transitions (= visited+matched)\n",
+ nstates+truncs);
+ else
+ printf("%9.8g transitions (= stored+matched)\n",
+ nstates+truncs);
+ printf("%9.8g atomic steps\n", nlinks);
+ if (nlost) printf("%g lost messages\n", (double) nlost);
+
+#ifndef BITSTATE
+ printf("hash conflicts: %9.8g (resolved)\n", hcmp);
+ #ifndef AUTO_RESIZE
+ if (hcmp > (double) (1<<ssize))
+ { printf("hint: increase hashtable-size (-w) to reduce runtime\n");
+ } /* in multi-core: also reduces lock delays on access to hashtable */
+ #endif
+#else
+#ifdef CHECK
+ printf("%8g states allocated for dfs stack\n", ngrabs);
+#endif
+ if (udmem)
+ printf("\nhash factor: %4g (best if > 100.)\n\n",
+ (double)(((double) udmem) * 8.0) / (double) nstates);
+ else
+ printf("\nhash factor: %4g (best if > 100.)\n\n",
+ (double)(1<<(ssize-8)) / (double) nstates * 256.0);
+ printf("bits set per state: %u (-k%u)\n", hfns, hfns);
+ #if 0
+ if (udmem)
+ { printf("total bits available: %8g (-M%ld)\n",
+ ((double) udmem) * 8.0, udmem/(1024L*1024L));
+ } else
+ printf("total bits available: %8g (-w%d)\n",
+ ((double) (ONE_L << (ssize-4)) * 16.0), ssize);
+ #endif
+#endif
+#ifdef BFS_DISK
+ printf("bfs disk reads: %ld writes %ld -- diff %ld\n",
+ bfs_dsk_reads, bfs_dsk_writes, bfs_dsk_writes-bfs_dsk_reads);
+ if (bfs_dsk_read >= 0) (void) close(bfs_dsk_read);
+ if (bfs_dsk_write >= 0) (void) close(bfs_dsk_write);
+ (void) unlink("pan_bfs_dsk.tmp");
+#endif
+}
+
+void
+wrapup(void)
+{
+#if defined(BITSTATE) || !defined(NOCOMP)
+ double nr1, nr2, nr3 = 0.0, nr4, nr5 = 0.0;
+ #if !defined(MA) && (defined(MEMCNT) || defined(MEMLIM))
+ int mverbose = 1;
+ #else
+ int mverbose = verbose;
+ #endif
+#endif
+#if NCORE>1
+ if (verbose) cpu_printf("wrapup -- %d error(s)\n", errors);
+ if (core_id != 0)
+ {
+#ifdef USE_DISK
+ void dsk_stats(void);
+ dsk_stats();
+#endif
+ if (search_terminated != NULL)
+ { *search_terminated |= 2; /* wrapup */
+ }
+ exit(0); /* normal termination, not an error */
+ }
+#endif
+#if !defined(WIN32) && !defined(WIN64)
+ signal(SIGINT, SIG_DFL);
+#endif
+ printf("\n(%s)\n", SpinVersion);
+ if (!done) printf("Warning: Search not completed\n");
+#ifdef SC
+ (void) unlink((const char *)stackfile);
+#endif
+#if NCORE>1
+ if (a_cycles)
+ { printf(" + Multi-Core (NCORE=%d)\n", NCORE);
+ } else
+ { printf(" + Multi-Core (NCORE=%d -z%d)\n", NCORE, z_handoff);
+ }
+#endif
+#ifdef BFS
+ printf(" + Using Breadth-First Search\n");
+#endif
+#ifndef NOREDUCE
+ printf(" + Partial Order Reduction\n");
+#endif
+#ifdef REVERSE
+ printf(" + Reverse Depth-First Search Order\n");
+#endif
+#ifdef T_REVERSE
+ printf(" + Reverse Transition Ordering\n");
+#endif
+#ifdef RANDOMIZE
+ printf(" + Randomized Transition Ordering\n");
+#endif
+#ifdef SCHED
+ printf(" + Scheduling Restriction (-DSCHED=%d)\n", sched_max);
+#endif
+#ifdef COLLAPSE
+ printf(" + Compression\n");
+#endif
+#ifdef MA
+ printf(" + Graph Encoding (-DMA=%d)\n", MA);
+ #ifdef R_XPT
+ printf(" Restarted from checkpoint %s.xpt\n", PanSource);
+ #endif
+#endif
+#ifdef CHECK
+ #ifdef FULLSTACK
+ printf(" + FullStack Matching\n");
+ #endif
+ #ifdef CNTRSTACK
+ printf(" + CntrStack Matching\n");
+ #endif
+#endif
+#ifdef BITSTATE
+ printf("\nBit statespace search for:\n");
+#else
+#ifdef HC
+ printf("\nHash-Compact %d search for:\n", HC);
+#else
+ printf("\nFull statespace search for:\n");
+#endif
+#endif
+#ifdef EVENT_TRACE
+#ifdef NEGATED_TRACE
+ printf(" notrace assertion +\n");
+#else
+ printf(" trace assertion +\n");
+#endif
+#endif
+#ifdef VERI
+ printf(" never claim +\n");
+ printf(" assertion violations ");
+ if (noasserts)
+ printf("- (disabled by -A flag)\n");
+ else
+ printf("+ (if within scope of claim)\n");
+#else
+#ifdef NOCLAIM
+ printf(" never claim - (not selected)\n");
+#else
+ printf(" never claim - (none specified)\n");
+#endif
+ printf(" assertion violations ");
+ if (noasserts)
+ printf("- (disabled by -A flag)\n");
+ else
+ printf("+\n");
+#endif
+#ifndef SAFETY
+#ifdef NP
+ printf(" non-progress cycles ");
+#else
+ printf(" acceptance cycles ");
+#endif
+ if (a_cycles)
+ printf("+ (fairness %sabled)\n",
+ fairness?"en":"dis");
+ else printf("- (not selected)\n");
+#else
+ printf(" cycle checks - (disabled by -DSAFETY)\n");
+#endif
+#ifdef VERI
+ printf(" invalid end states - ");
+ printf("(disabled by ");
+ if (noends)
+ printf("-E flag)\n\n");
+ else
+ printf("never claim)\n\n");
+#else
+ printf(" invalid end states ");
+ if (noends)
+ printf("- (disabled by -E flag)\n\n");
+ else
+ printf("+\n\n");
+#endif
+ printf("State-vector %d byte, depth reached %ld", hmax,
+#if NCORE>1
+ (nr_handoffs * z_handoff) +
+#endif
+ mreached);
+ printf(", errors: %d\n", errors);
+ fflush(stdout);
+#ifdef MA
+ if (done)
+ { extern void dfa_stats(void);
+ if (maxgs+a_cycles+2 < MA)
+ printf("MA stats: -DMA=%d is sufficient\n",
+ maxgs+a_cycles+2);
+ dfa_stats();
+ }
+#endif
+ wrap_stats();
+#ifdef CHECK
+ printf("stackframes: %d/%d\n\n", smax, svmax);
+ printf("stats: fa %d, fh %d, zh %d, zn %d - ",
+ Fa, Fh, Zh, Zn);
+ printf("check %d holds %d\n", Ccheck, Cholds);
+ printf("stack stats: puts %d, probes %d, zaps %d\n",
+ PUT, PROBE, ZAPS);
+#else
+ printf("\n");
+#endif
+
+#if defined(BITSTATE) || !defined(NOCOMP)
+ nr1 = (nstates-nShadow)*
+ (double)(hmax+sizeof(struct H_el)-sizeof(unsigned));
+#ifdef BFS
+ nr2 = 0.0;
+#else
+ nr2 = (double) ((maxdepth+3)*sizeof(Trail));
+#endif
+#ifndef BITSTATE
+#if !defined(MA) || defined(COLLAPSE)
+ nr3 = (double) (ONE_L<<ssize)*sizeof(struct H_el *);
+#endif
+#else
+ if (udmem)
+ nr3 = (double) (udmem);
+ else
+ nr3 = (double) (ONE_L<<(ssize-3));
+#ifdef CNTRSTACK
+ nr5 = (double) (ONE_L<<(ssize-3));
+#endif
+#ifdef FULLSTACK
+ nr5 = (double) (maxdepth*sizeof(struct H_el *));
+#endif
+#endif
+ nr4 = (double) (svmax * (sizeof(Svtack) + hmax))
+ + (double) (smax * (sizeof(Stack) + Maxbody));
+#ifndef MA
+ if (mverbose || memcnt < nr1+nr2+nr3+nr4+nr5)
+#endif
+ { double remainder = memcnt;
+ double tmp_nr = memcnt-nr3-nr4-(nr2-fragment)-nr5;
+#if NCORE>1 && !defined(SEP_STATE)
+ tmp_nr -= ((double) NCORE * LWQ_SIZE) + GWQ_SIZE;
+#endif
+ if (tmp_nr < 0.0) tmp_nr = 0.;
+ printf("Stats on memory usage (in Megabytes):\n");
+ printf("%9.3f equivalent memory usage for states",
+ nr1/1048576.); /* 1024*1024=1048576 */
+ printf(" (stored*(State-vector + overhead))\n");
+ #if NCORE>1 && !defined(WIN32) && !defined(WIN64)
+ printf("%9.3f shared memory reserved for state storage\n",
+ mem_reserved/1048576.);
+ #ifdef SEP_HEAP
+ printf(" in %d local heaps of %7.3f MB each\n",
+ NCORE, mem_reserved/(NCORE*1048576.));
+ #endif
+ printf("\n");
+ #endif
+#ifdef BITSTATE
+ if (udmem)
+ printf("%9.3f memory used for hash array (-M%ld)\n",
+ nr3/1048576., udmem/(1024L*1024L));
+ else
+ printf("%9.3f memory used for hash array (-w%d)\n",
+ nr3/1048576., ssize);
+ if (nr5 > 0.0)
+ printf("%9.3f memory used for bit stack\n",
+ nr5/1048576.);
+ remainder = remainder - nr3 - nr5;
+#else
+ printf("%9.3f actual memory usage for states",
+ tmp_nr/1048576.);
+ remainder -= tmp_nr;
+ printf(" (");
+ if (tmp_nr > 0.)
+ { if (tmp_nr > nr1) printf("unsuccessful ");
+ printf("compression: %.2f%%)\n",
+ (100.0*tmp_nr)/nr1);
+ } else
+ printf("less than 1k)\n");
+#ifndef MA
+ if (tmp_nr > 0.)
+ { printf(" state-vector as stored = %.0f byte",
+ (tmp_nr)/(nstates-nShadow) -
+ (double) (sizeof(struct H_el) - sizeof(unsigned)));
+ printf(" + %ld byte overhead\n",
+ (long int) sizeof(struct H_el)-sizeof(unsigned));
+ }
+#endif
+#if !defined(MA) || defined(COLLAPSE)
+ printf("%9.3f memory used for hash table (-w%d)\n",
+ nr3/1048576., ssize);
+ remainder -= nr3;
+#endif
+#endif
+#ifndef BFS
+ printf("%9.3f memory used for DFS stack (-m%ld)\n",
+ nr2/1048576., maxdepth);
+ remainder -= nr2;
+#endif
+#if NCORE>1
+ remainder -= ((double) NCORE * LWQ_SIZE) + GWQ_SIZE;
+ printf("%9.3f shared memory used for work-queues\n",
+ (GWQ_SIZE + (double) NCORE * LWQ_SIZE) /1048576.);
+ printf(" in %d queues of %7.3f MB each",
+ NCORE, (double) LWQ_SIZE /1048576.);
+ #ifndef NGQ
+ printf(" + a global q of %7.3f MB\n",
+ (double) GWQ_SIZE / 1048576.);
+ #else
+ printf("\n");
+ #endif
+ #endif
+ if (remainder - fragment > 1048576.)
+ printf("%9.3f other (proc and chan stacks)\n",
+ (remainder-fragment)/1048576.);
+ if (fragment > 1048576.)
+ printf("%9.3f memory lost to fragmentation\n",
+ fragment/1048576.);
+ printf("%9.3f total actual memory usage\n\n",
+ memcnt/1048576.);
+ }
+#ifndef MA
+ else
+#endif
+#endif
+#ifndef MA
+ printf("%9.3f memory usage (Mbyte)\n\n",
+ memcnt/1048576.);
+#endif
+#ifdef COLLAPSE
+ printf("nr of templates: [ globals chans procs ]\n");
+ printf("collapse counts: [ ");
+ { int i; for (i = 0; i < 256+2; i++)
+ if (ncomps[i] != 0)
+ printf("%d ", ncomps[i]);
+ printf("]\n");
+ }
+#endif
+ if ((done || verbose) && !no_rck) do_reach();
+#ifdef PEG
+ { int i;
+ printf("\nPeg Counts (transitions executed):\n");
+ for (i = 1; i < NTRANS; i++)
+ { if (peg[i]) putpeg(i, peg[i]);
+ } }
+#endif
+#ifdef VAR_RANGES
+ dumpranges();
+#endif
+#ifdef SVDUMP
+ if (vprefix > 0) close(svfd);
+#endif
+#ifdef LOOPSTATE
+ printf("%g loopstates hit\n", cnt_loops);
+#endif
+#ifdef NSUCC
+ dump_succ();
+#endif
+#if NCORE>1 && defined(T_ALERT)
+ crash_report();
+#endif
+ pan_exit(0);
+}
+
+void
+stopped(int arg)
+{ printf("Interrupted\n");
+#if NCORE>1
+ was_interrupted = 1;
+#endif
+ wrapup();
+ pan_exit(0);
+}
+
+#ifdef SFH
+/*
+ * super fast hash, based on Paul Hsieh's function
+ * http://www.azillionmonkeys.com/qed/hash.html
+ */
+#include <stdint.h>
+ #undef get16bits
+ #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
+ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+ #define get16bits(d) (*((const uint16_t *) (d)))
+ #endif
+
+ #ifndef get16bits
+ #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+ +(uint32_t)(((const uint8_t *)(d))[0]) )
+ #endif
+
+void
+d_sfh(const char *s, int len)
+{ uint32_t h = len, tmp;
+ int rem;
+
+ rem = len & 3;
+ len >>= 2;
+
+ for ( ; len > 0; len--)
+ { h += get16bits(s);
+ tmp = (get16bits(s+2) << 11) ^ h;
+ h = (h << 16) ^ tmp;
+ s += 2*sizeof(uint16_t);
+ h += h >> 11;
+ }
+ switch (rem) {
+ case 3: h += get16bits(s);
+ h ^= h << 16;
+ h ^= s[sizeof(uint16_t)] << 18;
+ h += h >> 11;
+ break;
+ case 2: h += get16bits(s);
+ h ^= h << 11;
+ h += h >> 17;
+ break;
+ case 1: h += *s;
+ h ^= h << 10;
+ h += h >> 1;
+ break;
+ }
+ h ^= h << 3;
+ h += h >> 5;
+ h ^= h << 4;
+ h += h >> 17;
+ h ^= h << 25;
+ h += h >> 6;
+
+ K1 = h;
+}
+#endif
+
+#include <stdint.h>
+#if defined(HASH64) || defined(WIN64)
+/* 64-bit Jenkins hash, 1997
+ * http://burtleburtle.net/bob/c/lookup8.c
+ */
+#define mix(a,b,c) \
+{ a -= b; a -= c; a ^= (c>>43); \
+ b -= c; b -= a; b ^= (a<<9); \
+ c -= a; c -= b; c ^= (b>>8); \
+ a -= b; a -= c; a ^= (c>>38); \
+ b -= c; b -= a; b ^= (a<<23); \
+ c -= a; c -= b; c ^= (b>>5); \
+ a -= b; a -= c; a ^= (c>>35); \
+ b -= c; b -= a; b ^= (a<<49); \
+ c -= a; c -= b; c ^= (b>>11); \
+ a -= b; a -= c; a ^= (c>>12); \
+ b -= c; b -= a; b ^= (a<<18); \
+ c -= a; c -= b; c ^= (b>>22); \
+}
+#else
+/* 32-bit Jenkins hash, 2006
+ * http://burtleburtle.net/bob/c/lookup3.c
+ */
+#define rot(x,k) (((x)<<(k))|((x)>>(32-(k))))
+
+#define mix(a,b,c) \
+{ a -= c; a ^= rot(c, 4); c += b; \
+ b -= a; b ^= rot(a, 6); a += c; \
+ c -= b; c ^= rot(b, 8); b += a; \
+ a -= c; a ^= rot(c,16); c += b; \
+ b -= a; b ^= rot(a,19); a += c; \
+ c -= b; c ^= rot(b, 4); b += a; \
+}
+
+#define final(a,b,c) \
+{ c ^= b; c -= rot(b,14); \
+ a ^= c; a -= rot(c,11); \
+ b ^= a; b -= rot(a,25); \
+ c ^= b; c -= rot(b,16); \
+ a ^= c; a -= rot(c,4); \
+ b ^= a; b -= rot(a,14); \
+ c ^= b; c -= rot(b,24); \
+}
+#endif
+
+void
+d_hash(uchar *kb, int nbytes)
+{ uint8_t *bp;
+#if defined(HASH64) || defined(WIN64)
+ uint64_t a = 0, b, c, n;
+ uint64_t *k = (uint64_t *) kb;
+#else
+ uint32_t a, b, c, n;
+ uint32_t *k = (uint32_t *) kb;
+#endif
+ /* extend to multiple of words, if needed */
+ n = nbytes/WS; /* nr of words */
+ a = nbytes - (n*WS);
+ if (a > 0)
+ { n++;
+ bp = kb + nbytes;
+ switch (a) {
+ case 3: *bp++ = 0; /* fall thru */
+ case 2: *bp++ = 0; /* fall thru */
+ case 1: *bp = 0;
+ case 0: break;
+ } }
+#if defined(HASH64) || defined(WIN64)
+ b = HASH_CONST[HASH_NR];
+ c = 0x9e3779b97f4a7c13LL; /* arbitrary value */
+ while (n >= 3)
+ { a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ n -= 3;
+ k += 3;
+ }
+ c += (((uint64_t) nbytes)<<3);
+ switch (n) {
+ case 2: b += k[1];
+ case 1: a += k[0];
+ case 0: break;
+ }
+ mix(a,b,c);
+#else
+ a = c = 0xdeadbeef + (n<<2);
+ b = HASH_CONST[HASH_NR];
+ while (n > 3)
+ { a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ n -= 3;
+ k += 3;
+ }
+ switch (n) {
+ case 3: c += k[2];
+ case 2: b += k[1];
+ case 1: a += k[0];
+ case 0: break;
+ }
+ final(a,b,c);
+#endif
+ j1 = c&nmask; j3 = a&7; /* 1st bit */
+ j2 = b&nmask; j4 = (a>>3)&7; /* 2nd bit */
+ K1 = c; K2 = b;
+}
+
+void
+s_hash(uchar *cp, int om)
+{
+#if defined(SFH)
+ d_sfh((const char *) cp, om); /* sets K1 */
+#else
+ d_hash(cp, om); /* sets K1 etc */
+#endif
+#ifdef BITSTATE
+ if (S_Tab == H_tab)
+ j1 = K1 % omaxdepth;
+ else
+#endif
+ if (ssize < 8*WS)
+ j1 = K1&mask;
+ else
+ j1 = K1;
+}
+#ifndef RANDSTOR
+int *prerand;
+void
+inirand(void)
+{ int i;
+ srand(123); /* fixed startpoint */
+ prerand = (int *) emalloc((omaxdepth+3)*sizeof(int));
+ for (i = 0; i < omaxdepth+3; i++)
+ prerand[i] = rand();
+}
+int
+pan_rand(void)
+{ if (!prerand) inirand();
+ return prerand[depth];
+}
+#endif
+
+void
+set_masks(void) /* 4.2.5 */
+{
+ if (WS == 4 && ssize >= 32)
+ { mask = 0xffffffff;
+#ifdef BITSTATE
+ switch (ssize) {
+ case 34: nmask = (mask>>1); break;
+ case 33: nmask = (mask>>2); break;
+ default: nmask = (mask>>3); break;
+ }
+#else
+ nmask = mask;
+#endif
+ } else if (WS == 8)
+ { mask = ((ONE_L<<ssize)-1); /* hash init */
+#ifdef BITSTATE
+ nmask = mask>>3;
+#else
+ nmask = mask;
+#endif
+ } else if (WS != 4)
+ { fprintf(stderr, "pan: wordsize %ld not supported\n", (long int) WS);
+ exit(1);
+ } else /* WS == 4 and ssize < 32 */
+ { mask = ((ONE_L<<ssize)-1); /* hash init */
+ nmask = (mask>>3);
+ }
+}
+
+static long reclaim_size;
+static char *reclaim_mem;
+#if defined(AUTO_RESIZE) && !defined(BITSTATE) && !defined(MA)
+#if NCORE>1
+ #error cannot combine AUTO_RESIZE with NCORE>1 yet
+#endif
+static struct H_el **N_tab;
+void
+reverse_capture(struct H_el *p)
+{ if (!p) return;
+ reverse_capture(p->nxt);
+ /* last element of list moves first */
+ /* to preserve list-order */
+ j2 = p->m_K1;
+ if (ssize < 8*WS) /* probably always true */
+ { j2 &= mask;
+ }
+ p->nxt = N_tab[j2];
+ N_tab[j2] = p;
+}
+void
+resize_hashtable(void)
+{
+ if (WS == 4 && ssize >= 27 - 1)
+ { return; /* canot increase further */
+ }
+
+ ssize += 2; /* 4x size */
+
+ printf("pan: resizing hashtable to -w%d.. ", ssize);
+
+ N_tab = (struct H_el **)
+ emalloc((ONE_L<<ssize)*sizeof(struct H_el *));
+
+ set_masks(); /* they changed */
+
+ for (j1 = 0; j1 < (ONE_L << (ssize - 2)); j1++)
+ { reverse_capture(H_tab[j1]);
+ }
+ reclaim_mem = (char *) H_tab;
+ reclaim_size = (ONE_L << (ssize - 2));
+ H_tab = N_tab;
+
+ printf(" done\n");
+}
+#endif
+#if defined(ZAPH) && defined(BITSTATE)
+void
+zap_hashtable(void)
+{ cpu_printf("pan: resetting hashtable\n");
+ if (udmem)
+ { memset(SS, 0, udmem);
+ } else
+ { memset(SS, 0, ONE_L<<(ssize-3));
+ }
+}
+#endif
+
+int
+main(int argc, char *argv[])
+{ void to_compile(void);
+
+ efd = stderr; /* default */
+#ifdef BITSTATE
+ bstore = bstore_reg; /* default */
+#endif
+#if NCORE>1
+ { int i, j;
+ strcpy(o_cmdline, "");
+ for (j = 1; j < argc; j++)
+ { strcat(o_cmdline, argv[j]);
+ strcat(o_cmdline, " ");
+ }
+ /* printf("Command Line: %s\n", o_cmdline); */
+ if (strlen(o_cmdline) >= sizeof(o_cmdline))
+ { Uerror("option list too long");
+ } }
+#endif
+ while (argc > 1 && argv[1][0] == '-')
+ { switch (argv[1][1]) {
+#ifndef SAFETY
+#ifdef NP
+ case 'a': fprintf(efd, "error: -a disabled");
+ usage(efd); break;
+#else
+ case 'a': a_cycles = 1; break;
+#endif
+#endif
+ case 'A': noasserts = 1; break;
+ case 'b': bounded = 1; break;
+#ifdef HAS_CODE
+ case 'C': coltrace = 1; goto samething;
+#endif
+ case 'c': upto = atoi(&argv[1][2]); break;
+ case 'd': state_tables++; break;
+ case 'e': every_error = 1; Nr_Trails = 1; break;
+ case 'E': noends = 1; break;
+#ifdef SC
+ case 'F': if (strlen(argv[1]) > 2)
+ stackfile = &argv[1][2];
+ break;
+#endif
+#if !defined(SAFETY) && !defined(NOFAIR)
+ case 'f': fairness = 1; break;
+#endif
+#ifdef HAS_CODE
+ case 'g': gui = 1; goto samething;
+#endif
+ case 'h': if (!argv[1][2]) usage(efd); else
+ HASH_NR = atoi(&argv[1][2])%33; break;
+ case 'I': iterative = 2; every_error = 1; break;
+ case 'i': iterative = 1; every_error = 1; break;
+ case 'J': like_java = 1; break; /* Klaus Havelund */
+#ifdef BITSTATE
+ case 'k': hfns = atoi(&argv[1][2]); break;
+#endif
+#ifdef SCHED
+ case 'L': sched_max = atoi(&argv[1][2]); break;
+#endif
+#ifndef SAFETY
+#ifdef NP
+ case 'l': a_cycles = 1; break;
+#else
+ case 'l': fprintf(efd, "error: -l disabled");
+ usage(efd); break;
+#endif
+#endif
+#ifdef BITSTATE
+ case 'M': udmem = atoi(&argv[1][2]); break;
+ case 'G': udmem = atoi(&argv[1][2]); udmem *= 1024; break;
+#else
+ case 'M': case 'G':
+ fprintf(stderr, "-M and -G affect only -DBITSTATE\n");
+ break;
+#endif
+ case 'm': maxdepth = atoi(&argv[1][2]); break;
+ case 'n': no_rck = 1; break;
+ case 'P': readtrail = 1; onlyproc = atoi(&argv[1][2]);
+ if (argv[2][0] != '-') /* check next arg */
+ { trailfilename = argv[2];
+ argc--; argv++; /* skip next arg */
+ }
+ break;
+#ifdef SVDUMP
+ case 'p': vprefix = atoi(&argv[1][2]); break;
+#endif
+#if NCORE==1
+ case 'Q': quota = (double) 60.0 * (double) atoi(&argv[1][2]); break;
+#endif
+ case 'q': strict = 1; break;
+ case 'R': Nrun = atoi(&argv[1][2]); break;
+#ifdef HAS_CODE
+ case 'r':
+samething: readtrail = 1;
+ if (isdigit(argv[1][2]))
+ whichtrail = atoi(&argv[1][2]);
+ else if (argc > 2 && argv[2][0] != '-') /* check next arg */
+ { trailfilename = argv[2];
+ argc--; argv++; /* skip next arg */
+ }
+ break;
+ case 'S': silent = 1; goto samething;
+#endif
+#ifdef BITSTATE
+ case 's': hfns = 1; break;
+#endif
+ case 'T': TMODE = 0444; break;
+ case 't': if (argv[1][2]) tprefix = &argv[1][2]; break;
+ case 'V': start_timer(); printf("Generated by %s\n", SpinVersion);
+ to_compile(); pan_exit(2); break;
+ case 'v': verbose++; break;
+ case 'w': ssize = atoi(&argv[1][2]); break;
+ case 'Y': signoff = 1; break;
+ case 'X': efd = stdout; break;
+ case 'x': exclusive = 1; break;
+#if NCORE>1
+ /* -B ip is passthru to proxy of remote ip address: */
+ case 'B': argc--; argv++; break;
+ case 'Q': worker_pids[0] = atoi(&argv[1][2]); break;
+ /* -Un means that the nth worker should be instantiated as a proxy */
+ case 'U': proxy_pid = atoi(&argv[1][2]); break;
+ /* -W means that this copy is started by a cluster-server as a remote */
+ /* this flag is passed to ./pan_proxy, which interprets it */
+ case 'W': remote_party++; break;
+ case 'Z': core_id = atoi(&argv[1][2]);
+ if (verbose)
+ { printf("cpu%d: pid %d parent %d\n",
+ core_id, getpid(), worker_pids[0]);
+ }
+ break;
+ case 'z': z_handoff = atoi(&argv[1][2]); break;
+#else
+ case 'z': break; /* ignored for single-core */
+#endif
+ default : fprintf(efd, "saw option -%c\n", argv[1][1]); usage(efd); break;
+ }
+ argc--; argv++;
+ }
+ if (iterative && TMODE != 0666)
+ { TMODE = 0666;
+ fprintf(efd, "warning: -T ignored when -i or -I is used\n");
+ }
+#if defined(HASH32) && !defined(SFH)
+ if (WS > 4)
+ { fprintf(efd, "strong warning: compiling -DHASH32 on a 64-bit machine\n");
+ fprintf(efd, " without -DSFH can slow down performance a lot\n");
+ }
+#endif
+#if defined(WIN32) || defined(WIN64)
+ if (TMODE == 0666)
+ TMODE = _S_IWRITE | _S_IREAD;
+ else
+ TMODE = _S_IREAD;
+#endif
+#if NCORE>1
+ store_proxy_pid = proxy_pid; /* for checks in mem_file() and someone_crashed() */
+ if (core_id != 0) { proxy_pid = 0; }
+ #ifndef SEP_STATE
+ if (core_id == 0 && a_cycles)
+ { fprintf(efd, "hint: this search may be more efficient ");
+ fprintf(efd, "if pan.c is compiled -DSEP_STATE\n");
+ }
+ #endif
+ if (z_handoff < 0)
+ { z_handoff = 20; /* conservative default - for non-liveness checks */
+ }
+#if defined(NGQ) || defined(LWQ_FIXED)
+ LWQ_SIZE = (double) (128.*1048576.);
+#else
+ LWQ_SIZE = (double) ( z_handoff + 2.) * (double) sizeof(SM_frame);
+#endif
+ #if NCORE>2
+ if (a_cycles)
+ { fprintf(efd, "warning: the intended nr of cores to be used in liveness mode is 2\n");
+ #ifndef SEP_STATE
+ fprintf(efd, "warning: without -DSEP_STATE there is no guarantee that all liveness violations are found\n");
+ #endif
+ }
+ #endif
+ #ifdef HAS_HIDDEN
+ #error cannot use hidden variables when compiling multi-core
+ #endif
+#endif
+#ifdef BITSTATE
+ if (hfns <= 0)
+ { hfns = 1;
+ fprintf(efd, "warning: using -k%d as minimal usable value\n", hfns);
+ }
+#endif
+ omaxdepth = maxdepth;
+#ifdef BITSTATE
+ if (WS == 4 && ssize > 34)
+ { ssize = 34;
+ fprintf(efd, "warning: using -w%d as max usable value\n", ssize);
+/*
+ * -w35 would not work: 35-3 = 32 but 1^31 is the largest
+ * power of 2 that can be represented in an unsigned long
+ */
+ }
+#else
+ if (WS == 4 && ssize > 27)
+ { ssize = 27;
+ fprintf(efd, "warning: using -w%d as max usable value\n", ssize);
+/*
+ * for emalloc, the lookup table size multiplies by 4 for the pointers
+ * the largest power of 2 that can be represented in a ulong is 1^31
+ * hence the largest number of lookup table slots is 31-4 = 27
+ */
+ }
+#endif
+#ifdef SC
+ hiwater = HHH = maxdepth-10;
+ DDD = HHH/2;
+ if (!stackfile)
+ { stackfile = (char *) emalloc(strlen(PanSource)+4+1);
+ sprintf(stackfile, "%s._s_", PanSource);
+ }
+ if (iterative)
+ { fprintf(efd, "error: cannot use -i or -I with -DSC\n");
+ pan_exit(1);
+ }
+#endif
+#if (defined(R_XPT) || defined(W_XPT)) && !defined(MA)
+ #warning -DR_XPT and -DW_XPT assume -DMA (ignored)
+#endif
+ if (iterative && a_cycles)
+ fprintf(efd, "warning: -i or -I work for safety properties only\n");
+#ifdef BFS
+ #ifdef SC
+ #error -DBFS not compatible with -DSC
+ #endif
+ #ifdef HAS_LAST
+ #error -DBFS not compatible with _last
+ #endif
+ #ifdef HAS_STACK
+ #error cannot use c_track UnMatched with BFS
+ #endif
+ #ifdef REACH
+ #warning -DREACH is redundant when -DBFS is used
+ #endif
+#endif
+#if defined(MERGED) && defined(PEG)
+ #error to use -DPEG use: spin -o3 -a
+#endif
+#ifdef HC
+ #ifdef SFH
+ #error cannot combine -DHC and -DSFH
+ /* use of NOCOMP is the real reason */
+ #else
+ #ifdef NOCOMP
+ #error cannot combine -DHC and -DNOCOMP
+ #endif
+ #endif
+ #ifdef BITSTATE
+ #error cannot combine -DHC and -DBITSTATE
+ #endif
+#endif
+#if defined(SAFETY) && defined(NP)
+ #error cannot combine -DNP and -DBFS or -DSAFETY
+#endif
+#ifdef MA
+ #ifdef BITSTATE
+ #error cannot combine -DMA and -DBITSTATE
+ #endif
+ #if MA <= 0
+ #error usage: -DMA=N with N > 0 and N < VECTORSZ
+ #endif
+#endif
+#ifdef COLLAPSE
+ #ifdef BITSTATE
+ #error cannot combine -DBITSTATE and -DCOLLAPSE
+ #endif
+ #ifdef SFH
+ #error cannot combine -DCOLLAPSE and -DSFH
+ /* use of NOCOMP is the real reason */
+ #else
+ #ifdef NOCOMP
+ #error cannot combine -DCOLLAPSE and -DNOCOMP
+ #endif
+ #endif
+#endif
+ if (maxdepth <= 0 || ssize <= 1) usage(efd);
+#if SYNC>0 && !defined(NOREDUCE)
+ if (a_cycles && fairness)
+ { fprintf(efd, "error: p.o. reduction not compatible with ");
+ fprintf(efd, "fairness (-f) in models\n");
+ fprintf(efd, " with rendezvous operations: ");
+ fprintf(efd, "recompile with -DNOREDUCE\n");
+ pan_exit(1);
+ }
+#endif
+#if defined(REM_VARS) && !defined(NOREDUCE)
+ #warning p.o. reduction not compatible with remote varrefs (use -DNOREDUCE)
+#endif
+#if defined(NOCOMP) && !defined(BITSTATE)
+ if (a_cycles)
+ { fprintf(efd, "error: use of -DNOCOMP voids -l and -a\n");
+ pan_exit(1);
+ }
+#endif
+#ifdef MEMLIM
+ memlim = ((double) MEMLIM) * (double) (1<<20); /* size in Mbyte */
+#endif
+#ifndef BITSTATE
+ if (Nrun > 1) HASH_NR = Nrun - 1;
+#endif
+ if (Nrun < 1 || Nrun > 32)
+ { fprintf(efd, "error: invalid arg for -R\n");
+ usage(efd);
+ }
+#ifndef SAFETY
+ if (fairness && !a_cycles)
+ { fprintf(efd, "error: -f requires -a or -l\n");
+ usage(efd);
+ }
+ #if ACCEPT_LAB==0
+ if (a_cycles)
+ { fprintf(efd, "error: no accept labels defined ");
+ fprintf(efd, "in model (for option -a)\n");
+ usage(efd);
+ }
+ #endif
+#endif
+#ifndef NOREDUCE
+ #ifdef HAS_ENABLED
+ #error use of enabled() requires -DNOREDUCE
+ #endif
+ #ifdef HAS_PCVALUE
+ #error use of pcvalue() requires -DNOREDUCE
+ #endif
+ #ifdef HAS_BADELSE
+ #error use of 'else' combined with i/o stmnts requires -DNOREDUCE
+ #endif
+ #ifdef HAS_LAST
+ #error use of _last requires -DNOREDUCE
+ #endif
+#endif
+#if SYNC>0 && !defined(NOREDUCE)
+ #ifdef HAS_UNLESS
+ fprintf(efd, "warning: use of a rendezvous stmnts in the escape\n");
+ fprintf(efd, " of an unless clause, if present, could make p.o. reduction\n");
+ fprintf(efd, " invalid (use -DNOREDUCE to avoid this)\n");
+ #ifdef BFS
+ fprintf(efd, " (this type of rv is also not compatible with -DBFS)\n");
+ #endif
+ #endif
+#endif
+#if SYNC>0 && defined(BFS)
+ #warning use of rendezvous with BFS does not preserve all invalid endstates
+#endif
+#if !defined(REACH) && !defined(BITSTATE)
+ if (iterative != 0 && a_cycles == 0)
+ { fprintf(efd, "warning: -i and -I need -DREACH to work accurately\n");
+ }
+#endif
+#if defined(BITSTATE) && defined(REACH)
+ #warning -DREACH is voided by -DBITSTATE
+#endif
+#if defined(MA) && defined(REACH)
+ #warning -DREACH is voided by -DMA
+#endif
+#if defined(FULLSTACK) && defined(CNTRSTACK)
+ #error cannot combine -DFULLSTACK and -DCNTRSTACK
+#endif
+#if defined(VERI)
+ #if ACCEPT_LAB>0
+ #ifndef BFS
+ if (!a_cycles
+ #ifdef HAS_CODE
+ && !readtrail
+ #endif
+ #if NCORE>1
+ && core_id == 0
+ #endif
+ && !state_tables)
+ { fprintf(efd, "warning: never claim + accept labels ");
+ fprintf(efd, "requires -a flag to fully verify\n");
+ }
+ #else
+ if (!state_tables
+ #ifdef HAS_CODE
+ && !readtrail
+ #endif
+ )
+ { fprintf(efd, "warning: verification in BFS mode ");
+ fprintf(efd, "is restricted to safety properties\n");
+ }
+ #endif
+ #endif
+#endif
+#ifndef SAFETY
+ if (!a_cycles
+ #ifdef HAS_CODE
+ && !readtrail
+ #endif
+ #if NCORE>1
+ && core_id == 0
+ #endif
+ && !state_tables)
+ { fprintf(efd, "hint: this search is more efficient ");
+ fprintf(efd, "if pan.c is compiled -DSAFETY\n");
+ }
+ #ifndef NOCOMP
+ if (!a_cycles)
+ { S_A = 0;
+ } else
+ { if (!fairness)
+ { S_A = 1; /* _a_t */
+ #ifndef NOFAIR
+ } else /* _a_t and _cnt[NFAIR] */
+ { S_A = (&(now._cnt[0]) - (uchar *) &now) + NFAIR - 2;
+ /* -2 because first two uchars in now are masked */
+ #endif
+ } }
+ #endif
+#endif
+ signal(SIGINT, stopped);
+ set_masks();
+#ifdef BFS
+ trail = (Trail *) emalloc(6*sizeof(Trail));
+ trail += 3;
+#else
+ trail = (Trail *) emalloc((maxdepth+3)*sizeof(Trail));
+ trail++; /* protect trpt-1 refs at depth 0 */
+#endif
+#ifdef SVDUMP
+ if (vprefix > 0)
+ { char nm[64];
+ sprintf(nm, "%s.svd", PanSource);
+ if ((svfd = creat(nm, TMODE)) < 0)
+ { fprintf(efd, "couldn't create %s\n", nm);
+ vprefix = 0;
+ } }
+#endif
+#ifdef RANDSTOR
+ srand(123);
+#endif
+#if SYNC>0 && ASYNC==0
+ set_recvs();
+#endif
+ run();
+ done = 1;
+ wrapup();
+ return 0;
+}
+
+void
+usage(FILE *fd)
+{
+ fprintf(fd, "%s\n", SpinVersion);
+ fprintf(fd, "Valid Options are:\n");
+#ifndef SAFETY
+#ifdef NP
+ fprintf(fd, " -a -> is disabled by -DNP ");
+ fprintf(fd, "(-DNP compiles for -l only)\n");
+#else
+ fprintf(fd, " -a find acceptance cycles\n");
+#endif
+#else
+ fprintf(fd, " -a,-l,-f -> are disabled by -DSAFETY\n");
+#endif
+ fprintf(fd, " -A ignore assert() violations\n");
+ fprintf(fd, " -b consider it an error to exceed the depth-limit\n");
+ fprintf(fd, " -cN stop at Nth error ");
+ fprintf(fd, "(defaults to -c1)\n");
+ fprintf(fd, " -d print state tables and stop\n");
+ fprintf(fd, " -e create trails for all errors\n");
+ fprintf(fd, " -E ignore invalid end states\n");
+#ifdef SC
+ fprintf(fd, " -Ffile use 'file' to store disk-stack\n");
+#endif
+#ifndef NOFAIR
+ fprintf(fd, " -f add weak fairness (to -a or -l)\n");
+#endif
+ fprintf(fd, " -hN use different hash-seed N:1..32\n");
+ fprintf(fd, " -i search for shortest path to error\n");
+ fprintf(fd, " -I like -i, but approximate and faster\n");
+ fprintf(fd, " -J reverse eval order of nested unlesses\n");
+#ifdef BITSTATE
+ fprintf(fd, " -kN set N bits per state (defaults to 3)\n");
+#endif
+#ifdef SCHED
+ fprintf(fd, " -LN set scheduling restriction to N (default 10)\n");
+#endif
+#ifndef SAFETY
+#ifdef NP
+ fprintf(fd, " -l find non-progress cycles\n");
+#else
+ fprintf(fd, " -l find non-progress cycles -> ");
+ fprintf(fd, "disabled, requires ");
+ fprintf(fd, "compilation with -DNP\n");
+#endif
+#endif
+#ifdef BITSTATE
+ fprintf(fd, " -MN use N Megabytes for bitstate hash array\n");
+ fprintf(fd, " -GN use N Gigabytes for bitstate hash array\n");
+#endif
+ fprintf(fd, " -mN max depth N steps (default=10k)\n");
+ fprintf(fd, " -n no listing of unreached states\n");
+#ifdef SVDUMP
+ fprintf(fd, " -pN create svfile (save N bytes per state)\n");
+#endif
+ fprintf(fd, " -QN set time-limit on execution of N minutes\n");
+ fprintf(fd, " -q require empty chans in valid end states\n");
+#ifdef HAS_CODE
+ fprintf(fd, " -r read and execute trail - can add -v,-n,-PN,-g,-C\n");
+ fprintf(fd, " -rN read and execute N-th error trail\n");
+ fprintf(fd, " -C read and execute trail - columnated output (can add -v,-n)\n");
+ fprintf(fd, " -PN read and execute trail - restrict trail output to proc N\n");
+ fprintf(fd, " -g read and execute trail + msc gui support\n");
+ fprintf(fd, " -S silent replay: only user defined printfs show\n");
+#endif
+#ifdef BITSTATE
+ fprintf(fd, " -RN repeat run Nx with N ");
+ fprintf(fd, "[1..32] independent hash functions\n");
+ fprintf(fd, " -s same as -k1 (single bit per state)\n");
+#endif
+ fprintf(fd, " -T create trail files in read-only mode\n");
+ fprintf(fd, " -tsuf replace .trail with .suf on trailfiles\n");
+ fprintf(fd, " -V print SPIN version number\n");
+ fprintf(fd, " -v verbose -- filenames in unreached state listing\n");
+ fprintf(fd, " -wN hashtable of 2^N entries ");
+ fprintf(fd, "(defaults to -w%d)\n", ssize);
+ fprintf(fd, " -x do not overwrite an existing trail file\n");
+#if NCORE>1
+ fprintf(fd, " -zN handoff states below depth N to 2nd cpu (multi_core)\n");
+#endif
+#ifdef HAS_CODE
+ fprintf(fd, "\n options -r, -C, -PN, -g, and -S can optionally be followed by\n");
+ fprintf(fd, " a filename argument, as in '-r filename', naming the trailfile\n");
+#endif
+#if NCORE>1
+ multi_usage(fd);
+#endif
+ exit(1);
+}
+
+char *
+Malloc(unsigned long n)
+{ char *tmp;
+#ifdef MEMLIM
+ if (memcnt+ (double) n > memlim) goto err;
+#endif
+#if 1
+ tmp = (char *) malloc(n);
+ if (!tmp)
+#else
+ tmp = (char *) sbrk(n);
+ if (tmp == (char *) -ONE_L)
+#endif
+ {
+#ifdef MEMLIM
+err:
+#endif
+ printf("pan: out of memory\n");
+#ifdef MEMLIM
+ printf(" %g bytes used\n", memcnt);
+ printf(" %g bytes more needed\n", (double) n);
+ printf(" %g bytes limit\n",
+ memlim);
+#endif
+#ifdef COLLAPSE
+ printf("hint: to reduce memory, recompile with\n");
+#ifndef MA
+ printf(" -DMA=%d # better/slower compression, or\n", hmax);
+#endif
+ printf(" -DBITSTATE # supertrace, approximation\n");
+#else
+#ifndef BITSTATE
+ printf("hint: to reduce memory, recompile with\n");
+#ifndef HC
+ printf(" -DCOLLAPSE # good, fast compression, or\n");
+#ifndef MA
+ printf(" -DMA=%d # better/slower compression, or\n", hmax);
+#endif
+ printf(" -DHC # hash-compaction, approximation\n");
+#endif
+ printf(" -DBITSTATE # supertrace, approximation\n");
+#endif
+#endif
+#if NCORE>1
+ #ifdef FULL_TRAIL
+ printf(" omit -DFULL_TRAIL or use pan -c0 to reduce memory\n");
+ #endif
+ #ifdef SEP_STATE
+ printf("hint: to reduce memory, recompile without\n");
+ printf(" -DSEP_STATE # may be faster, but uses more memory\n");
+ #endif
+#endif
+ wrapup();
+ }
+ memcnt += (double) n;
+ return tmp;
+}
+
+#define CHUNK (100*VECTORSZ)
+
+char *
+emalloc(unsigned long n) /* never released or reallocated */
+{ char *tmp;
+ if (n == 0)
+ return (char *) NULL;
+ if (n&(sizeof(void *)-1)) /* for proper alignment */
+ n += sizeof(void *)-(n&(sizeof(void *)-1));
+ if ((unsigned long) left < n)
+ { grow = (n < CHUNK) ? CHUNK : n;
+ have = Malloc(grow);
+ fragment += (double) left;
+ left = grow;
+ }
+ tmp = have;
+ have += (long) n;
+ left -= (long) n;
+ memset(tmp, 0, n);
+ return tmp;
+}
+void
+Uerror(char *str)
+{ /* always fatal */
+ uerror(str);
+#if NCORE>1
+ sudden_stop("Uerror");
+#endif
+ wrapup();
+}
+
+#if defined(MA) && !defined(SAFETY)
+int
+Unwind(void)
+{ Trans *t; uchar ot, _m; int tt; short II;
+#ifdef VERBOSE
+ int i;
+#endif
+ uchar oat = now._a_t;
+ now._a_t &= ~(1|16|32);
+ memcpy((char *) &comp_now, (char *) &now, vsize);
+ now._a_t = oat;
+Up:
+#ifdef SC
+ trpt = getframe(depth);
+#endif
+#ifdef VERBOSE
+ printf("%d State: ", depth);
+ for (i = 0; i < vsize; i++) printf("%d%s,",
+ ((char *)&now)[i], Mask[i]?"*":"");
+ printf("\n");
+#endif
+#ifndef NOFAIR
+ if (trpt->o_pm&128) /* fairness alg */
+ { now._cnt[now._a_t&1] = trpt->bup.oval;
+ depth--;
+#ifdef SC
+ trpt = getframe(depth);
+#else
+ trpt--;
+#endif
+ goto Q999;
+ }
+#endif
+#ifdef HAS_LAST
+#ifdef VERI
+ { int d; Trail *trl;
+ now._last = 0;
+ for (d = 1; d < depth; d++)
+ { trl = getframe(depth-d); /* was trl = (trpt-d); */
+ if (trl->pr != 0)
+ { now._last = trl->pr - BASE;
+ break;
+ } } }
+#else
+ now._last = (depth<1)?0:(trpt-1)->pr;
+#endif
+#endif
+#ifdef EVENT_TRACE
+ now._event = trpt->o_event;
+#endif
+ if ((now._a_t&1) && depth <= A_depth)
+ { now._a_t &= ~(1|16|32);
+ if (fairness) now._a_t |= 2; /* ? */
+ A_depth = 0;
+ goto CameFromHere; /* checkcycles() */
+ }
+ t = trpt->o_t;
+ ot = trpt->o_ot; II = trpt->pr;
+ tt = trpt->o_tt; this = pptr(II);
+ _m = do_reverse(t, II, trpt->o_m);
+#ifdef VERBOSE
+ printf("%3d: proc %d ", depth, II);
+ printf("reverses %d, %d to %d,",
+ t->forw, tt, t->st);
+ printf(" %s [abit=%d,adepth=%d,",
+ t->tp, now._a_t, A_depth);
+ printf("tau=%d,%d] <unwind>\n",
+ trpt->tau, (trpt-1)->tau);
+#endif
+ depth--;
+#ifdef SC
+ trpt = getframe(depth);
+#else
+ trpt--;
+#endif
+ /* reached[ot][t->st] = 1; 3.4.13 */
+ ((P0 *)this)->_p = tt;
+#ifndef NOFAIR
+ if ((trpt->o_pm&32))
+ {
+#ifdef VERI
+ if (now._cnt[now._a_t&1] == 0)
+ now._cnt[now._a_t&1] = 1;
+#endif
+ now._cnt[now._a_t&1] += 1;
+ }
+Q999:
+ if (trpt->o_pm&8)
+ { now._a_t &= ~2;
+ now._cnt[now._a_t&1] = 0;
+ }
+ if (trpt->o_pm&16)
+ now._a_t |= 2;
+#endif
+CameFromHere:
+ if (memcmp((char *) &now, (char *) &comp_now, vsize) == 0)
+ return depth;
+ if (depth > 0) goto Up;
+ return 0;
+}
+#endif
+static char unwinding;
+void
+uerror(char *str)
+{ static char laststr[256];
+ int is_cycle;
+
+ if (unwinding) return; /* 1.4.2 */
+ if (strncmp(str, laststr, 254))
+#if NCORE>1
+ cpu_printf("pan: %s (at depth %ld)\n", str,
+#else
+ printf("pan: %s (at depth %ld)\n", str,
+#endif
+#if NCORE>1
+ (nr_handoffs * z_handoff) +
+#endif
+ ((depthfound==-1)?depth:depthfound));
+ strncpy(laststr, str, 254);
+ errors++;
+#ifdef HAS_CODE
+ if (readtrail) { wrap_trail(); return; }
+#endif
+ is_cycle = (strstr(str, " cycle") != (char *) 0);
+ if (!is_cycle)
+ { depth++; trpt++;
+ }
+ if ((every_error != 0)
+ || errors == upto)
+ {
+#if defined(MA) && !defined(SAFETY)
+ if (is_cycle)
+ { int od = depth;
+ unwinding = 1;
+ depthfound = Unwind();
+ unwinding = 0;
+ depth = od;
+ }
+#endif
+#if NCORE>1
+ writing_trail = 1;
+#endif
+#ifdef BFS
+ if (depth > 1) trpt--;
+ nuerror(str);
+ if (depth > 1) trpt++;
+#else
+ putrail();
+#endif
+#if defined(MA) && !defined(SAFETY)
+ if (strstr(str, " cycle"))
+ { if (every_error)
+ printf("sorry: MA writes 1 trail max\n");
+ wrapup(); /* no recovery from unwind */
+ }
+#endif
+#if NCORE>1
+ if (search_terminated != NULL)
+ { *search_terminated |= 4; /* uerror */
+ }
+ writing_trail = 0;
+#endif
+ }
+ if (!is_cycle)
+ { depth--; trpt--; /* undo */
+ }
+#ifndef BFS
+ if (iterative != 0 && maxdepth > 0)
+ { maxdepth = (iterative == 1)?(depth-1):(depth/2);
+ warned = 1;
+ printf("pan: reducing search depth to %ld\n",
+ maxdepth);
+ } else
+#endif
+ if (errors >= upto && upto != 0)
+ {
+#if NCORE>1
+ sudden_stop("uerror");
+#endif
+ wrapup();
+ }
+ depthfound = -1;
+}
+
+int
+xrefsrc(int lno, S_F_MAP *mp, int M, int i)
+{ Trans *T; int j, retval=1;
+ for (T = trans[M][i]; T; T = T->nxt)
+ if (T && T->tp)
+ { if (strcmp(T->tp, ".(goto)") == 0
+ || strncmp(T->tp, "goto :", 6) == 0)
+ return 1; /* not reported */
+
+ printf("\tline %d", lno);
+ if (verbose)
+ for (j = 0; j < sizeof(mp); j++)
+ if (i >= mp[j].from && i <= mp[j].upto)
+ { printf(", \"%s\"", mp[j].fnm);
+ break;
+ }
+ printf(", state %d", i);
+ if (strcmp(T->tp, "") != 0)
+ { char *q;
+ q = transmognify(T->tp);
+ printf(", \"%s\"", q?q:"");
+ } else if (stopstate[M][i])
+ printf(", -end state-");
+ printf("\n");
+ retval = 0; /* reported */
+ }
+ return retval;
+}
+
+void
+r_ck(uchar *which, int N, int M, short *src, S_F_MAP *mp)
+{ int i, m=0;
+
+#ifdef VERI
+ if (M == VERI && !verbose) return;
+#endif
+ printf("unreached in proctype %s\n", procname[M]);
+ for (i = 1; i < N; i++)
+ if (which[i] == 0
+ && (mapstate[M][i] == 0
+ || which[mapstate[M][i]] == 0))
+ m += xrefsrc((int) src[i], mp, M, i);
+ else
+ m++;
+ printf(" (%d of %d states)\n", N-1-m, N-1);
+}
+#if NCORE>1 && !defined(SEP_STATE)
+static long rev_trail_cnt;
+
+#ifdef FULL_TRAIL
+void
+rev_trail(int fd, volatile Stack_Tree *st_tr)
+{ long j; char snap[64];
+
+ if (!st_tr)
+ { return;
+ }
+ rev_trail(fd, st_tr->prv);
+#ifdef VERBOSE
+ printf("%d (%d) LRT [%d,%d] -- %9u (root %9u)\n",
+ depth, rev_trail_cnt, st_tr->pr, st_tr->t_id, st_tr, stack_last[core_id]);
+#endif
+ if (st_tr->pr != 255)
+ { sprintf(snap, "%ld:%d:%d\n",
+ rev_trail_cnt++, st_tr->pr, st_tr->t_id);
+ j = strlen(snap);
+ if (write(fd, snap, j) != j)
+ { printf("pan: error writing trailfile\n");
+ close(fd);
+ wrapup();
+ return;
+ }
+ } else /* handoff point */
+ { if (a_cycles)
+ { write(fd, "-1:-1:-1\n", 9);
+ } }
+}
+#endif
+#endif
+
+void
+putrail(void)
+{ int fd;
+#if defined VERI || defined(MERGED)
+ char snap[64];
+#endif
+#if NCORE==1 || defined(SEP_STATE) || !defined(FULL_TRAIL)
+ long i, j;
+ Trail *trl;
+#endif
+ fd = make_trail();
+ if (fd < 0) return;
+#ifdef VERI
+ sprintf(snap, "-2:%d:-2\n", VERI);
+ write(fd, snap, strlen(snap));
+#endif
+#ifdef MERGED
+ sprintf(snap, "-4:-4:-4\n");
+ write(fd, snap, strlen(snap));
+#endif
+#if NCORE>1 && !defined(SEP_STATE) && defined(FULL_TRAIL)
+ rev_trail_cnt = 1;
+ enter_critical(GLOBAL_LOCK);
+ rev_trail(fd, stack_last[core_id]);
+ leave_critical(GLOBAL_LOCK);
+#else
+ i = 1; /* trail starts at position 1 */
+ #if NCORE>1 && defined(SEP_STATE)
+ if (cur_Root.m_vsize > 0) { i++; depth++; }
+ #endif
+ for ( ; i <= depth; i++)
+ { if (i == depthfound+1)
+ write(fd, "-1:-1:-1\n", 9);
+ trl = getframe(i);
+ if (!trl->o_t) continue;
+ if (trl->o_pm&128) continue;
+ sprintf(snap, "%ld:%d:%d\n",
+ i, trl->pr, trl->o_t->t_id);
+ j = strlen(snap);
+ if (write(fd, snap, j) != j)
+ { printf("pan: error writing trailfile\n");
+ close(fd);
+ wrapup();
+ } }
+#endif
+ close(fd);
+#if NCORE>1
+ cpu_printf("pan: wrote trailfile\n");
+#endif
+}
+
+void
+sv_save(void) /* push state vector onto save stack */
+{ if (!svtack->nxt)
+ { svtack->nxt = (Svtack *) emalloc(sizeof(Svtack));
+ svtack->nxt->body = emalloc(vsize*sizeof(char));
+ svtack->nxt->lst = svtack;
+ svtack->nxt->m_delta = vsize;
+ svmax++;
+ } else if (vsize > svtack->nxt->m_delta)
+ { svtack->nxt->body = emalloc(vsize*sizeof(char));
+ svtack->nxt->lst = svtack;
+ svtack->nxt->m_delta = vsize;
+ svmax++;
+ }
+ svtack = svtack->nxt;
+#if SYNC
+ svtack->o_boq = boq;
+#endif
+ svtack->o_delta = vsize; /* don't compress */
+ memcpy((char *)(svtack->body), (char *) &now, vsize);
+#if defined(C_States) && defined(HAS_STACK) && (HAS_TRACK==1)
+ c_stack((uchar *) &(svtack->c_stack[0]));
+#endif
+#ifdef DEBUG
+ cpu_printf("%d: sv_save\n", depth);
+#endif
+}
+
+void
+sv_restor(void) /* pop state vector from save stack */
+{
+ memcpy((char *)&now, svtack->body, svtack->o_delta);
+#if SYNC
+ boq = svtack->o_boq;
+#endif
+#if defined(C_States) && (HAS_TRACK==1)
+#ifdef HAS_STACK
+ c_unstack((uchar *) &(svtack->c_stack[0]));
+#endif
+ c_revert((uchar *) &(now.c_state[0]));
+#endif
+ if (vsize != svtack->o_delta)
+ Uerror("sv_restor");
+ if (!svtack->lst)
+ Uerror("error: v_restor");
+ svtack = svtack->lst;
+#ifdef DEBUG
+ cpu_printf(" sv_restor\n");
+#endif
+}
+
+void
+p_restor(int h)
+{ int i; char *z = (char *) &now;
+
+ proc_offset[h] = stack->o_offset;
+ proc_skip[h] = (uchar) stack->o_skip;
+#ifndef XUSAFE
+ p_name[h] = stack->o_name;
+#endif
+#ifndef NOCOMP
+ for (i = vsize + stack->o_skip; i > vsize; i--)
+ Mask[i-1] = 1; /* align */
+#endif
+ vsize += stack->o_skip;
+ memcpy(z+vsize, stack->body, stack->o_delta);
+ vsize += stack->o_delta;
+#ifndef NOVSZ
+ now._vsz = vsize;
+#endif
+#ifndef NOCOMP
+ for (i = 1; i <= Air[((P0 *)pptr(h))->_t]; i++)
+ Mask[vsize - i] = 1; /* pad */
+ Mask[proc_offset[h]] = 1; /* _pid */
+#endif
+ if (BASE > 0 && h > 0)
+ ((P0 *)pptr(h))->_pid = h-BASE;
+ else
+ ((P0 *)pptr(h))->_pid = h;
+ i = stack->o_delqs;
+ now._nr_pr += 1;
+ if (!stack->lst) /* debugging */
+ Uerror("error: p_restor");
+ stack = stack->lst;
+ this = pptr(h);
+ while (i-- > 0)
+ q_restor();
+}
+
+void
+q_restor(void)
+{ char *z = (char *) &now;
+#ifndef NOCOMP
+ int k, k_end;
+#endif
+ q_offset[now._nr_qs] = stack->o_offset;
+ q_skip[now._nr_qs] = (uchar) stack->o_skip;
+#ifndef XUSAFE
+ q_name[now._nr_qs] = stack->o_name;
+#endif
+ vsize += stack->o_skip;
+ memcpy(z+vsize, stack->body, stack->o_delta);
+ vsize += stack->o_delta;
+#ifndef NOVSZ
+ now._vsz = vsize;
+#endif
+ now._nr_qs += 1;
+#ifndef NOCOMP
+ k_end = stack->o_offset;
+ k = k_end - stack->o_skip;
+#if SYNC
+#ifndef BFS
+ if (q_zero(now._nr_qs)) k_end += stack->o_delta;
+#endif
+#endif
+ for ( ; k < k_end; k++)
+ Mask[k] = 1;
+#endif
+ if (!stack->lst) /* debugging */
+ Uerror("error: q_restor");
+ stack = stack->lst;
+}
+typedef struct IntChunks {
+ int *ptr;
+ struct IntChunks *nxt;
+} IntChunks;
+IntChunks *filled_chunks[512];
+IntChunks *empty_chunks[512];
+int *
+grab_ints(int nr)
+{ IntChunks *z;
+ if (nr >= 512) Uerror("cannot happen grab_int");
+ if (filled_chunks[nr])
+ { z = filled_chunks[nr];
+ filled_chunks[nr] = filled_chunks[nr]->nxt;
+ } else
+ { z = (IntChunks *) emalloc(sizeof(IntChunks));
+ z->ptr = (int *) emalloc(nr * sizeof(int));
+ }
+ z->nxt = empty_chunks[nr];
+ empty_chunks[nr] = z;
+ return z->ptr;
+}
+void
+ungrab_ints(int *p, int nr)
+{ IntChunks *z;
+ if (!empty_chunks[nr]) Uerror("cannot happen ungrab_int");
+ z = empty_chunks[nr];
+ empty_chunks[nr] = empty_chunks[nr]->nxt;
+ z->ptr = p;
+ z->nxt = filled_chunks[nr];
+ filled_chunks[nr] = z;
+}
+int
+delproc(int sav, int h)
+{ int d, i=0;
+#ifndef NOCOMP
+ int o_vsize = vsize;
+#endif
+ if (h+1 != (int) now._nr_pr) return 0;
+
+ while (now._nr_qs
+ && q_offset[now._nr_qs-1] > proc_offset[h])
+ { delq(sav);
+ i++;
+ }
+ d = vsize - proc_offset[h];
+ if (sav)
+ { if (!stack->nxt)
+ { stack->nxt = (Stack *)
+ emalloc(sizeof(Stack));
+ stack->nxt->body =
+ emalloc(Maxbody*sizeof(char));
+ stack->nxt->lst = stack;
+ smax++;
+ }
+ stack = stack->nxt;
+ stack->o_offset = proc_offset[h];
+#if VECTORSZ>32000
+ stack->o_skip = (int) proc_skip[h];
+#else
+ stack->o_skip = (short) proc_skip[h];
+#endif
+#ifndef XUSAFE
+ stack->o_name = p_name[h];
+#endif
+ stack->o_delta = d;
+ stack->o_delqs = i;
+ memcpy(stack->body, (char *)pptr(h), d);
+ }
+ vsize = proc_offset[h];
+ now._nr_pr = now._nr_pr - 1;
+ memset((char *)pptr(h), 0, d);
+ vsize -= (int) proc_skip[h];
+#ifndef NOVSZ
+ now._vsz = vsize;
+#endif
+#ifndef NOCOMP
+ for (i = vsize; i < o_vsize; i++)
+ Mask[i] = 0; /* reset */
+#endif
+ return 1;
+}
+
+void
+delq(int sav)
+{ int h = now._nr_qs - 1;
+ int d = vsize - q_offset[now._nr_qs - 1];
+#ifndef NOCOMP
+ int k, o_vsize = vsize;
+#endif
+ if (sav)
+ { if (!stack->nxt)
+ { stack->nxt = (Stack *)
+ emalloc(sizeof(Stack));
+ stack->nxt->body =
+ emalloc(Maxbody*sizeof(char));
+ stack->nxt->lst = stack;
+ smax++;
+ }
+ stack = stack->nxt;
+ stack->o_offset = q_offset[h];
+#if VECTORSZ>32000
+ stack->o_skip = (int) q_skip[h];
+#else
+ stack->o_skip = (short) q_skip[h];
+#endif
+#ifndef XUSAFE
+ stack->o_name = q_name[h];
+#endif
+ stack->o_delta = d;
+ memcpy(stack->body, (char *)qptr(h), d);
+ }
+ vsize = q_offset[h];
+ now._nr_qs = now._nr_qs - 1;
+ memset((char *)qptr(h), 0, d);
+ vsize -= (int) q_skip[h];
+#ifndef NOVSZ
+ now._vsz = vsize;
+#endif
+#ifndef NOCOMP
+ for (k = vsize; k < o_vsize; k++)
+ Mask[k] = 0; /* reset */
+#endif
+}
+
+int
+qs_empty(void)
+{ int i;
+ for (i = 0; i < (int) now._nr_qs; i++)
+ { if (q_sz(i) > 0)
+ return 0;
+ }
+ return 1;
+}
+
+int
+endstate(void)
+{ int i; P0 *ptr;
+ for (i = BASE; i < (int) now._nr_pr; i++)
+ { ptr = (P0 *) pptr(i);
+ if (!stopstate[ptr->_t][ptr->_p])
+ return 0;
+ }
+ if (strict) return qs_empty();
+#if defined(EVENT_TRACE) && !defined(OTIM)
+ if (!stopstate[EVENT_TRACE][now._event] && !a_cycles)
+ { printf("pan: event_trace not completed\n");
+ return 0;
+ }
+#endif
+ return 1;
+}
+
+#ifndef SAFETY
+void
+checkcycles(void)
+{ uchar o_a_t = now._a_t;
+#ifdef SCHED
+ int o_limit;
+#endif
+#ifndef NOFAIR
+ uchar o_cnt = now._cnt[1];
+#endif
+#ifdef FULLSTACK
+#ifndef MA
+ struct H_el *sv = trpt->ostate; /* save */
+#else
+ uchar prov = trpt->proviso; /* save */
+#endif
+#endif
+#ifdef DEBUG
+ { int i; uchar *v = (uchar *) &now;
+ printf(" set Seed state ");
+#ifndef NOFAIR
+ if (fairness) printf("(cnt = %d:%d, nrpr=%d) ",
+ now._cnt[0], now._cnt[1], now._nr_pr);
+#endif
+ /* for (i = 0; i < n; i++) printf("%d,", v[i]); */
+ printf("\n");
+ }
+ printf("%d: cycle check starts\n", depth);
+#endif
+ now._a_t |= (1|16|32);
+ /* 1 = 2nd DFS; (16|32) to help hasher */
+#ifndef NOFAIR
+ now._cnt[1] = now._cnt[0];
+#endif
+ memcpy((char *)&A_Root, (char *)&now, vsize);
+ A_depth = depthfound = depth;
+#if NCORE>1
+ mem_put_acc();
+#else
+ #ifdef SCHED
+ o_limit = trpt->sched_limit;
+ trpt->sched_limit = 0;
+ #endif
+ new_state(); /* start 2nd DFS */
+ #ifdef SCHED
+ trpt->sched_limit = o_limit;
+ #endif
+#endif
+ now._a_t = o_a_t;
+#ifndef NOFAIR
+ now._cnt[1] = o_cnt;
+#endif
+ A_depth = 0; depthfound = -1;
+#ifdef DEBUG
+ printf("%d: cycle check returns\n", depth);
+#endif
+#ifdef FULLSTACK
+#ifndef MA
+ trpt->ostate = sv; /* restore */
+#else
+ trpt->proviso = prov;
+#endif
+#endif
+}
+#endif
+
+#if defined(FULLSTACK) && defined(BITSTATE)
+struct H_el *Free_list = (struct H_el *) 0;
+void
+onstack_init(void) /* to store stack states in a bitstate search */
+{ S_Tab = (struct H_el **) emalloc(maxdepth*sizeof(struct H_el *));
+}
+struct H_el *
+grab_state(int n)
+{ struct H_el *v, *last = 0;
+ if (H_tab == S_Tab)
+ { for (v = Free_list; v && ((int) v->tagged >= n); v=v->nxt)
+ { if ((int) v->tagged == n)
+ { if (last)
+ last->nxt = v->nxt;
+ else
+gotcha: Free_list = v->nxt;
+ v->tagged = 0;
+ v->nxt = 0;
+#ifdef COLLAPSE
+ v->ln = 0;
+#endif
+ return v;
+ }
+ Fh++; last=v;
+ }
+ /* new: second try */
+ v = Free_list;
+ if (v && ((int) v->tagged >= n))
+ goto gotcha;
+ ngrabs++;
+ }
+ return (struct H_el *)
+ emalloc(sizeof(struct H_el)+n-sizeof(unsigned));
+}
+
+#else
+#if NCORE>1
+struct H_el *
+grab_state(int n)
+{ struct H_el *grab_shared(int);
+ return grab_shared(sizeof(struct H_el)+n-sizeof(unsigned));
+}
+#else
+ #ifndef AUTO_RESIZE
+ #define grab_state(n) (struct H_el *) \
+ emalloc(sizeof(struct H_el)+n-sizeof(unsigned long));
+ #else
+ struct H_el *
+ grab_state(int n)
+ { struct H_el *p;
+ int cnt = sizeof(struct H_el)+n-sizeof(unsigned long);
+
+ if (reclaim_size >= cnt+WS)
+ { if ((cnt & (WS-1)) != 0) /* alignment */
+ { cnt += WS - (cnt & (WS-1));
+ }
+ p = (struct H_el *) reclaim_mem;
+ reclaim_mem += cnt;
+ reclaim_size -= cnt;
+ memset(p, 0, cnt);
+ } else
+ { p = (struct H_el *) emalloc(cnt);
+ }
+ return p;
+ }
+ #endif
+#endif
+#endif
+#ifdef COLLAPSE
+unsigned long
+ordinal(char *v, long n, short tp)
+{ struct H_el *tmp, *ntmp; long m;
+ struct H_el *olst = (struct H_el *) 0;
+ s_hash((uchar *)v, n);
+#if NCORE>1 && !defined(SEP_STATE)
+ enter_critical(CS_ID); /* uses spinlock - 1..128 */
+#endif
+ tmp = H_tab[j1];
+ if (!tmp)
+ { tmp = grab_state(n);
+ H_tab[j1] = tmp;
+ } else
+ for ( ;; olst = tmp, tmp = tmp->nxt)
+ { m = memcmp(((char *)&(tmp->state)), v, n);
+ if (n == tmp->ln)
+ {
+ if (m == 0)
+ goto done;
+ if (m < 0)
+ {
+Insert: ntmp = grab_state(n);
+ ntmp->nxt = tmp;
+ if (!olst)
+ H_tab[j1] = ntmp;
+ else
+ olst->nxt = ntmp;
+ tmp = ntmp;
+ break;
+ } else if (!tmp->nxt)
+ {
+Append: tmp->nxt = grab_state(n);
+ tmp = tmp->nxt;
+ break;
+ }
+ continue;
+ }
+ if (n < tmp->ln)
+ goto Insert;
+ else if (!tmp->nxt)
+ goto Append;
+ }
+ m = ++ncomps[tp];
+#ifdef FULLSTACK
+ tmp->tagged = m;
+#else
+ tmp->st_id = m;
+#endif
+#if defined(AUTO_RESIZE) && !defined(BITSTATE)
+ tmp->m_K1 = K1;
+#endif
+ memcpy(((char *)&(tmp->state)), v, n);
+ tmp->ln = n;
+done:
+#if NCORE>1 && !defined(SEP_STATE)
+ leave_critical(CS_ID); /* uses spinlock */
+#endif
+#ifdef FULLSTACK
+ return tmp->tagged;
+#else
+ return tmp->st_id;
+#endif
+}
+
+int
+compress(char *vin, int nin) /* collapse compression */
+{ char *w, *v = (char *) &comp_now;
+ int i, j;
+ unsigned long n;
+ static char *x;
+ static uchar nbytes[513]; /* 1 + 256 + 256 */
+ static unsigned short nbytelen;
+ long col_q(int, char *);
+ long col_p(int, char *);
+#ifndef SAFETY
+ if (a_cycles)
+ *v++ = now._a_t;
+#ifndef NOFAIR
+ if (fairness)
+ for (i = 0; i < NFAIR; i++)
+ *v++ = now._cnt[i];
+#endif
+#endif
+ nbytelen = 0;
+#ifndef JOINPROCS
+ for (i = 0; i < (int) now._nr_pr; i++)
+ { n = col_p(i, (char *) 0);
+#ifdef NOFIX
+ nbytes[nbytelen] = 0;
+#else
+ nbytes[nbytelen] = 1;
+ *v++ = ((P0 *) pptr(i))->_t;
+#endif
+ *v++ = n&255;
+ if (n >= (1<<8))
+ { nbytes[nbytelen]++;
+ *v++ = (n>>8)&255;
+ }
+ if (n >= (1<<16))
+ { nbytes[nbytelen]++;
+ *v++ = (n>>16)&255;
+ }
+ if (n >= (1<<24))
+ { nbytes[nbytelen]++;
+ *v++ = (n>>24)&255;
+ }
+ nbytelen++;
+ }
+#else
+ x = scratch;
+ for (i = 0; i < (int) now._nr_pr; i++)
+ x += col_p(i, x);
+ n = ordinal(scratch, x-scratch, 2); /* procs */
+ *v++ = n&255;
+ nbytes[nbytelen] = 0;
+ if (n >= (1<<8))
+ { nbytes[nbytelen]++;
+ *v++ = (n>>8)&255;
+ }
+ if (n >= (1<<16))
+ { nbytes[nbytelen]++;
+ *v++ = (n>>16)&255;
+ }
+ if (n >= (1<<24))
+ { nbytes[nbytelen]++;
+ *v++ = (n>>24)&255;
+ }
+ nbytelen++;
+#endif
+#ifdef SEPQS
+ for (i = 0; i < (int) now._nr_qs; i++)
+ { n = col_q(i, (char *) 0);
+ nbytes[nbytelen] = 0;
+ *v++ = n&255;
+ if (n >= (1<<8))
+ { nbytes[nbytelen]++;
+ *v++ = (n>>8)&255;
+ }
+ if (n >= (1<<16))
+ { nbytes[nbytelen]++;
+ *v++ = (n>>16)&255;
+ }
+ if (n >= (1<<24))
+ { nbytes[nbytelen]++;
+ *v++ = (n>>24)&255;
+ }
+ nbytelen++;
+ }
+#endif
+#ifdef NOVSZ
+ /* 3 = _a_t, _nr_pr, _nr_qs */
+ w = (char *) &now + 3 * sizeof(uchar);
+#ifndef NOFAIR
+ w += NFAIR;
+#endif
+#else
+#if VECTORSZ<65536
+ w = (char *) &(now._vsz) + sizeof(unsigned short);
+#else
+ w = (char *) &(now._vsz) + sizeof(unsigned long);
+#endif
+#endif
+ x = scratch;
+ *x++ = now._nr_pr;
+ *x++ = now._nr_qs;
+ if (now._nr_qs > 0 && qptr(0) < pptr(0))
+ n = qptr(0) - (uchar *) w;
+ else
+ n = pptr(0) - (uchar *) w;
+ j = w - (char *) &now;
+ for (i = 0; i < (int) n; i++, w++)
+ if (!Mask[j++]) *x++ = *w;
+#ifndef SEPQS
+ for (i = 0; i < (int) now._nr_qs; i++)
+ x += col_q(i, x);
+#endif
+ x--;
+ for (i = 0, j = 6; i < nbytelen; i++)
+ { if (j == 6)
+ { j = 0;
+ *(++x) = 0;
+ } else
+ j += 2;
+ *x |= (nbytes[i] << j);
+ }
+ x++;
+ for (j = 0; j < WS-1; j++)
+ *x++ = 0;
+ x -= j; j = 0;
+ n = ordinal(scratch, x-scratch, 0); /* globals */
+ *v++ = n&255;
+ if (n >= (1<< 8)) { *v++ = (n>> 8)&255; j++; }
+ if (n >= (1<<16)) { *v++ = (n>>16)&255; j++; }
+ if (n >= (1<<24)) { *v++ = (n>>24)&255; j++; }
+ *v++ = j; /* add last count as a byte */
+ for (i = 0; i < WS-1; i++)
+ *v++ = 0;
+ v -= i;
+#if 0
+ printf("collapse %d -> %d\n",
+ vsize, v - (char *)&comp_now);
+#endif
+ return v - (char *)&comp_now;
+}
+#else
+#if !defined(NOCOMP)
+int
+compress(char *vin, int n) /* default compression */
+{
+#ifdef HC
+ int delta = 0;
+ s_hash((uchar *)vin, n); /* sets K1 and K2 */
+#ifndef SAFETY
+ if (S_A)
+ { delta++; /* _a_t */
+#ifndef NOFAIR
+ if (S_A > NFAIR)
+ delta += NFAIR; /* _cnt[] */
+#endif
+ }
+#endif
+ memcpy((char *) &comp_now + delta, (char *) &K1, WS);
+ delta += WS;
+#if HC>0
+ memcpy((char *) &comp_now + delta, (char *) &K2, HC);
+ delta += HC;
+#endif
+ return delta;
+#else
+ char *vv = vin;
+ char *v = (char *) &comp_now;
+ int i;
+ #ifndef NO_FAST_C
+ int r = 0, unroll = n/8;
+ if (unroll > 0)
+ { i = 0;
+ while (r++ < unroll)
+ { /* unroll 8 times, avoid ifs */
+ /* 1 */ *v = *vv++;
+ v += 1 - Mask[i++];
+ /* 2 */ *v = *vv++;
+ v += 1 - Mask[i++];
+ /* 3 */ *v = *vv++;
+ v += 1 - Mask[i++];
+ /* 4 */ *v = *vv++;
+ v += 1 - Mask[i++];
+ /* 5 */ *v = *vv++;
+ v += 1 - Mask[i++];
+ /* 6 */ *v = *vv++;
+ v += 1 - Mask[i++];
+ /* 7 */ *v = *vv++;
+ v += 1 - Mask[i++];
+ /* 8 */ *v = *vv++;
+ v += 1 - Mask[i++];
+ }
+ r = n - i; /* the rest, at most 7 */
+ switch (r) {
+ case 7: *v = *vv++; v += 1 - Mask[i++];
+ case 6: *v = *vv++; v += 1 - Mask[i++];
+ case 5: *v = *vv++; v += 1 - Mask[i++];
+ case 4: *v = *vv++; v += 1 - Mask[i++];
+ case 3: *v = *vv++; v += 1 - Mask[i++];
+ case 2: *v = *vv++; v += 1 - Mask[i++];
+ case 1: *v = *vv++; v += 1 - Mask[i++];
+ case 0: break;
+ }
+ r = (n+WS-1)/WS; /* words rounded up */
+ r *= WS; /* bytes */
+ i = r - i; /* remainder */
+ switch (i) {
+ case 7: *v++ = 0; /* fall thru */
+ case 6: *v++ = 0;
+ case 5: *v++ = 0;
+ case 4: *v++ = 0;
+ case 3: *v++ = 0;
+ case 2: *v++ = 0;
+ case 1: *v++ = 0;
+ case 0: break;
+ default: Uerror("unexpected wordsize");
+ }
+ v -= i;
+ } else
+ #endif
+ { for (i = 0; i < n; i++, vv++)
+ if (!Mask[i]) *v++ = *vv;
+ for (i = 0; i < WS-1; i++)
+ *v++ = 0;
+ v -= i;
+ }
+#if 0
+ printf("compress %d -> %d\n",
+ n, v - (char *)&comp_now);
+#endif
+ return v - (char *)&comp_now;
+#endif
+}
+#endif
+#endif
+#if defined(FULLSTACK) && defined(BITSTATE)
+#if defined(MA)
+#if !defined(onstack_now)
+int onstack_now(void) {}
+#endif
+#if !defined(onstack_put)
+void onstack_put(void) {}
+#endif
+#if !defined(onstack_zap)
+void onstack_zap(void) {}
+#endif
+#else
+void
+onstack_zap(void)
+{ struct H_el *v, *w, *last = 0;
+ struct H_el **tmp = H_tab;
+ char *nv; int n, m;
+
+ static char warned = 0;
+
+ H_tab = S_Tab;
+#ifndef NOCOMP
+ nv = (char *) &comp_now;
+ n = compress((char *)&now, vsize);
+#else
+#if defined(BITSTATE) && defined(LC)
+ nv = (char *) &comp_now;
+ n = compact_stack((char *)&now, vsize);
+#else
+ nv = (char *) &now;
+ n = vsize;
+#endif
+#endif
+#if !defined(HC) && !(defined(BITSTATE) && defined(LC))
+ s_hash((uchar *)nv, n);
+#endif
+ H_tab = tmp;
+ for (v = S_Tab[j1]; v; Zh++, last=v, v=v->nxt)
+ { m = memcmp(&(v->state), nv, n);
+ if (m == 0)
+ goto Found;
+ if (m < 0)
+ break;
+ }
+/* NotFound: */
+#ifndef ZAPH
+ #if defined(BITSTATE) && NCORE>1
+ /* seen this happen, likely harmless, but not yet understood */
+ if (warned == 0)
+ #endif
+ { /* Uerror("stack out of wack - zap"); */
+ cpu_printf("pan: warning, stack incomplete\n");
+ warned = 1;
+ }
+#endif
+ return;
+Found:
+ ZAPS++;
+ if (last)
+ last->nxt = v->nxt;
+ else
+ S_Tab[j1] = v->nxt;
+ v->tagged = (unsigned) n;
+#if !defined(NOREDUCE) && !defined(SAFETY)
+ v->proviso = 0;
+#endif
+ v->nxt = last = (struct H_el *) 0;
+ for (w = Free_list; w; Fa++, last=w, w = w->nxt)
+ { if ((int) w->tagged <= n)
+ { if (last)
+ { v->nxt = w;
+ last->nxt = v;
+ } else
+ { v->nxt = Free_list;
+ Free_list = v;
+ }
+ return;
+ }
+ if (!w->nxt)
+ { w->nxt = v;
+ return;
+ } }
+ Free_list = v;
+}
+void
+onstack_put(void)
+{ struct H_el **tmp = H_tab;
+ H_tab = S_Tab;
+ if (hstore((char *)&now, vsize) != 0)
+#if defined(BITSTATE) && defined(LC)
+ printf("pan: warning, double stack entry\n");
+#else
+ #ifndef ZAPH
+ Uerror("cannot happen - unstack_put");
+ #endif
+#endif
+ H_tab = tmp;
+ trpt->ostate = Lstate;
+ PUT++;
+}
+int
+onstack_now(void)
+{ struct H_el *tmp;
+ struct H_el **tmp2 = H_tab;
+ char *v; int n, m = 1;
+
+ H_tab = S_Tab;
+#ifdef NOCOMP
+#if defined(BITSTATE) && defined(LC)
+ v = (char *) &comp_now;
+ n = compact_stack((char *)&now, vsize);
+#else
+ v = (char *) &now;
+ n = vsize;
+#endif
+#else
+ v = (char *) &comp_now;
+ n = compress((char *)&now, vsize);
+#endif
+#if !defined(HC) && !(defined(BITSTATE) && defined(LC))
+ s_hash((uchar *)v, n);
+#endif
+ H_tab = tmp2;
+ for (tmp = S_Tab[j1]; tmp; Zn++, tmp = tmp->nxt)
+ { m = memcmp(((char *)&(tmp->state)),v,n);
+ if (m <= 0)
+ { Lstate = (struct H_el *) tmp;
+ break;
+ } }
+ PROBE++;
+ return (m == 0);
+}
+#endif
+#endif
+#ifndef BITSTATE
+void
+hinit(void)
+{
+ #ifdef MA
+#ifdef R_XPT
+ { void r_xpoint(void);
+ r_xpoint();
+ }
+#else
+ dfa_init((unsigned short) (MA+a_cycles));
+#if NCORE>1 && !defined(COLLAPSE)
+ if (!readtrail)
+ { void init_HT(unsigned long);
+ init_HT(0L);
+ }
+#endif
+#endif
+ #endif
+ #if !defined(MA) || defined(COLLAPSE)
+#if NCORE>1
+ if (!readtrail)
+ { void init_HT(unsigned long);
+ init_HT((unsigned long) (ONE_L<<ssize)*sizeof(struct H_el *));
+ } else
+#endif
+ H_tab = (struct H_el **)
+ emalloc((ONE_L<<ssize)*sizeof(struct H_el *));
+ #endif
+}
+#endif
+
+#if !defined(BITSTATE) || defined(FULLSTACK)
+#ifdef DEBUG
+void
+dumpstate(int wasnew, char *v, int n, int tag)
+{ int i;
+#ifndef SAFETY
+ if (S_A)
+ { printf(" state tags %d (%d::%d): ",
+ V_A, wasnew, v[0]);
+#ifdef FULLSTACK
+ printf(" %d ", tag);
+#endif
+ printf("\n");
+ }
+#endif
+#ifdef SDUMP
+#ifndef NOCOMP
+ printf(" State: ");
+ for (i = 0; i < vsize; i++) printf("%d%s,",
+ ((char *)&now)[i], Mask[i]?"*":"");
+#endif
+ printf("\n Vector: ");
+ for (i = 0; i < n; i++) printf("%d,", v[i]);
+ printf("\n");
+#endif
+}
+#endif
+#ifdef MA
+int
+gstore(char *vin, int nin, uchar pbit)
+{ int n, i;
+ int ret_val = 1;
+ uchar *v;
+ static uchar Info[MA+1];
+#ifndef NOCOMP
+ n = compress(vin, nin);
+ v = (uchar *) &comp_now;
+#else
+ n = nin;
+ v = vin;
+#endif
+ if (n >= MA)
+ { printf("pan: error, MA too small, recompile pan.c");
+ printf(" with -DMA=N with N>%d\n", n);
+ Uerror("aborting");
+ }
+ if (n > (int) maxgs)
+ { maxgs = (unsigned int) n;
+ }
+ for (i = 0; i < n; i++)
+ { Info[i] = v[i];
+ }
+ for ( ; i < MA-1; i++)
+ { Info[i] = 0;
+ }
+ Info[MA-1] = pbit;
+ if (a_cycles) /* place _a_t at the end */
+ { Info[MA] = Info[0];
+ Info[0] = 0;
+ }
+
+#if NCORE>1 && !defined(SEP_STATE)
+ enter_critical(GLOBAL_LOCK); /* crude, but necessary */
+ /* to make this mode work, also replace emalloc with grab_shared inside store MA routines */
+#endif
+
+ if (!dfa_store(Info))
+ { if (pbit == 0
+ && (now._a_t&1)
+ && depth > A_depth)
+ { Info[MA] &= ~(1|16|32); /* _a_t */
+ if (dfa_member(MA))
+ { Info[MA-1] = 4; /* off-stack bit */
+ nShadow++;
+ if (!dfa_member(MA-1))
+ { ret_val = 3;
+ #ifdef VERBOSE
+ printf("intersected 1st dfs stack\n");
+ #endif
+ goto done;
+ } } }
+ ret_val = 0;
+ #ifdef VERBOSE
+ printf("new state\n");
+ #endif
+ goto done;
+ }
+#ifdef FULLSTACK
+ if (pbit == 0)
+ { Info[MA-1] = 1; /* proviso bit */
+#ifndef BFS
+ trpt->proviso = dfa_member(MA-1);
+#endif
+ Info[MA-1] = 4; /* off-stack bit */
+ if (dfa_member(MA-1))
+ { ret_val = 1; /* off-stack */
+ #ifdef VERBOSE
+ printf("old state\n");
+ #endif
+ } else
+ { ret_val = 2; /* on-stack */
+ #ifdef VERBOSE
+ printf("on-stack\n");
+ #endif
+ }
+ goto done;
+ }
+#endif
+ ret_val = 1;
+#ifdef VERBOSE
+ printf("old state\n");
+#endif
+done:
+#if NCORE>1 && !defined(SEP_STATE)
+ leave_critical(GLOBAL_LOCK);
+#endif
+ return ret_val; /* old state */
+}
+#endif
+#if defined(BITSTATE) && defined(LC)
+int
+compact_stack(char *vin, int n)
+{ int delta = 0;
+ s_hash((uchar *)vin, n); /* sets K1 and K2 */
+#ifndef SAFETY
+ delta++; /* room for state[0] |= 128 */
+#endif
+ memcpy((char *) &comp_now + delta, (char *) &K1, WS);
+ delta += WS;
+ memcpy((char *) &comp_now + delta, (char *) &K2, WS);
+ delta += WS; /* use all available bits */
+ return delta;
+}
+#endif
+int
+hstore(char *vin, int nin) /* hash table storage */
+{ struct H_el *ntmp;
+ struct H_el *tmp, *olst = (struct H_el *) 0;
+ char *v; int n, m=0;
+#ifdef HC
+ uchar rem_a;
+#endif
+#ifdef NOCOMP
+#if defined(BITSTATE) && defined(LC)
+ if (S_Tab == H_tab)
+ { v = (char *) &comp_now;
+ n = compact_stack(vin, nin);
+ } else
+ { v = vin; n = nin;
+ }
+#else
+ v = vin; n = nin;
+#endif
+#else
+ v = (char *) &comp_now;
+ #ifdef HC
+ rem_a = now._a_t;
+ now._a_t = 0;
+ #endif
+ n = compress(vin, nin);
+ #ifdef HC
+ now._a_t = rem_a;
+ #endif
+#ifndef SAFETY
+ if (S_A)
+ { v[0] = 0; /* _a_t */
+#ifndef NOFAIR
+ if (S_A > NFAIR)
+ for (m = 0; m < NFAIR; m++)
+ v[m+1] = 0; /* _cnt[] */
+#endif
+ m = 0;
+ }
+ #endif
+#endif
+#if !defined(HC) && !(defined(BITSTATE) && defined(LC))
+ s_hash((uchar *)v, n);
+#endif
+#if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)
+ enter_critical(CS_ID); /* uses spinlock */
+#endif
+ tmp = H_tab[j1];
+ if (!tmp)
+ { tmp = grab_state(n);
+#if NCORE>1
+ if (!tmp)
+ { /* if we get here -- we've already issued a warning */
+ /* but we want to allow the normal distributed termination */
+ /* to collect the stats on all cpus in the wrapup */
+ #if !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+ #endif
+ return 1; /* allow normal termination */
+ }
+#endif
+ H_tab[j1] = tmp;
+ } else
+ { for (;; hcmp++, olst = tmp, tmp = tmp->nxt)
+ { /* skip the _a_t and the _cnt bytes */
+#ifdef COLLAPSE
+ if (tmp->ln != 0)
+ { if (!tmp->nxt) goto Append;
+ continue;
+ }
+#endif
+ m = memcmp(((char *)&(tmp->state)) + S_A,
+ v + S_A, n - S_A);
+ if (m == 0) {
+#ifdef SAFETY
+#define wasnew 0
+#else
+ int wasnew = 0;
+#endif
+#ifndef SAFETY
+#ifndef NOCOMP
+ if (S_A)
+ { if ((((char *)&(tmp->state))[0] & V_A) != V_A)
+ { wasnew = 1; nShadow++;
+ ((char *)&(tmp->state))[0] |= V_A;
+ }
+#ifndef NOFAIR
+ if (S_A > NFAIR)
+ { /* 0 <= now._cnt[now._a_t&1] < MAXPROC */
+ unsigned ci, bp; /* index, bit pos */
+ ci = (now._cnt[now._a_t&1] / 8);
+ bp = (now._cnt[now._a_t&1] - 8*ci);
+ if (now._a_t&1) /* use tail-bits in _cnt */
+ { ci = (NFAIR - 1) - ci;
+ bp = 7 - bp; /* bp = 0..7 */
+ }
+ ci++; /* skip over _a_t */
+ bp = 1 << bp; /* the bit mask */
+ if ((((char *)&(tmp->state))[ci] & bp)==0)
+ { if (!wasnew)
+ { wasnew = 1;
+ nShadow++;
+ }
+ ((char *)&(tmp->state))[ci] |= bp;
+ }
+ }
+ /* else: wasnew == 0, i.e., old state */
+#endif
+ }
+#endif
+#endif
+#if NCORE>1
+ Lstate = (struct H_el *) tmp;
+#endif
+#ifdef FULLSTACK
+#ifndef SAFETY
+ if (wasnew)
+ { Lstate = (struct H_el *) tmp;
+ tmp->tagged |= V_A;
+ if ((now._a_t&1)
+ && (tmp->tagged&A_V)
+ && depth > A_depth)
+ {
+intersect:
+#ifdef CHECK
+#if NCORE>1
+ printf("cpu%d: ", core_id);
+#endif
+ printf("1st dfs-stack intersected on state %d+\n",
+ (int) tmp->st_id);
+#endif
+#if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+#endif
+ return 3;
+ }
+#ifdef CHECK
+#if NCORE>1
+ printf("cpu%d: ", core_id);
+#endif
+ printf(" New state %d+\n", (int) tmp->st_id);
+#endif
+#ifdef DEBUG
+ dumpstate(1, (char *)&(tmp->state),n,tmp->tagged);
+#endif
+#if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+#endif
+ return 0;
+ } else
+#endif
+ if ((S_A)?(tmp->tagged&V_A):tmp->tagged)
+ { Lstate = (struct H_el *) tmp;
+#ifndef SAFETY
+ /* already on current dfs stack */
+ /* but may also be on 1st dfs stack */
+ if ((now._a_t&1)
+ && (tmp->tagged&A_V)
+ && depth > A_depth
+#ifndef NOFAIR
+ && (!fairness || now._cnt[1] <= 1)
+#endif
+ )
+ goto intersect;
+#endif
+#ifdef CHECK
+#if NCORE>1
+ printf("cpu%d: ", core_id);
+#endif
+ printf(" Stack state %d\n", (int) tmp->st_id);
+#endif
+#ifdef DEBUG
+ dumpstate(0, (char *)&(tmp->state),n,tmp->tagged);
+#endif
+#if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+#endif
+ return 2; /* match on stack */
+ }
+#else
+ if (wasnew)
+ {
+#ifdef CHECK
+#if NCORE>1
+ printf("cpu%d: ", core_id);
+#endif
+ printf(" New state %d+\n", (int) tmp->st_id);
+#endif
+#ifdef DEBUG
+ dumpstate(1, (char *)&(tmp->state), n, 0);
+#endif
+#if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+#endif
+ return 0;
+ }
+#endif
+#ifdef CHECK
+#if NCORE>1
+ printf("cpu%d: ", core_id);
+#endif
+ printf(" Old state %d\n", (int) tmp->st_id);
+#endif
+#ifdef DEBUG
+ dumpstate(0, (char *)&(tmp->state), n, 0);
+#endif
+#ifdef REACH
+ if (tmp->D > depth)
+ { tmp->D = depth;
+#ifdef CHECK
+#if NCORE>1
+ printf("cpu%d: ", core_id);
+#endif
+ printf(" ReVisiting (from smaller depth)\n");
+#endif
+ nstates--;
+#if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+#endif
+ return 0;
+ }
+#endif
+#if (defined(BFS) && defined(Q_PROVISO)) || NCORE>1
+ Lstate = (struct H_el *) tmp;
+#endif
+#if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+#endif
+ return 1; /* match outside stack */
+ } else if (m < 0)
+ { /* insert state before tmp */
+ ntmp = grab_state(n);
+#if NCORE>1
+ if (!ntmp)
+ {
+ #if !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+ #endif
+ return 1; /* allow normal termination */
+ }
+#endif
+ ntmp->nxt = tmp;
+ if (!olst)
+ H_tab[j1] = ntmp;
+ else
+ olst->nxt = ntmp;
+ tmp = ntmp;
+ break;
+ } else if (!tmp->nxt)
+ { /* append after tmp */
+#ifdef COLLAPSE
+Append:
+#endif
+ tmp->nxt = grab_state(n);
+#if NCORE>1
+ if (!tmp->nxt)
+ {
+ #if !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+ #endif
+ return 1; /* allow normal termination */
+ }
+#endif
+ tmp = tmp->nxt;
+ break;
+ } }
+ }
+#ifdef CHECK
+ tmp->st_id = (unsigned) nstates;
+#if NCORE>1
+ printf("cpu%d: ", core_id);
+#endif
+#ifdef BITSTATE
+ printf(" Push state %d\n", ((int) nstates) - 1);
+#else
+ printf(" New state %d\n", (int) nstates);
+#endif
+#endif
+#if !defined(SAFETY) || defined(REACH)
+ tmp->D = depth;
+#endif
+#ifndef SAFETY
+#ifndef NOCOMP
+ if (S_A)
+ { v[0] = V_A;
+#ifndef NOFAIR
+ if (S_A > NFAIR)
+ { unsigned ci, bp; /* as above */
+ ci = (now._cnt[now._a_t&1] / 8);
+ bp = (now._cnt[now._a_t&1] - 8*ci);
+ if (now._a_t&1)
+ { ci = (NFAIR - 1) - ci;
+ bp = 7 - bp; /* bp = 0..7 */
+ }
+ v[1+ci] = 1 << bp;
+ }
+#endif
+ }
+#endif
+#endif
+#if defined(AUTO_RESIZE) && !defined(BITSTATE)
+ tmp->m_K1 = K1;
+#endif
+ memcpy(((char *)&(tmp->state)), v, n);
+#ifdef FULLSTACK
+ tmp->tagged = (S_A)?V_A:(depth+1);
+#ifdef DEBUG
+ dumpstate(-1, v, n, tmp->tagged);
+#endif
+ Lstate = (struct H_el *) tmp;
+#else
+ #ifdef DEBUG
+ dumpstate(-1, v, n, 0);
+ #endif
+ #if NCORE>1
+ Lstate = (struct H_el *) tmp;
+ #endif
+#endif
+/* #if NCORE>1 && !defined(SEP_STATE) */
+#if NCORE>1
+ #ifdef V_PROVISO
+ tmp->cpu_id = core_id;
+ #endif
+ #if !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+ #endif
+#endif
+ return 0;
+}
+#endif
+#include TRANSITIONS
+void
+do_reach(void)
+{
+ r_ck(reached0, nstates0, 0, src_ln0, src_file0);
+ r_ck(reached1, nstates1, 1, src_ln1, src_file1);
+ r_ck(reached2, nstates2, 2, src_ln2, src_file2);
+ r_ck(reached3, nstates3, 3, src_ln3, src_file3);
+ r_ck(reached4, nstates4, 4, src_ln4, src_file4);
+ r_ck(reached5, nstates5, 5, src_ln5, src_file5);
+}
+
+void
+iniglobals(void)
+{
+ deliver = 0;
+ { int l_in;
+ for (l_in = 0; l_in < 4; l_in++)
+ {
+ now.buffer_use[l_in] = 0;
+ }
+ }
+ now.write_off = 0;
+ { int l_in;
+ for (l_in = 0; l_in < 2; l_in++)
+ {
+ now.commit_count[l_in] = 0;
+ }
+ }
+ now._commit_sum = 0;
+ now.read_off = 0;
+ now.events_lost = 0;
+ now.refcount = 0;
+#ifdef VAR_RANGES
+ { int l_in;
+ for (l_in = 0; l_in < 4; l_in++)
+ {
+ logval("buffer_use[l_in]", now.buffer_use[l_in]);
+ }
+ }
+ logval("write_off", now.write_off);
+ { int l_in;
+ for (l_in = 0; l_in < 2; l_in++)
+ {
+ logval("commit_count[l_in]", now.commit_count[l_in]);
+ }
+ }
+ logval("_commit_sum", now._commit_sum);
+ logval("read_off", now.read_off);
+ logval("events_lost", now.events_lost);
+ logval("refcount", now.refcount);
+#endif
+ Maxbody = max(Maxbody, sizeof(State)-VECTORSZ);
+}
+
+int
+addqueue(int n, int is_rv)
+{ int j=0, i = now._nr_qs;
+#ifndef NOCOMP
+ int k;
+#endif
+ if (i >= MAXQ)
+ Uerror("too many queues");
+ switch (n) {
+ default: Uerror("bad queue - addqueue");
+ }
+ if (vsize%WS)
+ q_skip[i] = WS-(vsize%WS);
+ else
+ q_skip[i] = 0;
+#ifndef NOCOMP
+ k = vsize;
+#ifndef BFS
+ if (is_rv) k += j;
+#endif
+ for (k += (int) q_skip[i]; k > vsize; k--)
+ Mask[k-1] = 1;
+#endif
+ vsize += (int) q_skip[i];
+ q_offset[i] = vsize;
+ now._nr_qs += 1;
+ vsize += j;
+#ifndef NOVSZ
+ now._vsz = vsize;
+#endif
+ hmax = max(hmax, vsize);
+ if (vsize >= VECTORSZ)
+ Uerror("VECTORSZ is too small, edit pan.h");
+ memset((char *)qptr(i), 0, j);
+ ((Q0 *)qptr(i))->_t = n;
+ return i+1;
+}
+
+#if NQS>0
+void
+qsend(int into, int sorted, int args_given)
+{ int j; uchar *z;
+
+#ifdef HAS_SORTED
+ int k;
+#endif
+ if (!into--)
+ uerror("ref to uninitialized chan name (sending)");
+ if (into >= (int) now._nr_qs || into < 0)
+ Uerror("qsend bad queue#");
+ z = qptr(into);
+ j = ((Q0 *)qptr(into))->Qlen;
+ switch (((Q0 *)qptr(into))->_t) {
+ case 0: printf("queue %d was deleted\n", into+1);
+ default: Uerror("bad queue - qsend");
+ }
+#ifdef EVENT_TRACE
+ if (in_s_scope(into+1))
+ require('s', into);
+#endif
+}
+#endif
+
+#if SYNC
+int
+q_zero(int from)
+{ if (!from--)
+ { uerror("ref to uninitialized chan name (q_zero)");
+ return 0;
+ }
+ switch(((Q0 *)qptr(from))->_t) {
+ case 0: printf("queue %d was deleted\n", from+1);
+ }
+ Uerror("bad queue q-zero");
+ return -1;
+}
+int
+not_RV(int from)
+{ if (q_zero(from))
+ { printf("==>> a test of the contents of a rv ");
+ printf("channel always returns FALSE\n");
+ uerror("error to poll rendezvous channel");
+ }
+ return 1;
+}
+#endif
+#ifndef XUSAFE
+void
+setq_claim(int x, int m, char *s, int y, char *p)
+{ if (x == 0)
+ uerror("x[rs] claim on uninitialized channel");
+ if (x < 0 || x > MAXQ)
+ Uerror("cannot happen setq_claim");
+ q_claim[x] |= m;
+ p_name[y] = p;
+ q_name[x] = s;
+ if (m&2) q_S_check(x, y);
+ if (m&1) q_R_check(x, y);
+}
+short q_sender[MAXQ+1];
+int
+q_S_check(int x, int who)
+{ if (!q_sender[x])
+ { q_sender[x] = who+1;
+#if SYNC
+ if (q_zero(x))
+ { printf("chan %s (%d), ",
+ q_name[x], x-1);
+ printf("sndr proc %s (%d)\n",
+ p_name[who], who);
+ uerror("xs chans cannot be used for rv");
+ }
+#endif
+ } else
+ if (q_sender[x] != who+1)
+ { printf("pan: xs assertion violated: ");
+ printf("access to chan <%s> (%d)\npan: by ",
+ q_name[x], x-1);
+ if (q_sender[x] > 0 && p_name[q_sender[x]-1])
+ printf("%s (proc %d) and by ",
+ p_name[q_sender[x]-1], q_sender[x]-1);
+ printf("%s (proc %d)\n",
+ p_name[who], who);
+ uerror("error, partial order reduction invalid");
+ }
+ return 1;
+}
+short q_recver[MAXQ+1];
+int
+q_R_check(int x, int who)
+{ if (!q_recver[x])
+ { q_recver[x] = who+1;
+#if SYNC
+ if (q_zero(x))
+ { printf("chan %s (%d), ",
+ q_name[x], x-1);
+ printf("recv proc %s (%d)\n",
+ p_name[who], who);
+ uerror("xr chans cannot be used for rv");
+ }
+#endif
+ } else
+ if (q_recver[x] != who+1)
+ { printf("pan: xr assertion violated: ");
+ printf("access to chan %s (%d)\npan: ",
+ q_name[x], x-1);
+ if (q_recver[x] > 0 && p_name[q_recver[x]-1])
+ printf("by %s (proc %d) and ",
+ p_name[q_recver[x]-1], q_recver[x]-1);
+ printf("by %s (proc %d)\n",
+ p_name[who], who);
+ uerror("error, partial order reduction invalid");
+ }
+ return 1;
+}
+#endif
+int
+q_len(int x)
+{ if (!x--)
+ uerror("ref to uninitialized chan name (len)");
+ return ((Q0 *)qptr(x))->Qlen;
+}
+
+int
+q_full(int from)
+{ if (!from--)
+ uerror("ref to uninitialized chan name (qfull)");
+ switch(((Q0 *)qptr(from))->_t) {
+ case 0: printf("queue %d was deleted\n", from+1);
+ }
+ Uerror("bad queue - q_full");
+ return 0;
+}
+
+#ifdef HAS_UNLESS
+int
+q_e_f(int from)
+{ /* empty or full */
+ return !q_len(from) || q_full(from);
+}
+#endif
+#if NQS>0
+int
+qrecv(int from, int slot, int fld, int done)
+{ uchar *z;
+ int j, k, r=0;
+
+ if (!from--)
+ uerror("ref to uninitialized chan name (receiving)");
+ if (from >= (int) now._nr_qs || from < 0)
+ Uerror("qrecv bad queue#");
+ z = qptr(from);
+#ifdef EVENT_TRACE
+ if (done && (in_r_scope(from+1)))
+ require('r', from);
+#endif
+ switch (((Q0 *)qptr(from))->_t) {
+ case 0: printf("queue %d was deleted\n", from+1);
+ default: Uerror("bad queue - qrecv");
+ }
+ return r;
+}
+#endif
+
+#ifndef BITSTATE
+#ifdef COLLAPSE
+long
+col_q(int i, char *z)
+{ int j=0, k;
+ char *x, *y;
+ Q0 *ptr = (Q0 *) qptr(i);
+ switch (ptr->_t) {
+ default: Uerror("bad qtype - collapse");
+ }
+ if (z) x = z; else x = scratch;
+ y = (char *) ptr; k = q_offset[i];
+ /* no need to store the empty slots at the end */
+ j -= (q_max[ptr->_t] - ptr->Qlen) * ((j - 2)/q_max[ptr->_t]);
+ for ( ; j > 0; j--, y++)
+ if (!Mask[k++]) *x++ = *y;
+ for (j = 0; j < WS-1; j++)
+ *x++ = 0;
+ x -= j;
+ if (z) return (long) (x - z);
+ return ordinal(scratch, x-scratch, 1); /* chan */
+}
+#endif
+#endif
+int
+unsend(int into)
+{ int _m=0, j; uchar *z;
+
+#ifdef HAS_SORTED
+ int k;
+#endif
+ if (!into--)
+ uerror("ref to uninitialized chan (unsend)");
+ z = qptr(into);
+ j = ((Q0 *)z)->Qlen;
+ ((Q0 *)z)->Qlen = --j;
+ switch (((Q0 *)qptr(into))->_t) {
+ default: Uerror("bad queue - unsend");
+ }
+ return _m;
+}
+
+void
+unrecv(int from, int slot, int fld, int fldvar, int strt)
+{ int j; uchar *z;
+
+ if (!from--)
+ uerror("ref to uninitialized chan (unrecv)");
+ z = qptr(from);
+ j = ((Q0 *)z)->Qlen;
+ if (strt) ((Q0 *)z)->Qlen = j+1;
+ switch (((Q0 *)qptr(from))->_t) {
+ default: Uerror("bad queue - qrecv");
+ }
+}
+int
+q_cond(short II, Trans *t)
+{ int i = 0;
+ for (i = 0; i < 6; i++)
+ { if (t->ty[i] == TIMEOUT_F) return 1;
+ if (t->ty[i] == ALPHA_F)
+#ifdef GLOB_ALPHA
+ return 0;
+#else
+ return (II+1 == (short) now._nr_pr && II+1 < MAXPROC);
+#endif
+ switch (t->qu[i]) {
+ case 0: break;
+ default: Uerror("unknown qid - q_cond");
+ return 0;
+ }
+ }
+ return 1;
+}
+void
+to_compile(void)
+{ char ctd[1024], carg[64];
+#ifdef BITSTATE
+ strcpy(ctd, "-DBITSTATE ");
+#else
+ strcpy(ctd, "");
+#endif
+#ifdef NOVSZ
+ strcat(ctd, "-DNOVSZ ");
+#endif
+#ifdef REVERSE
+ strcat(ctd, "-DREVERSE ");
+#endif
+#ifdef T_REVERSE
+ strcat(ctd, "-DT_REVERSE ");
+#endif
+#ifdef RANDOMIZE
+ #if RANDOMIZE>0
+ sprintf(carg, "-DRANDOMIZE=%d ", RANDOMIZE);
+ strcat(ctd, carg);
+ #else
+ strcat(ctd, "-DRANDOMIZE ");
+ #endif
+#endif
+#ifdef SCHED
+ sprintf(carg, "-DSCHED=%d ", SCHED);
+ strcat(ctd, carg);
+#endif
+#ifdef BFS
+ strcat(ctd, "-DBFS ");
+#endif
+#ifdef MEMLIM
+ sprintf(carg, "-DMEMLIM=%d ", MEMLIM);
+ strcat(ctd, carg);
+#else
+#ifdef MEMCNT
+ sprintf(carg, "-DMEMCNT=%d ", MEMCNT);
+ strcat(ctd, carg);
+#endif
+#endif
+#ifdef NOCLAIM
+ strcat(ctd, "-DNOCLAIM ");
+#endif
+#ifdef SAFETY
+ strcat(ctd, "-DSAFETY ");
+#else
+#ifdef NOFAIR
+ strcat(ctd, "-DNOFAIR ");
+#else
+#ifdef NFAIR
+ if (NFAIR != 2)
+ { sprintf(carg, "-DNFAIR=%d ", NFAIR);
+ strcat(ctd, carg);
+ }
+#endif
+#endif
+#endif
+#ifdef NOREDUCE
+ strcat(ctd, "-DNOREDUCE ");
+#else
+#ifdef XUSAFE
+ strcat(ctd, "-DXUSAFE ");
+#endif
+#endif
+#ifdef NP
+ strcat(ctd, "-DNP ");
+#endif
+#ifdef PEG
+ strcat(ctd, "-DPEG ");
+#endif
+#ifdef VAR_RANGES
+ strcat(ctd, "-DVAR_RANGES ");
+#endif
+#ifdef HC0
+ strcat(ctd, "-DHC0 ");
+#endif
+#ifdef HC1
+ strcat(ctd, "-DHC1 ");
+#endif
+#ifdef HC2
+ strcat(ctd, "-DHC2 ");
+#endif
+#ifdef HC3
+ strcat(ctd, "-DHC3 ");
+#endif
+#ifdef HC4
+ strcat(ctd, "-DHC4 ");
+#endif
+#ifdef CHECK
+ strcat(ctd, "-DCHECK ");
+#endif
+#ifdef CTL
+ strcat(ctd, "-DCTL ");
+#endif
+#ifdef NIBIS
+ strcat(ctd, "-DNIBIS ");
+#endif
+#ifdef NOBOUNDCHECK
+ strcat(ctd, "-DNOBOUNDCHECK ");
+#endif
+#ifdef NOSTUTTER
+ strcat(ctd, "-DNOSTUTTER ");
+#endif
+#ifdef REACH
+ strcat(ctd, "-DREACH ");
+#endif
+#ifdef PRINTF
+ strcat(ctd, "-DPRINTF ");
+#endif
+#ifdef OTIM
+ strcat(ctd, "-DOTIM ");
+#endif
+#ifdef COLLAPSE
+ strcat(ctd, "-DCOLLAPSE ");
+#endif
+#ifdef MA
+ sprintf(carg, "-DMA=%d ", MA);
+ strcat(ctd, carg);
+#endif
+#ifdef SVDUMP
+ strcat(ctd, "-DSVDUMP ");
+#endif
+#ifdef VECTORSZ
+ if (VECTORSZ != 1024)
+ { sprintf(carg, "-DVECTORSZ=%d ", VECTORSZ);
+ strcat(ctd, carg);
+ }
+#endif
+#ifdef VERBOSE
+ strcat(ctd, "-DVERBOSE ");
+#endif
+#ifdef CHECK
+ strcat(ctd, "-DCHECK ");
+#endif
+#ifdef SDUMP
+ strcat(ctd, "-DSDUMP ");
+#endif
+#if NCORE>1
+ sprintf(carg, "-DNCORE=%d ", NCORE);
+ strcat(ctd, carg);
+#endif
+#ifdef SFH
+ sprintf(carg, "-DSFH ");
+ strcat(ctd, carg);
+#endif
+#ifdef VMAX
+ if (VMAX != 256)
+ { sprintf(carg, "-DVMAX=%d ", VMAX);
+ strcat(ctd, carg);
+ }
+#endif
+#ifdef PMAX
+ if (PMAX != 16)
+ { sprintf(carg, "-DPMAX=%d ", PMAX);
+ strcat(ctd, carg);
+ }
+#endif
+#ifdef QMAX
+ if (QMAX != 16)
+ { sprintf(carg, "-DQMAX=%d ", QMAX);
+ strcat(ctd, carg);
+ }
+#endif
+#ifdef SET_WQ_SIZE
+ sprintf(carg, "-DSET_WQ_SIZE=%d ", SET_WQ_SIZE);
+ strcat(ctd, carg);
+#endif
+ printf("Compiled as: cc -o pan %span.c\n", ctd);
+}
+void
+active_procs(void)
+{
+ if (!permuted) {
+ Addproc(4);
+ } else {
+ Addproc(4);
+ }
+}
+#ifdef MA
+/*
+#include <stdio.h>
+#define uchar unsigned char
+*/
+#define ulong unsigned long
+#define ushort unsigned short
+
+#define TWIDTH 256
+#define HASH(y,n) (n)*(((long)y))
+#define INRANGE(e,h) ((h>=e->From && h<=e->To)||(e->s==1 && e->S==h))
+
+extern char *emalloc(unsigned long); /* imported routine */
+extern void dfa_init(ushort); /* 4 exported routines */
+extern int dfa_member(ulong);
+extern int dfa_store(uchar *);
+extern void dfa_stats(void);
+
+typedef struct Edge {
+ uchar From, To; /* max range 0..255 */
+ uchar s, S; /* if s=1, S is singleton */
+ struct Vertex *Dst;
+ struct Edge *Nxt;
+} Edge;
+
+typedef struct Vertex {
+ ulong key, num; /* key for splay tree, nr incoming edges */
+ uchar from[2], to[2]; /* in-node predefined edge info */
+ struct Vertex *dst[2];/* most nodes have 2 or more edges */
+ struct Edge *Succ; /* in case there are more edges */
+ struct Vertex *lnk, *left, *right; /* splay tree plumbing */
+} Vertex;
+
+static Edge *free_edges;
+static Vertex *free_vertices;
+static Vertex **layers; /* one splay tree of nodes per layer */
+static Vertex **path; /* run of word in the DFA */
+static Vertex *R, *F, *NF; /* Root, Final, Not-Final */
+static uchar *word, *lastword;/* string, and last string inserted */
+static int dfa_depth, iv=0, nv=0, pfrst=0, Tally;
+
+static void insert_it(Vertex *, int); /* splay-tree code */
+static void delete_it(Vertex *, int);
+static Vertex *find_it(Vertex *, Vertex *, uchar, int);
+
+static void
+recyc_edges(Edge *e)
+{
+ if (!e) return;
+ recyc_edges(e->Nxt);
+ e->Nxt = free_edges;
+ free_edges = e;
+}
+
+static Edge *
+new_edge(Vertex *dst)
+{ Edge *e;
+
+ if (free_edges)
+ { e = free_edges;
+ free_edges = e->Nxt;
+ e->From = e->To = e->s = e->S = 0;
+ e->Nxt = (Edge *) 0;
+ } else
+ e = (Edge *) emalloc(sizeof(Edge));
+ e->Dst = dst;
+
+ return e;
+}
+
+static void
+recyc_vertex(Vertex *v)
+{
+ recyc_edges(v->Succ);
+ v->Succ = (Edge *) free_vertices;
+ free_vertices = v;
+ nr_states--;
+}
+
+static Vertex *
+new_vertex(void)
+{ Vertex *v;
+
+ if (free_vertices)
+ { v = free_vertices;
+ free_vertices = (Vertex *) v->Succ;
+ v->Succ = (Edge *) 0;
+ v->num = 0;
+ } else
+ v = (Vertex *) emalloc(sizeof(Vertex));
+
+ nr_states++;
+ return v;
+}
+
+static Vertex *
+allDelta(Vertex *v, int n)
+{ Vertex *dst = new_vertex();
+
+ v->from[0] = 0;
+ v->to[0] = 255;
+ v->dst[0] = dst;
+ dst->num = 256;
+ insert_it(v, n);
+ return dst;
+}
+
+static void
+insert_edge(Vertex *v, Edge *e)
+{ /* put new edge first */
+ if (!v->dst[0])
+ { v->dst[0] = e->Dst;
+ v->from[0] = e->From;
+ v->to[0] = e->To;
+ recyc_edges(e);
+ return;
+ }
+ if (!v->dst[1])
+ { v->from[1] = v->from[0]; v->from[0] = e->From;
+ v->to[1] = v->to[0]; v->to[0] = e->To;
+ v->dst[1] = v->dst[0]; v->dst[0] = e->Dst;
+ recyc_edges(e);
+ return;
+ } /* shift */
+ { int f = v->from[1];
+ int t = v->to[1];
+ Vertex *d = v->dst[1];
+ v->from[1] = v->from[0]; v->from[0] = e->From;
+ v->to[1] = v->to[0]; v->to[0] = e->To;
+ v->dst[1] = v->dst[0]; v->dst[0] = e->Dst;
+ e->From = f;
+ e->To = t;
+ e->Dst = d;
+ }
+ e->Nxt = v->Succ;
+ v->Succ = e;
+}
+
+static void
+copyRecursive(Vertex *v, Edge *e)
+{ Edge *f;
+ if (e->Nxt) copyRecursive(v, e->Nxt);
+ f = new_edge(e->Dst);
+ f->From = e->From;
+ f->To = e->To;
+ f->s = e->s;
+ f->S = e->S;
+ f->Nxt = v->Succ;
+ v->Succ = f;
+}
+
+static void
+copyEdges(Vertex *to, Vertex *from)
+{ int i;
+ for (i = 0; i < 2; i++)
+ { to->from[i] = from->from[i];
+ to->to[i] = from->to[i];
+ to->dst[i] = from->dst[i];
+ }
+ if (from->Succ) copyRecursive(to, from->Succ);
+}
+
+static Edge *
+cacheDelta(Vertex *v, int h, int first)
+{ static Edge *ov, tmp; int i;
+
+ if (!first && INRANGE(ov,h))
+ return ov; /* intercepts about 10% */
+ for (i = 0; i < 2; i++)
+ if (v->dst[i] && h >= v->from[i] && h <= v->to[i])
+ { tmp.From = v->from[i];
+ tmp.To = v->to[i];
+ tmp.Dst = v->dst[i];
+ tmp.s = tmp.S = 0;
+ ov = &tmp;
+ return ov;
+ }
+ for (ov = v->Succ; ov; ov = ov->Nxt)
+ if (INRANGE(ov,h)) return ov;
+
+ Uerror("cannot get here, cacheDelta");
+ return (Edge *) 0;
+}
+
+static Vertex *
+Delta(Vertex *v, int h) /* v->delta[h] */
+{ Edge *e;
+
+ if (v->dst[0] && h >= v->from[0] && h <= v->to[0])
+ return v->dst[0]; /* oldest edge */
+ if (v->dst[1] && h >= v->from[1] && h <= v->to[1])
+ return v->dst[1];
+ for (e = v->Succ; e; e = e->Nxt)
+ if (INRANGE(e,h))
+ return e->Dst;
+ Uerror("cannot happen Delta");
+ return (Vertex *) 0;
+}
+
+static void
+numDelta(Vertex *v, int d)
+{ Edge *e;
+ ulong cnt;
+ int i;
+
+ for (i = 0; i < 2; i++)
+ if (v->dst[i])
+ { cnt = v->dst[i]->num + d*(1 + v->to[i] - v->from[i]);
+ if (d == 1 && cnt < v->dst[i]->num) goto bad;
+ v->dst[i]->num = cnt;
+ }
+ for (e = v->Succ; e; e = e->Nxt)
+ { cnt = e->Dst->num + d*(1 + e->To - e->From + e->s);
+ if (d == 1 && cnt < e->Dst->num)
+bad: Uerror("too many incoming edges");
+ e->Dst->num = cnt;
+ }
+}
+
+static void
+setDelta(Vertex *v, int h, Vertex *newdst) /* v->delta[h] = newdst; */
+{ Edge *e, *f = (Edge *) 0, *g;
+ int i;
+
+ /* remove the old entry, if there */
+ for (i = 0; i < 2; i++)
+ if (v->dst[i] && h >= v->from[i] && h <= v->to[i])
+ { if (h == v->from[i])
+ { if (h == v->to[i])
+ { v->dst[i] = (Vertex *) 0;
+ v->from[i] = v->to[i] = 0;
+ } else
+ v->from[i]++;
+ } else if (h == v->to[i])
+ { v->to[i]--;
+ } else
+ { g = new_edge(v->dst[i]);/* same dst */
+ g->From = v->from[i];
+ g->To = h-1; /* left half */
+ v->from[i] = h+1; /* right half */
+ insert_edge(v, g);
+ }
+ goto part2;
+ }
+ for (e = v->Succ; e; f = e, e = e->Nxt)
+ { if (e->s == 1 && e->S == h)
+ { e->s = e->S = 0;
+ goto rem_tst;
+ }
+ if (h >= e->From && h <= e->To)
+ { if (h == e->From)
+ { if (h == e->To)
+ { if (e->s)
+ { e->From = e->To = e->S;
+ e->s = 0;
+ break;
+ } else
+ goto rem_do;
+ } else
+ e->From++;
+ } else if (h == e->To)
+ { e->To--;
+ } else /* split */
+ { g = new_edge(e->Dst); /* same dst */
+ g->From = e->From;
+ g->To = h-1; /* g=left half */
+ e->From = h+1; /* e=right half */
+ g->Nxt = e->Nxt; /* insert g */
+ e->Nxt = g; /* behind e */
+ break; /* done */
+ }
+
+rem_tst: if (e->From > e->To)
+ { if (e->s == 0) {
+rem_do: if (f)
+ f->Nxt = e->Nxt;
+ else
+ v->Succ = e->Nxt;
+ e->Nxt = (Edge *) 0;
+ recyc_edges(e);
+ } else
+ { e->From = e->To = e->S;
+ e->s = 0;
+ } }
+ break;
+ } }
+part2:
+ /* check if newdst is already there */
+ for (i = 0; i < 2; i++)
+ if (v->dst[i] == newdst)
+ { if (h+1 == (int) v->from[i])
+ { v->from[i] = h;
+ return;
+ }
+ if (h == (int) v->to[i]+1)
+ { v->to[i] = h;
+ return;
+ } }
+ for (e = v->Succ; e; e = e->Nxt)
+ { if (e->Dst == newdst)
+ { if (h+1 == (int) e->From)
+ { e->From = h;
+ if (e->s == 1 && e->S+1 == e->From)
+ { e->From = e->S;
+ e->s = e->S = 0;
+ }
+ return;
+ }
+ if (h == (int) e->To+1)
+ { e->To = h;
+ if (e->s == 1 && e->S == e->To+1)
+ { e->To = e->S;
+ e->s = e->S = 0;
+ }
+ return;
+ }
+ if (e->s == 0)
+ { e->s = 1;
+ e->S = h;
+ return;
+ } } }
+ /* add as a new edge */
+ e = new_edge(newdst);
+ e->From = e->To = h;
+ insert_edge(v, e);
+}
+
+static ulong
+cheap_key(Vertex *v)
+{ ulong vk2 = 0;
+
+ if (v->dst[0])
+ { vk2 = (ulong) v->dst[0];
+ if ((ulong) v->dst[1] > vk2)
+ vk2 = (ulong) v->dst[1];
+ } else if (v->dst[1])
+ vk2 = (ulong) v->dst[1];
+ if (v->Succ)
+ { Edge *e;
+ for (e = v->Succ; e; e = e->Nxt)
+ if ((ulong) e->Dst > vk2)
+ vk2 = (ulong) e->Dst;
+ }
+ Tally = (vk2>>2)&(TWIDTH-1);
+ return v->key;
+}
+
+static ulong
+mk_key(Vertex *v) /* not sensitive to order */
+{ ulong m = 0, vk2 = 0;
+ Edge *e;
+
+ if (v->dst[0])
+ { m += HASH(v->dst[0], v->to[0] - v->from[0] + 1);
+ vk2 = (ulong) v->dst[0];
+ }
+ if (v->dst[1])
+ { m += HASH(v->dst[1], v->to[1] - v->from[1] + 1);
+ if ((ulong) v->dst[1] > vk2) vk2 = (ulong) v->dst[1];
+ }
+ for (e = v->Succ; e; e = e->Nxt)
+ { m += HASH(e->Dst, e->To - e->From + 1 + e->s);
+ if ((ulong) e->Dst > vk2) vk2 = (ulong) e->Dst;
+ }
+ Tally = (vk2>>2)&(TWIDTH-1);
+ return m;
+}
+
+static ulong
+mk_special(int sigma, Vertex *n, Vertex *v)
+{ ulong m = 0, vk2 = 0;
+ Edge *f;
+ int i;
+
+ for (i = 0; i < 2; i++)
+ if (v->dst[i])
+ { if (sigma >= v->from[i] && sigma <= v->to[i])
+ { m += HASH(v->dst[i], v->to[i]-v->from[i]);
+ if ((ulong) v->dst[i] > vk2
+ && v->to[i] > v->from[i])
+ vk2 = (ulong) v->dst[i];
+ } else
+ { m += HASH(v->dst[i], v->to[i]-v->from[i]+1);
+ if ((ulong) v->dst[i] > vk2)
+ vk2 = (ulong) v->dst[i];
+ } }
+ for (f = v->Succ; f; f = f->Nxt)
+ { if (sigma >= f->From && sigma <= f->To)
+ { m += HASH(f->Dst, f->To - f->From + f->s);
+ if ((ulong) f->Dst > vk2
+ && f->To - f->From + f->s > 0)
+ vk2 = (ulong) f->Dst;
+ } else if (f->s == 1 && sigma == f->S)
+ { m += HASH(f->Dst, f->To - f->From + 1);
+ if ((ulong) f->Dst > vk2) vk2 = (ulong) f->Dst;
+ } else
+ { m += HASH(f->Dst, f->To - f->From + 1 + f->s);
+ if ((ulong) f->Dst > vk2) vk2 = (ulong) f->Dst;
+ } }
+
+ if ((ulong) n > vk2) vk2 = (ulong) n;
+ Tally = (vk2>>2)&(TWIDTH-1);
+ m += HASH(n, 1);
+ return m;
+}
+
+void
+dfa_init(ushort nr_layers)
+{ int i; Vertex *r, *t;
+
+ dfa_depth = nr_layers; /* one byte per layer */
+ path = (Vertex **) emalloc((dfa_depth+1)*sizeof(Vertex *));
+ layers = (Vertex **) emalloc(TWIDTH*(dfa_depth+1)*sizeof(Vertex *));
+ lastword = (uchar *) emalloc((dfa_depth+1)*sizeof(uchar));
+ lastword[dfa_depth] = lastword[0] = 255;
+ path[0] = R = new_vertex(); F = new_vertex();
+
+ for (i = 1, r = R; i < dfa_depth; i++, r = t)
+ t = allDelta(r, i-1);
+ NF = allDelta(r, i-1);
+}
+
+#if 0
+static void complement_dfa(void) { Vertex *tmp = F; F = NF; NF = tmp; }
+#endif
+
+double
+tree_stats(Vertex *t)
+{ Edge *e; double cnt=0.0;
+ if (!t) return 0;
+ if (!t->key) return 0;
+ t->key = 0; /* precaution */
+ if (t->dst[0]) cnt++;
+ if (t->dst[1]) cnt++;
+ for (e = t->Succ; e; e = e->Nxt)
+ cnt++;
+ cnt += tree_stats(t->lnk);
+ cnt += tree_stats(t->left);
+ cnt += tree_stats(t->right);
+ return cnt;
+}
+
+void
+dfa_stats(void)
+{ int i, j; double cnt = 0.0;
+ for (j = 0; j < TWIDTH; j++)
+ for (i = 0; i < dfa_depth+1; i++)
+ cnt += tree_stats(layers[i*TWIDTH+j]);
+ printf("Minimized Automaton: %6d nodes and %6g edges\n",
+ nr_states, cnt);
+}
+
+int
+dfa_member(ulong n)
+{ Vertex **p, **q;
+ uchar *w = &word[n];
+ int i;
+
+ p = &path[n]; q = (p+1);
+ for (i = n; i < dfa_depth; i++)
+ *q++ = Delta(*p++, *w++);
+ return (*p == F);
+}
+
+int
+dfa_store(uchar *sv)
+{ Vertex **p, **q, *s, *y, *old, *new = F;
+ uchar *w, *u = lastword;
+ int i, j, k;
+
+ w = word = sv;
+ while (*w++ == *u++) /* find first byte that differs */
+ ;
+ pfrst = (int) (u - lastword) - 1;
+ memcpy(&lastword[pfrst], &sv[pfrst], dfa_depth-pfrst);
+ if (pfrst > iv) pfrst = iv;
+ if (pfrst > nv) pfrst = nv;
+/* phase1: */
+ p = &path[pfrst]; q = (p+1); w = &word[pfrst];
+ for (i = pfrst; i < dfa_depth; i++)
+ *q++ = Delta(*p++, *w++); /* (*p)->delta[*w++]; */
+
+ if (*p == F) return 1; /* it's already there */
+/* phase2: */
+ iv = dfa_depth;
+ do { iv--;
+ old = new;
+ new = find_it(path[iv], old, word[iv], iv);
+ } while (new && iv > 0);
+
+/* phase3: */
+ nv = k = 0; s = path[0];
+ for (j = 1; j <= iv; ++j)
+ if (path[j]->num > 1)
+ { y = new_vertex();
+ copyEdges(y, path[j]);
+ insert_it(y, j);
+ numDelta(y, 1);
+ delete_it(s, j-1);
+ setDelta(s, word[j-1], y);
+ insert_it(s, j-1);
+ y->num = 1; /* initial value 1 */
+ s = y;
+ path[j]->num--; /* only 1 moved from j to y */
+ k = 1;
+ } else
+ { s = path[j];
+ if (!k) nv = j;
+ }
+ y = Delta(s, word[iv]);
+ y->num--;
+ delete_it(s, iv);
+ setDelta(s, word[iv], old);
+ insert_it(s, iv);
+ old->num++;
+
+ for (j = iv+1; j < dfa_depth; j++)
+ if (path[j]->num == 0)
+ { numDelta(path[j], -1);
+ delete_it(path[j], j);
+ recyc_vertex(path[j]);
+ } else
+ break;
+ return 0;
+}
+
+static Vertex *
+splay(ulong i, Vertex *t)
+{ Vertex N, *l, *r, *y;
+
+ if (!t) return t;
+ N.left = N.right = (Vertex *) 0;
+ l = r = &N;
+ for (;;)
+ { if (i < t->key)
+ { if (!t->left) break;
+ if (i < t->left->key)
+ { y = t->left;
+ t->left = y->right;
+ y->right = t;
+ t = y;
+ if (!t->left) break;
+ }
+ r->left = t;
+ r = t;
+ t = t->left;
+ } else if (i > t->key)
+ { if (!t->right) break;
+ if (i > t->right->key)
+ { y = t->right;
+ t->right = y->left;
+ y->left = t;
+ t = y;
+ if (!t->right) break;
+ }
+ l->right = t;
+ l = t;
+ t = t->right;
+ } else
+ break;
+ }
+ l->right = t->left;
+ r->left = t->right;
+ t->left = N.right;
+ t->right = N.left;
+ return t;
+}
+
+static void
+insert_it(Vertex *v, int L)
+{ Vertex *new, *t;
+ ulong i; int nr;
+
+ i = mk_key(v);
+ nr = ((L*TWIDTH)+Tally);
+ t = layers[nr];
+
+ v->key = i;
+ if (!t)
+ { layers[nr] = v;
+ return;
+ }
+ t = splay(i, t);
+ if (i < t->key)
+ { new = v;
+ new->left = t->left;
+ new->right = t;
+ t->left = (Vertex *) 0;
+ } else if (i > t->key)
+ { new = v;
+ new->right = t->right;
+ new->left = t;
+ t->right = (Vertex *) 0;
+ } else /* it's already there */
+ { v->lnk = t->lnk; /* put in linked list off v */
+ t->lnk = v;
+ new = t;
+ }
+ layers[nr] = new;
+}
+
+static int
+checkit(Vertex *h, Vertex *v, Vertex *n, uchar sigma)
+{ Edge *g, *f;
+ int i, k, j = 1;
+
+ for (k = 0; k < 2; k++)
+ if (h->dst[k])
+ { if (sigma >= h->from[k] && sigma <= h->to[k])
+ { if (h->dst[k] != n) goto no_match;
+ }
+ for (i = h->from[k]; i <= h->to[k]; i++)
+ { if (i == sigma) continue;
+ g = cacheDelta(v, i, j); j = 0;
+ if (h->dst[k] != g->Dst)
+ goto no_match;
+ if (g->s == 0 || g->S != i)
+ i = g->To;
+ } }
+ for (f = h->Succ; f; f = f->Nxt)
+ { if (INRANGE(f,sigma))
+ { if (f->Dst != n) goto no_match;
+ }
+ for (i = f->From; i <= f->To; i++)
+ { if (i == sigma) continue;
+ g = cacheDelta(v, i, j); j = 0;
+ if (f->Dst != g->Dst)
+ goto no_match;
+ if (g->s == 1 && i == g->S)
+ continue;
+ i = g->To;
+ }
+ if (f->s && f->S != sigma)
+ { g = cacheDelta(v, f->S, 1);
+ if (f->Dst != g->Dst)
+ goto no_match;
+ }
+ }
+ if (h->Succ || h->dst[0] || h->dst[1]) return 1;
+no_match:
+ return 0;
+}
+
+static Vertex *
+find_it(Vertex *v, Vertex *n, uchar sigma, int L)
+{ Vertex *z, *t;
+ ulong i; int nr;
+
+ i = mk_special(sigma,n,v);
+ nr = ((L*TWIDTH)+Tally);
+ t = layers[nr];
+
+ if (!t) return (Vertex *) 0;
+ layers[nr] = t = splay(i, t);
+ if (i == t->key)
+ for (z = t; z; z = z->lnk)
+ if (checkit(z, v, n, sigma))
+ return z;
+
+ return (Vertex *) 0;
+}
+
+static void
+delete_it(Vertex *v, int L)
+{ Vertex *x, *t;
+ ulong i; int nr;
+
+ i = cheap_key(v);
+ nr = ((L*TWIDTH)+Tally);
+ t = layers[nr];
+ if (!t) return;
+
+ t = splay(i, t);
+ if (i == t->key)
+ { Vertex *z, *y = (Vertex *) 0;
+ for (z = t; z && z != v; y = z, z = z->lnk)
+ ;
+ if (z != v) goto bad;
+ if (y)
+ { y->lnk = z->lnk;
+ z->lnk = (Vertex *) 0;
+ layers[nr] = t;
+ return;
+ } else if (z->lnk) /* z == t == v */
+ { y = z->lnk;
+ y->left = t->left;
+ y->right = t->right;
+ t->left = t->right = t->lnk = (Vertex *) 0;
+ layers[nr] = y;
+ return;
+ }
+ /* delete the node itself */
+ if (!t->left)
+ { x = t->right;
+ } else
+ { x = splay(i, t->left);
+ x->right = t->right;
+ }
+ t->left = t->right = t->lnk = (Vertex *) 0;
+ layers[nr] = x;
+ return;
+ }
+bad: Uerror("cannot happen delete");
+}
+#endif
+#if defined(MA) && (defined(W_XPT) || defined(R_XPT))
+static Vertex **temptree;
+static char wbuf[4096];
+static int WCNT = 4096, wcnt=0;
+static uchar stacker[MA+1];
+static ulong stackcnt = 0;
+extern double nstates, nlinks, truncs, truncs2;
+
+static void
+xwrite(int fd, char *b, int n)
+{
+ if (wcnt+n >= 4096)
+ { write(fd, wbuf, wcnt);
+ wcnt = 0;
+ }
+ memcpy(&wbuf[wcnt], b, n);
+ wcnt += n;
+}
+
+static void
+wclose(fd)
+{
+ if (wcnt > 0)
+ write(fd, wbuf, wcnt);
+ wcnt = 0;
+ close(fd);
+}
+
+static void
+w_vertex(int fd, Vertex *v)
+{ char t[3]; int i; Edge *e;
+
+ xwrite(fd, (char *) &v, sizeof(Vertex *));
+ t[0] = 0;
+ for (i = 0; i < 2; i++)
+ if (v->dst[i])
+ { t[1] = v->from[i], t[2] = v->to[i];
+ xwrite(fd, t, 3);
+ xwrite(fd, (char *) &(v->dst[i]), sizeof(Vertex *));
+ }
+ for (e = v->Succ; e; e = e->Nxt)
+ { t[1] = e->From, t[2] = e->To;
+ xwrite(fd, t, 3);
+ xwrite(fd, (char *) &(e->Dst), sizeof(Vertex *));
+
+ if (e->s)
+ { t[1] = t[2] = e->S;
+ xwrite(fd, t, 3);
+ xwrite(fd, (char *) &(e->Dst), sizeof(Vertex *));
+ } }
+}
+
+static void
+w_layer(int fd, Vertex *v)
+{ uchar c=1;
+
+ if (!v) return;
+ xwrite(fd, (char *) &c, 1);
+ w_vertex(fd, v);
+ w_layer(fd, v->lnk);
+ w_layer(fd, v->left);
+ w_layer(fd, v->right);
+}
+
+void
+w_xpoint(void)
+{ int fd; char nm[64];
+ int i, j; uchar c;
+ static uchar xwarned = 0;
+
+ sprintf(nm, "%s.xpt", PanSource);
+ if ((fd = creat(nm, 0666)) <= 0)
+ if (!xwarned)
+ { xwarned = 1;
+ printf("cannot creat checkpoint file\n");
+ return;
+ }
+ xwrite(fd, (char *) &nstates, sizeof(double));
+ xwrite(fd, (char *) &truncs, sizeof(double));
+ xwrite(fd, (char *) &truncs2, sizeof(double));
+ xwrite(fd, (char *) &nlinks, sizeof(double));
+ xwrite(fd, (char *) &dfa_depth, sizeof(int));
+ xwrite(fd, (char *) &R, sizeof(Vertex *));
+ xwrite(fd, (char *) &F, sizeof(Vertex *));
+ xwrite(fd, (char *) &NF, sizeof(Vertex *));
+
+ for (j = 0; j < TWIDTH; j++)
+ for (i = 0; i < dfa_depth+1; i++)
+ { w_layer(fd, layers[i*TWIDTH+j]);
+ c = 2; xwrite(fd, (char *) &c, 1);
+ }
+ wclose(fd);
+}
+
+static void
+xread(int fd, char *b, int n)
+{ int m = wcnt; int delta = 0;
+ if (m < n)
+ { if (m > 0) memcpy(b, &wbuf[WCNT-m], m);
+ delta = m;
+ WCNT = wcnt = read(fd, wbuf, 4096);
+ if (wcnt < n-m)
+ Uerror("xread failed -- insufficient data");
+ n -= m;
+ }
+ memcpy(&b[delta], &wbuf[WCNT-wcnt], n);
+ wcnt -= n;
+}
+
+static void
+x_cleanup(Vertex *c)
+{ Edge *e; /* remove the tree and edges from c */
+ if (!c) return;
+ for (e = c->Succ; e; e = e->Nxt)
+ x_cleanup(e->Dst);
+ recyc_vertex(c);
+}
+
+static void
+x_remove(void)
+{ Vertex *tmp; int i, s;
+ int r, j;
+ /* double-check: */
+ stacker[dfa_depth-1] = 0; r = dfa_store(stacker);
+ stacker[dfa_depth-1] = 4; j = dfa_member(dfa_depth-1);
+ if (r != 1 || j != 0)
+ { printf("%d: ", stackcnt);
+ for (i = 0; i < dfa_depth; i++)
+ printf("%d,", stacker[i]);
+ printf(" -- not a stackstate <o:%d,4:%d>\n", r, j);
+ return;
+ }
+ stacker[dfa_depth-1] = 1;
+ s = dfa_member(dfa_depth-1);
+
+ { tmp = F; F = NF; NF = tmp; } /* complement */
+ if (s) dfa_store(stacker);
+ stacker[dfa_depth-1] = 0;
+ dfa_store(stacker);
+ stackcnt++;
+ { tmp = F; F = NF; NF = tmp; }
+}
+
+static void
+x_rm_stack(Vertex *t, int k)
+{ int j; Edge *e;
+
+ if (k == 0)
+ { x_remove();
+ return;
+ }
+ if (t)
+ for (e = t->Succ; e; e = e->Nxt)
+ { for (j = e->From; j <= (int) e->To; j++)
+ { stacker[k] = (uchar) j;
+ x_rm_stack(e->Dst, k-1);
+ }
+ if (e->s)
+ { stacker[k] = e->S;
+ x_rm_stack(e->Dst, k-1);
+ } }
+}
+
+static Vertex *
+insert_withkey(Vertex *v, int L)
+{ Vertex *new, *t = temptree[L];
+
+ if (!t) { temptree[L] = v; return v; }
+ t = splay(v->key, t);
+ if (v->key < t->key)
+ { new = v;
+ new->left = t->left;
+ new->right = t;
+ t->left = (Vertex *) 0;
+ } else if (v->key > t->key)
+ { new = v;
+ new->right = t->right;
+ new->left = t;
+ t->right = (Vertex *) 0;
+ } else
+ { if (t != R && t != F && t != NF)
+ Uerror("double insert, bad checkpoint data");
+ else
+ { recyc_vertex(v);
+ new = t;
+ } }
+ temptree[L] = new;
+
+ return new;
+}
+
+static Vertex *
+find_withkey(Vertex *v, int L)
+{ Vertex *t = temptree[L];
+ if (t)
+ { temptree[L] = t = splay((ulong) v, t);
+ if (t->key == (ulong) v)
+ return t;
+ }
+ Uerror("not found error, bad checkpoint data");
+ return (Vertex *) 0;
+}
+
+void
+r_layer(int fd, int n)
+{ Vertex *v;
+ Edge *e;
+ char c, t[2];
+
+ for (;;)
+ { xread(fd, &c, 1);
+ if (c == 2) break;
+ if (c == 1)
+ { v = new_vertex();
+ xread(fd, (char *) &(v->key), sizeof(Vertex *));
+ v = insert_withkey(v, n);
+ } else /* c == 0 */
+ { e = new_edge((Vertex *) 0);
+ xread(fd, t, 2);
+ e->From = t[0];
+ e->To = t[1];
+ xread(fd, (char *) &(e->Dst), sizeof(Vertex *));
+ insert_edge(v, e);
+ } }
+}
+
+static void
+v_fix(Vertex *t, int nr)
+{ int i; Edge *e;
+
+ if (!t) return;
+
+ for (i = 0; i < 2; i++)
+ if (t->dst[i])
+ t->dst[i] = find_withkey(t->dst[i], nr);
+
+ for (e = t->Succ; e; e = e->Nxt)
+ e->Dst = find_withkey(e->Dst, nr);
+
+ v_fix(t->left, nr);
+ v_fix(t->right, nr);
+}
+
+static void
+v_insert(Vertex *t, int nr)
+{ Edge *e; int i;
+
+ if (!t) return;
+ v_insert(t->left, nr);
+ v_insert(t->right, nr);
+
+ /* remove only leafs from temptree */
+ t->left = t->right = t->lnk = (Vertex *) 0;
+ insert_it(t, nr); /* into layers */
+ for (i = 0; i < 2; i++)
+ if (t->dst[i])
+ t->dst[i]->num += (t->to[i] - t->from[i] + 1);
+ for (e = t->Succ; e; e = e->Nxt)
+ e->Dst->num += (e->To - e->From + 1 + e->s);
+}
+
+static void
+x_fixup(void)
+{ int i;
+
+ for (i = 0; i < dfa_depth; i++)
+ v_fix(temptree[i], (i+1));
+
+ for (i = dfa_depth; i >= 0; i--)
+ v_insert(temptree[i], i);
+}
+
+static Vertex *
+x_tail(Vertex *t, ulong want)
+{ int i, yes, no; Edge *e; Vertex *v = (Vertex *) 0;
+
+ if (!t) return v;
+
+ yes = no = 0;
+ for (i = 0; i < 2; i++)
+ if ((ulong) t->dst[i] == want)
+ { /* was t->from[i] <= 0 && t->to[i] >= 0 */
+ /* but from and to are uchar */
+ if (t->from[i] == 0)
+ yes = 1;
+ else
+ if (t->from[i] <= 4 && t->to[i] >= 4)
+ no = 1;
+ }
+
+ for (e = t->Succ; e; e = e->Nxt)
+ if ((ulong) e->Dst == want)
+ { /* was INRANGE(e,0) but From and To are uchar */
+ if ((e->From == 0) || (e->s==1 && e->S==0))
+ yes = 1;
+ else if (INRANGE(e, 4))
+ no = 1;
+ }
+ if (yes && !no) return t;
+ v = x_tail(t->left, want); if (v) return v;
+ v = x_tail(t->right, want); if (v) return v;
+ return (Vertex *) 0;
+}
+
+static void
+x_anytail(Vertex *t, Vertex *c, int nr)
+{ int i; Edge *e, *f; Vertex *v;
+
+ if (!t) return;
+
+ for (i = 0; i < 2; i++)
+ if ((ulong) t->dst[i] == c->key)
+ { v = new_vertex(); v->key = t->key;
+ f = new_edge(v);
+ f->From = t->from[i];
+ f->To = t->to[i];
+ f->Nxt = c->Succ;
+ c->Succ = f;
+ if (nr > 0)
+ x_anytail(temptree[nr-1], v, nr-1);
+ }
+
+ for (e = t->Succ; e; e = e->Nxt)
+ if ((ulong) e->Dst == c->key)
+ { v = new_vertex(); v->key = t->key;
+ f = new_edge(v);
+ f->From = e->From;
+ f->To = e->To;
+ f->s = e->s;
+ f->S = e->S;
+ f->Nxt = c->Succ;
+ c->Succ = f;
+ x_anytail(temptree[nr-1], v, nr-1);
+ }
+
+ x_anytail(t->left, c, nr);
+ x_anytail(t->right, c, nr);
+}
+
+static Vertex *
+x_cpy_rev(void)
+{ Vertex *c, *v; /* find 0 and !4 predecessor of F */
+
+ v = x_tail(temptree[dfa_depth-1], F->key);
+ if (!v) return (Vertex *) 0;
+
+ c = new_vertex(); c->key = v->key;
+
+ /* every node on dfa_depth-2 that has v->key as succ */
+ /* make copy and let c point to these (reversing ptrs) */
+
+ x_anytail(temptree[dfa_depth-2], c, dfa_depth-2);
+
+ return c;
+}
+
+void
+r_xpoint(void)
+{ int fd; char nm[64]; Vertex *d;
+ int i, j;
+
+ wcnt = 0;
+ sprintf(nm, "%s.xpt", PanSource);
+ if ((fd = open(nm, 0)) < 0) /* O_RDONLY */
+ Uerror("cannot open checkpoint file");
+
+ xread(fd, (char *) &nstates, sizeof(double));
+ xread(fd, (char *) &truncs, sizeof(double));
+ xread(fd, (char *) &truncs2, sizeof(double));
+ xread(fd, (char *) &nlinks, sizeof(double));
+ xread(fd, (char *) &dfa_depth, sizeof(int));
+
+ if (dfa_depth != MA+a_cycles)
+ Uerror("bad dfa_depth in checkpoint file");
+
+ path = (Vertex **) emalloc((dfa_depth+1)*sizeof(Vertex *));
+ layers = (Vertex **) emalloc(TWIDTH*(dfa_depth+1)*sizeof(Vertex *));
+ temptree = (Vertex **) emalloc((dfa_depth+2)*sizeof(Vertex *));
+ lastword = (uchar *) emalloc((dfa_depth+1)*sizeof(uchar));
+ lastword[dfa_depth] = lastword[0] = 255;
+
+ path[0] = R = new_vertex();
+ xread(fd, (char *) &R->key, sizeof(Vertex *));
+ R = insert_withkey(R, 0);
+
+ F = new_vertex();
+ xread(fd, (char *) &F->key, sizeof(Vertex *));
+ F = insert_withkey(F, dfa_depth);
+
+ NF = new_vertex();
+ xread(fd, (char *) &NF->key, sizeof(Vertex *));
+ NF = insert_withkey(NF, dfa_depth);
+
+ for (j = 0; j < TWIDTH; j++)
+ for (i = 0; i < dfa_depth+1; i++)
+ r_layer(fd, i);
+
+ if (wcnt != 0) Uerror("bad count in checkpoint file");
+
+ d = x_cpy_rev();
+ x_fixup();
+ stacker[dfa_depth-1] = 0;
+ x_rm_stack(d, dfa_depth-2);
+ x_cleanup(d);
+ close(fd);
+
+ printf("pan: removed %d stackstates\n", stackcnt);
+ nstates -= (double) stackcnt;
+}
+#endif
+#ifdef VERI
+void
+check_claim(int st)
+{
+ if (st == endclaim)
+ uerror("claim violated!");
+ if (stopstate[VERI][st])
+ uerror("end state in claim reached");
+}
+#endif
+void
+c_globals(void)
+{ /* int i; */
+ printf("global vars:\n");
+ printf(" byte write_off: %d\n", now.write_off);
+ { int l_in;
+ for (l_in = 0; l_in < 2; l_in++)
+ {
+ printf(" byte commit_count[%d]: %d\n", l_in, now.commit_count[l_in]);
+ }
+ }
+ printf(" byte _commit_sum: %d\n", now._commit_sum);
+ printf(" byte read_off: %d\n", now.read_off);
+ printf(" byte events_lost: %d\n", now.events_lost);
+ printf(" byte refcount: %d\n", now.refcount);
+ { int l_in;
+ for (l_in = 0; l_in < 4; l_in++)
+ {
+ printf(" bit buffer_use[%d]: %d\n", l_in, now.buffer_use[l_in]);
+ }
+ }
+}
+void
+c_locals(int pid, int tp)
+{ /* int i; */
+ switch(tp) {
+ case 5:
+ /* none */
+ break;
+ case 4:
+ printf("local vars proc %d (:init:):\n", pid);
+ printf(" byte i: %d\n", ((P4 *)pptr(pid))->i);
+ printf(" byte j: %d\n", ((P4 *)pptr(pid))->j);
+ printf(" byte sum: %d\n", ((P4 *)pptr(pid))->sum);
+ printf(" byte commit_sum: %d\n", ((P4 *)pptr(pid))->commit_sum);
+ break;
+ case 3:
+ /* none */
+ break;
+ case 2:
+ printf("local vars proc %d (reader):\n", pid);
+ printf(" byte i: %d\n", ((P2 *)pptr(pid))->i);
+ printf(" byte j: %d\n", ((P2 *)pptr(pid))->j);
+ break;
+ case 1:
+ printf("local vars proc %d (tracer):\n", pid);
+ printf(" byte size: %d\n", ((P1 *)pptr(pid))->size);
+ printf(" byte prev_off: %d\n", ((P1 *)pptr(pid))->prev_off);
+ printf(" byte new_off: %d\n", ((P1 *)pptr(pid))->new_off);
+ printf(" byte tmp_commit: %d\n", ((P1 *)pptr(pid))->tmp_commit);
+ printf(" byte i: %d\n", ((P1 *)pptr(pid))->i);
+ printf(" byte j: %d\n", ((P1 *)pptr(pid))->j);
+ break;
+ case 0:
+ printf("local vars proc %d (switcher):\n", pid);
+ printf(" byte prev_off: %d\n", ((P0 *)pptr(pid))->prev_off);
+ printf(" byte new_off: %d\n", ((P0 *)pptr(pid))->new_off);
+ printf(" byte tmp_commit: %d\n", ((P0 *)pptr(pid))->tmp_commit);
+ printf(" byte size: %d\n", ((P0 *)pptr(pid))->size);
+ break;
+ }
+}
+void
+printm(int x)
+{
+ switch (x) {
+ default: Printf("%d", x);
+ }
+}
+void
+c_chandump(int unused) { unused++; /* avoid complaints */ }
--- /dev/null
+#define SpinVersion "Spin Version 5.1.6 -- 9 May 2008"
+#define PanSource "model.spin"
+
+#ifdef WIN64
+#define ONE_L ((unsigned long) 1)
+#define long long long
+#else
+#define ONE_L (1L)
+#endif
+char *TrailFile = PanSource; /* default */
+char *trailfilename;
+#if defined(BFS)
+#ifndef SAFETY
+#define SAFETY
+#endif
+#ifndef XUSAFE
+#define XUSAFE
+#endif
+#endif
+#ifndef uchar
+#define uchar unsigned char
+#endif
+#ifndef uint
+#define uint unsigned int
+#endif
+#define DELTA 500
+#ifdef MA
+ #if NCORE>1 && !defined(SEP_STATE)
+ #define SEP_STATE
+ #endif
+#if MA==1
+#undef MA
+#define MA 100
+#endif
+#endif
+#ifdef W_XPT
+#if W_XPT==1
+#undef W_XPT
+#define W_XPT 1000000
+#endif
+#endif
+#ifndef NFAIR
+#define NFAIR 2 /* must be >= 2 */
+#endif
+#define HAS_CODE
+#define MERGED 1
+#ifdef NP /* includes np_ demon */
+#define HAS_NP 2
+#define VERI 6
+#define endclaim 3 /* none */
+#endif
+#if !defined(NOCLAIM) && !defined NP
+#define VERI 5
+#define endclaim endstate5
+#endif
+typedef struct S_F_MAP {
+ char *fnm; int from; int upto;
+} S_F_MAP;
+
+#define nstates5 15 /* :never: */
+#define nstates_claim nstates5
+#define endstate5 14
+short src_ln5 [] = {
+ 0, 301, 301, 302, 302, 300, 304, 306,
+ 306, 307, 307, 305, 309, 310, 311, 0, };
+S_F_MAP src_file5 [] = {
+ { "-", 0, 0 },
+ { "pan.___", 1, 14 },
+ { "-", 15, 16 }
+};
+#define src_claim src_ln5
+uchar reached5 [] = {
+ 0, 1, 1, 1, 1, 0, 1, 1,
+ 1, 1, 1, 0, 1, 1, 0, 0, };
+uchar *loopstate5;
+#define reached_claim reached5
+
+#define nstates4 44 /* :init: */
+#define endstate4 43
+short src_ln4 [] = {
+ 0, 252, 254, 255, 256, 257, 257, 253,
+ 260, 253, 260, 262, 264, 265, 266, 267,
+ 267, 263, 269, 263, 269, 270, 271, 273,
+ 274, 275, 276, 277, 277, 272, 279, 272,
+ 279, 281, 282, 283, 284, 285, 285, 280,
+ 287, 280, 251, 288, 0, };
+S_F_MAP src_file4 [] = {
+ { "-", 0, 0 },
+ { "pan.___", 1, 43 },
+ { "-", 44, 45 }
+};
+uchar reached4 [] = {
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 1, 1, 0, 0, 1, 0, 0, 1,
+ 1, 0, 1, 1, 0, 0, 0, 1,
+ 0, 0, 0, 1, 1, 0, 1, 1,
+ 0, 1, 0, 0, 0, 1, 1, 0,
+ 1, 1, 0, 0, 0, };
+uchar *loopstate4;
+
+#define nstates3 10 /* cleaner */
+#define endstate3 9
+short src_ln3 [] = {
+ 0, 237, 238, 239, 240, 236, 242, 236,
+ 235, 243, 0, };
+S_F_MAP src_file3 [] = {
+ { "-", 0, 0 },
+ { "pan.___", 1, 9 },
+ { "-", 10, 11 }
+};
+uchar reached3 [] = {
+ 0, 1, 0, 0, 1, 0, 1, 1,
+ 0, 0, 0, };
+uchar *loopstate3;
+
+#define nstates2 30 /* reader */
+#define endstate2 29
+short src_ln2 [] = {
+ 0, 200, 202, 204, 205, 206, 207, 208,
+ 208, 203, 210, 203, 201, 216, 218, 219,
+ 220, 221, 221, 217, 223, 217, 223, 215,
+ 225, 225, 195, 227, 195, 227, 0, };
+S_F_MAP src_file2 [] = {
+ { "-", 0, 0 },
+ { "pan.___", 1, 29 },
+ { "-", 30, 31 }
+};
+uchar reached2 [] = {
+ 0, 1, 1, 1, 0, 0, 0, 1,
+ 1, 0, 1, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 1, 0, 0,
+ 1, 1, 0, 1, 1, 0, 0, };
+uchar *loopstate2;
+
+#define nstates1 52 /* tracer */
+#define endstate1 51
+short src_ln1 [] = {
+ 0, 123, 124, 122, 128, 129, 130, 130,
+ 127, 132, 126, 135, 135, 136, 136, 134,
+ 138, 138, 140, 141, 142, 143, 144, 144,
+ 139, 146, 139, 133, 152, 154, 155, 156,
+ 157, 157, 153, 159, 153, 159, 161, 164,
+ 167, 168, 169, 170, 165, 172, 151, 174,
+ 176, 178, 173, 180, 0, };
+S_F_MAP src_file1 [] = {
+ { "-", 0, 0 },
+ { "pan.___", 1, 51 },
+ { "-", 52, 53 }
+};
+uchar reached1 [] = {
+ 0, 1, 0, 0, 1, 1, 1, 0,
+ 1, 1, 0, 1, 1, 1, 0, 1,
+ 1, 0, 1, 0, 0, 0, 1, 1,
+ 0, 1, 1, 0, 1, 1, 0, 0,
+ 1, 1, 0, 1, 1, 0, 0, 0,
+ 1, 0, 1, 0, 0, 1, 0, 1,
+ 0, 0, 0, 0, 0, };
+uchar *loopstate1;
+
+#define nstates0 32 /* switcher */
+#define endstate0 31
+short src_ln0 [] = {
+ 0, 72, 73, 74, 77, 78, 79, 80,
+ 80, 75, 82, 71, 85, 85, 86, 86,
+ 84, 88, 83, 91, 93, 96, 99, 100,
+ 101, 102, 97, 104, 104, 90, 107, 108,
+ 0, };
+S_F_MAP src_file0 [] = {
+ { "-", 0, 0 },
+ { "pan.___", 1, 31 },
+ { "-", 32, 33 }
+};
+uchar reached0 [] = {
+ 0, 1, 0, 0, 1, 0, 1, 1,
+ 0, 0, 1, 0, 1, 1, 1, 0,
+ 1, 1, 0, 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0, 0, 1, 0,
+ 0, };
+uchar *loopstate0;
+struct {
+ int tp; short *src;
+} src_all[] = {
+ { 5, &src_ln5[0] },
+ { 4, &src_ln4[0] },
+ { 3, &src_ln3[0] },
+ { 2, &src_ln2[0] },
+ { 1, &src_ln1[0] },
+ { 0, &src_ln0[0] },
+ { 0, (short *) 0 }
+};
+short *frm_st0;
+struct {
+ char *c; char *t;
+} code_lookup[] = {
+ { (char *) 0, "" }
+};
+#define _T5 64
+#define _T2 65
+#define T_ID unsigned char
+#define SYNC 0
+#define ASYNC 0
+
+#ifndef NCORE
+ #ifdef DUAL_CORE
+ #define NCORE 2
+ #elif QUAD_CORE
+ #define NCORE 4
+ #else
+ #define NCORE 1
+ #endif
+#endif
+char *procname[] = {
+ "switcher",
+ "tracer",
+ "reader",
+ "cleaner",
+ ":init:",
+ ":never:",
+ ":np_:",
+};
+
+typedef struct P5 { /* :never: */
+ unsigned _pid : 8; /* 0..255 */
+ unsigned _t : 4; /* proctype */
+ unsigned _p : 7; /* state */
+} P5;
+#define Air5 (sizeof(P5) - 3)
+#define Pinit ((P4 *)this)
+typedef struct P4 { /* :init: */
+ unsigned _pid : 8; /* 0..255 */
+ unsigned _t : 4; /* proctype */
+ unsigned _p : 7; /* state */
+ uchar i;
+ uchar j;
+ uchar sum;
+ uchar commit_sum;
+} P4;
+#define Air4 (sizeof(P4) - Offsetof(P4, commit_sum) - 1*sizeof(uchar))
+#define Pcleaner ((P3 *)this)
+typedef struct P3 { /* cleaner */
+ unsigned _pid : 8; /* 0..255 */
+ unsigned _t : 4; /* proctype */
+ unsigned _p : 7; /* state */
+} P3;
+#define Air3 (sizeof(P3) - 3)
+#define Preader ((P2 *)this)
+typedef struct P2 { /* reader */
+ unsigned _pid : 8; /* 0..255 */
+ unsigned _t : 4; /* proctype */
+ unsigned _p : 7; /* state */
+ uchar i;
+ uchar j;
+} P2;
+#define Air2 (sizeof(P2) - Offsetof(P2, j) - 1*sizeof(uchar))
+#define Ptracer ((P1 *)this)
+typedef struct P1 { /* tracer */
+ unsigned _pid : 8; /* 0..255 */
+ unsigned _t : 4; /* proctype */
+ unsigned _p : 7; /* state */
+ uchar size;
+ uchar prev_off;
+ uchar new_off;
+ uchar tmp_commit;
+ uchar i;
+ uchar j;
+} P1;
+#define Air1 (sizeof(P1) - Offsetof(P1, j) - 1*sizeof(uchar))
+#define Pswitcher ((P0 *)this)
+typedef struct P0 { /* switcher */
+ unsigned _pid : 8; /* 0..255 */
+ unsigned _t : 4; /* proctype */
+ unsigned _p : 7; /* state */
+ uchar prev_off;
+ uchar new_off;
+ uchar tmp_commit;
+ uchar size;
+} P0;
+#define Air0 (sizeof(P0) - Offsetof(P0, size) - 1*sizeof(uchar))
+typedef struct P6 { /* np_ */
+ unsigned _pid : 8; /* 0..255 */
+ unsigned _t : 4; /* proctype */
+ unsigned _p : 7; /* state */
+} P6;
+#define Air6 (sizeof(P6) - 3)
+#if defined(BFS) && defined(REACH)
+#undef REACH
+#endif
+#ifdef VERI
+#define BASE 1
+#else
+#define BASE 0
+#endif
+typedef struct Trans {
+ short atom; /* if &2 = atomic trans; if &8 local */
+#ifdef HAS_UNLESS
+ short escp[HAS_UNLESS]; /* lists the escape states */
+ short e_trans; /* if set, this is an escp-trans */
+#endif
+ short tpe[2]; /* class of operation (for reduction) */
+ short qu[6]; /* for conditional selections: qid's */
+ uchar ty[6]; /* ditto: type's */
+#ifdef NIBIS
+ short om; /* completion status of preselects */
+#endif
+ char *tp; /* src txt of statement */
+ int st; /* the nextstate */
+ int t_id; /* transition id, unique within proc */
+ int forw; /* index forward transition */
+ int back; /* index return transition */
+ struct Trans *nxt;
+} Trans;
+
+#define qptr(x) (((uchar *)&now)+(int)q_offset[x])
+#define pptr(x) (((uchar *)&now)+(int)proc_offset[x])
+extern uchar *Pptr(int);
+#define q_sz(x) (((Q0 *)qptr(x))->Qlen)
+
+#ifndef VECTORSZ
+#define VECTORSZ 1024 /* sv size in bytes */
+#endif
+
+#ifdef VERBOSE
+#ifndef CHECK
+#define CHECK
+#endif
+#ifndef DEBUG
+#define DEBUG
+#endif
+#endif
+#ifdef SAFETY
+#ifndef NOFAIR
+#define NOFAIR
+#endif
+#endif
+#ifdef NOREDUCE
+#ifndef XUSAFE
+#define XUSAFE
+#endif
+#if !defined(SAFETY) && !defined(MA)
+#define FULLSTACK
+#endif
+#else
+#ifdef BITSTATE
+#if defined(SAFETY) && !defined(HASH64)
+#define CNTRSTACK
+#else
+#define FULLSTACK
+#endif
+#else
+#define FULLSTACK
+#endif
+#endif
+#ifdef BITSTATE
+#ifndef NOCOMP
+#define NOCOMP
+#endif
+#if !defined(LC) && defined(SC)
+#define LC
+#endif
+#endif
+#if defined(COLLAPSE2) || defined(COLLAPSE3) || defined(COLLAPSE4)
+/* accept the above for backward compatibility */
+#define COLLAPSE
+#endif
+#ifdef HC
+#undef HC
+#define HC4
+#endif
+#ifdef HC0
+#define HC 0
+#endif
+#ifdef HC1
+#define HC 1
+#endif
+#ifdef HC2
+#define HC 2
+#endif
+#ifdef HC3
+#define HC 3
+#endif
+#ifdef HC4
+#define HC 4
+#endif
+#ifdef COLLAPSE
+#if NCORE>1 && !defined(SEP_STATE)
+unsigned long *ncomps; /* in shared memory */
+#else
+unsigned long ncomps[256+2];
+#endif
+#endif
+#define MAXQ 255
+#define MAXPROC 255
+#define WS sizeof(void *) /* word size in bytes */
+typedef struct Stack { /* for queues and processes */
+#if VECTORSZ>32000
+ int o_delta;
+ int o_offset;
+ int o_skip;
+ int o_delqs;
+#else
+ short o_delta;
+ short o_offset;
+ short o_skip;
+ short o_delqs;
+#endif
+ short o_boq;
+#ifndef XUSAFE
+ char *o_name;
+#endif
+ char *body;
+ struct Stack *nxt;
+ struct Stack *lst;
+} Stack;
+
+typedef struct Svtack { /* for complete state vector */
+#if VECTORSZ>32000
+ int o_delta;
+ int m_delta;
+#else
+ short o_delta; /* current size of frame */
+ short m_delta; /* maximum size of frame */
+#endif
+#if SYNC
+ short o_boq;
+#endif
+#define StackSize (WS)
+ char *body;
+ struct Svtack *nxt;
+ struct Svtack *lst;
+} Svtack;
+
+Trans ***trans; /* 1 ptr per state per proctype */
+
+struct H_el *Lstate;
+int depthfound = -1; /* loop detection */
+#if VECTORSZ>32000
+int proc_offset[MAXPROC];
+int q_offset[MAXQ];
+#else
+short proc_offset[MAXPROC];
+short q_offset[MAXQ];
+#endif
+uchar proc_skip[MAXPROC];
+uchar q_skip[MAXQ];
+unsigned long vsize; /* vector size in bytes */
+#ifdef SVDUMP
+int vprefix=0, svfd; /* runtime option -pN */
+#endif
+char *tprefix = "trail"; /* runtime option -tsuffix */
+short boq = -1; /* blocked_on_queue status */
+typedef struct State {
+ uchar _nr_pr;
+ uchar _nr_qs;
+ uchar _a_t; /* cycle detection */
+#ifndef NOFAIR
+ uchar _cnt[NFAIR]; /* counters, weak fairness */
+#endif
+#ifndef NOVSZ
+#if VECTORSZ<65536
+ unsigned short _vsz;
+#else
+ unsigned long _vsz;
+#endif
+#endif
+#ifdef HAS_LAST
+ uchar _last; /* pid executed in last step */
+#endif
+#ifdef EVENT_TRACE
+#if nstates_event<256
+ uchar _event;
+#else
+ unsigned short _event;
+#endif
+#endif
+ uchar buffer_use[4];
+ uchar write_off;
+ uchar commit_count[2];
+ uchar _commit_sum;
+ uchar read_off;
+ uchar events_lost;
+ uchar refcount;
+ uchar sv[VECTORSZ];
+} State;
+
+#define HAS_TRACK 0
+/* hidden variable: */ uchar deliver;
+int _; /* a predefined write-only variable */
+
+#define FORWARD_MOVES "pan.m"
+#define REVERSE_MOVES "pan.b"
+#define TRANSITIONS "pan.t"
+#define _NP_ 6
+uchar reached6[3]; /* np_ */
+uchar *loopstate6; /* np_ */
+#define nstates6 3 /* np_ */
+#define endstate6 2 /* np_ */
+
+#define start6 0 /* np_ */
+#define start5 5
+#define start_claim 5
+#define start4 42
+#define start3 8
+#define start2 26
+#define start1 3
+#define start0 11
+#ifdef NP
+ #define ACCEPT_LAB 1 /* at least 1 in np_ */
+#else
+ #define ACCEPT_LAB 1 /* user-defined accept labels */
+#endif
+#ifdef MEMCNT
+ #ifdef MEMLIM
+ #warning -DMEMLIM takes precedence over -DMEMCNT
+ #undef MEMCNT
+ #else
+ #if MEMCNT<20
+ #warning using minimal value -DMEMCNT=20 (=1MB)
+ #define MEMLIM (1)
+ #undef MEMCNT
+ #else
+ #if MEMCNT==20
+ #define MEMLIM (1)
+ #undef MEMCNT
+ #else
+ #if MEMCNT>=50
+ #error excessive value for MEMCNT
+ #else
+ #define MEMLIM (1<<(MEMCNT-20))
+ #endif
+ #endif
+ #endif
+ #endif
+#endif
+#if NCORE>1 && !defined(MEMLIM)
+ #define MEMLIM (2048) /* need a default, using 2 GB */
+#endif
+#define PROG_LAB 0 /* progress labels */
+uchar *accpstate[7];
+uchar *progstate[7];
+uchar *loopstate[7];
+uchar *reached[7];
+uchar *stopstate[7];
+uchar *visstate[7];
+short *mapstate[7];
+#ifdef HAS_CODE
+int NrStates[7];
+#endif
+#define NQS 0
+short q_flds[1];
+short q_max[1];
+typedef struct Q0 { /* generic q */
+ uchar Qlen; /* q_size */
+ uchar _t;
+} Q0;
+
+/** function prototypes **/
+char *emalloc(unsigned long);
+char *Malloc(unsigned long);
+int Boundcheck(int, int, int, int, Trans *);
+int addqueue(int, int);
+/* int atoi(char *); */
+/* int abort(void); */
+int close(int);
+int delproc(int, int);
+int endstate(void);
+int hstore(char *, int);
+#ifdef MA
+int gstore(char *, int, uchar);
+#endif
+int q_cond(short, Trans *);
+int q_full(int);
+int q_len(int);
+int q_zero(int);
+int qrecv(int, int, int, int);
+int unsend(int);
+/* void *sbrk(int); */
+void Uerror(char *);
+void assert(int, char *, int, int, Trans *);
+void c_chandump(int);
+void c_globals(void);
+void c_locals(int, int);
+void checkcycles(void);
+void crack(int, int, Trans *, short *);
+void d_sfh(const char *, int);
+void sfh(const char *, int);
+void d_hash(uchar *, int);
+void s_hash(uchar *, int);
+void r_hash(uchar *, int);
+void delq(int);
+void do_reach(void);
+void pan_exit(int);
+void exit(int);
+void hinit(void);
+void imed(Trans *, int, int, int);
+void new_state(void);
+void p_restor(int);
+void putpeg(int, int);
+void putrail(void);
+void q_restor(void);
+void retrans(int, int, int, short *, uchar *, uchar *);
+void settable(void);
+void setq_claim(int, int, char *, int, char *);
+void sv_restor(void);
+void sv_save(void);
+void tagtable(int, int, int, short *, uchar *);
+void do_dfs(int, int, int, short *, uchar *, uchar *);
+void uerror(char *);
+void unrecv(int, int, int, int, int);
+void usage(FILE *);
+void wrap_stats(void);
+#if defined(FULLSTACK) && defined(BITSTATE)
+int onstack_now(void);
+void onstack_init(void);
+void onstack_put(void);
+void onstack_zap(void);
+#endif
+#ifndef XUSAFE
+int q_S_check(int, int);
+int q_R_check(int, int);
+uchar q_claim[MAXQ+1];
+char *q_name[MAXQ+1];
+char *p_name[MAXPROC+1];
+#endif
+void qsend(int, int, int);
+#define Addproc(x) addproc(x)
+#define LOCAL 1
+#define Q_FULL_F 2
+#define Q_EMPT_F 3
+#define Q_EMPT_T 4
+#define Q_FULL_T 5
+#define TIMEOUT_F 6
+#define GLOBAL 7
+#define BAD 8
+#define ALPHA_F 9
+#define NTRANS 66
+#ifdef PEG
+long peg[NTRANS];
+#endif
--- /dev/null
+#define rwoff1 (write_off - read_off >= 0)
+#define rwoff2 (write_off - read_off < HALF_UCHAR)
+
+#define wcsum1 (write_off - _commit_sum >= 0)
+#define wcsum2 (write_off - _commit_sum < HALF_UCHAR)
+
+#define buffer_large_enough (NUMPROCS + NUMSWITCH <= BUFSIZE)
+#define have_events_lost (events_lost != 0)
+never { /* !( buffer_large_enough -> ([](!have_events_lost))) */
+T0_init:
+ if
+ :: ((buffer_large_enough) && (have_events_lost)) -> goto accept_all
+ :: ((buffer_large_enough)) -> goto T0_S3
+ fi;
+T0_S3:
+ if
+ :: ((have_events_lost)) -> goto accept_all
+ :: (1) -> goto T0_S3
+ fi;
+accept_all:
+ skip
+}
--- /dev/null
+#define rand pan_rand
+#if defined(HAS_CODE) && defined(VERBOSE)
+ cpu_printf("Pr: %d Tr: %d\n", II, t->forw);
+#endif
+ switch (t->forw) {
+ default: Uerror("bad forward move");
+ case 0: /* if without executable clauses */
+ continue;
+ case 1: /* generic 'goto' or 'skip' */
+ IfNotBlocked
+ _m = 3; goto P999;
+ case 2: /* generic 'else' */
+ IfNotBlocked
+ if (trpt->o_pm&1) continue;
+ _m = 3; goto P999;
+
+ /* PROC :never: */
+ case 3: /* STATE 1 - line 301 "pan.___" - [((((4+1)<=4)&&(events_lost!=0)))] (0:0:0 - 1) */
+
+#if defined(VERI) && !defined(NP)
+ { static int reported1 = 0;
+ if (verbose && !reported1)
+ { printf("depth %d: Claim reached state %d (line %d)\n",
+ depth, frm_st0[t->forw], src_claim[1]);
+ reported1 = 1;
+ fflush(stdout);
+ } }
+#endif
+ reached[5][1] = 1;
+ if (!((((4+1)<=4)&&(((int)now.events_lost)!=0))))
+ continue;
+ _m = 3; goto P999; /* 0 */
+ case 4: /* STATE 3 - line 302 "pan.___" - [(((4+1)<=4))] (0:0:0 - 1) */
+
+#if defined(VERI) && !defined(NP)
+ { static int reported3 = 0;
+ if (verbose && !reported3)
+ { printf("depth %d: Claim reached state %d (line %d)\n",
+ depth, frm_st0[t->forw], src_claim[3]);
+ reported3 = 1;
+ fflush(stdout);
+ } }
+#endif
+ reached[5][3] = 1;
+ if (!(((4+1)<=4)))
+ continue;
+ _m = 3; goto P999; /* 0 */
+ case 5: /* STATE 7 - line 306 "pan.___" - [((events_lost!=0))] (0:0:0 - 1) */
+
+#if defined(VERI) && !defined(NP)
+ { static int reported7 = 0;
+ if (verbose && !reported7)
+ { printf("depth %d: Claim reached state %d (line %d)\n",
+ depth, frm_st0[t->forw], src_claim[7]);
+ reported7 = 1;
+ fflush(stdout);
+ } }
+#endif
+ reached[5][7] = 1;
+ if (!((((int)now.events_lost)!=0)))
+ continue;
+ _m = 3; goto P999; /* 0 */
+ case 6: /* STATE 14 - line 311 "pan.___" - [-end-] (0:0:0 - 1) */
+
+#if defined(VERI) && !defined(NP)
+ { static int reported14 = 0;
+ if (verbose && !reported14)
+ { printf("depth %d: Claim reached state %d (line %d)\n",
+ depth, frm_st0[t->forw], src_claim[14]);
+ reported14 = 1;
+ fflush(stdout);
+ } }
+#endif
+ reached[5][14] = 1;
+ if (!delproc(1, II)) continue;
+ _m = 3; goto P999; /* 0 */
+
+ /* PROC :init: */
+ case 7: /* STATE 1 - line 252 "pan.___" - [i = 0] (0:0:1 - 1) */
+ IfNotBlocked
+ reached[4][1] = 1;
+ (trpt+1)->bup.oval = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ _m = 3; goto P999; /* 0 */
+ case 8: /* STATE 2 - line 254 "pan.___" - [((i<2))] (7:0:2 - 1) */
+ IfNotBlocked
+ reached[4][2] = 1;
+ if (!((((int)((P4 *)this)->i)<2)))
+ continue;
+ /* merge: commit_count[i] = 0(7, 3, 7) */
+ reached[4][3] = 1;
+ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((int)now.commit_count[ Index(((int)((P4 *)this)->i), 2) ]);
+ now.commit_count[ Index(((P4 *)this)->i, 2) ] = 0;
+#ifdef VAR_RANGES
+ logval("commit_count[:init::i]", ((int)now.commit_count[ Index(((int)((P4 *)this)->i), 2) ]));
+#endif
+ ;
+ /* merge: i = (i+1)(7, 4, 7) */
+ reached[4][4] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = (((int)((P4 *)this)->i)+1);
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 8, 7) */
+ reached[4][8] = 1;
+ ;
+ _m = 3; goto P999; /* 3 */
+ case 9: /* STATE 5 - line 257 "pan.___" - [((i>=2))] (17:0:3 - 1) */
+ IfNotBlocked
+ reached[4][5] = 1;
+ if (!((((int)((P4 *)this)->i)>=2)))
+ continue;
+ /* dead 1: i */ (trpt+1)->bup.ovals = grab_ints(3);
+ (trpt+1)->bup.ovals[0] = ((P4 *)this)->i;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P4 *)this)->i = 0;
+ /* merge: goto :b6(17, 6, 17) */
+ reached[4][6] = 1;
+ ;
+ /* merge: _commit_sum = 0(17, 10, 17) */
+ reached[4][10] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)now._commit_sum);
+ now._commit_sum = 0;
+#ifdef VAR_RANGES
+ logval("_commit_sum", ((int)now._commit_sum));
+#endif
+ ;
+ /* merge: i = 0(17, 11, 17) */
+ reached[4][11] = 1;
+ (trpt+1)->bup.ovals[2] = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 18, 17) */
+ reached[4][18] = 1;
+ ;
+ _m = 3; goto P999; /* 4 */
+ case 10: /* STATE 10 - line 260 "pan.___" - [_commit_sum = 0] (0:17:2 - 3) */
+ IfNotBlocked
+ reached[4][10] = 1;
+ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((int)now._commit_sum);
+ now._commit_sum = 0;
+#ifdef VAR_RANGES
+ logval("_commit_sum", ((int)now._commit_sum));
+#endif
+ ;
+ /* merge: i = 0(17, 11, 17) */
+ reached[4][11] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 18, 17) */
+ reached[4][18] = 1;
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 11: /* STATE 12 - line 264 "pan.___" - [((i<4))] (17:0:2 - 1) */
+ IfNotBlocked
+ reached[4][12] = 1;
+ if (!((((int)((P4 *)this)->i)<4)))
+ continue;
+ /* merge: buffer_use[i] = 0(17, 13, 17) */
+ reached[4][13] = 1;
+ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((int)now.buffer_use[ Index(((int)((P4 *)this)->i), 4) ]);
+ now.buffer_use[ Index(((P4 *)this)->i, 4) ] = 0;
+#ifdef VAR_RANGES
+ logval("buffer_use[:init::i]", ((int)now.buffer_use[ Index(((int)((P4 *)this)->i), 4) ]));
+#endif
+ ;
+ /* merge: i = (i+1)(17, 14, 17) */
+ reached[4][14] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = (((int)((P4 *)this)->i)+1);
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 18, 17) */
+ reached[4][18] = 1;
+ ;
+ _m = 3; goto P999; /* 3 */
+ case 12: /* STATE 15 - line 267 "pan.___" - [((i>=4))] (0:0:1 - 1) */
+ IfNotBlocked
+ reached[4][15] = 1;
+ if (!((((int)((P4 *)this)->i)>=4)))
+ continue;
+ /* dead 1: i */ (trpt+1)->bup.oval = ((P4 *)this)->i;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P4 *)this)->i = 0;
+ _m = 3; goto P999; /* 0 */
+ case 13: /* STATE 20 - line 269 "pan.___" - [(run reader())] (0:0:0 - 3) */
+ IfNotBlocked
+ reached[4][20] = 1;
+ if (!(addproc(2)))
+ continue;
+ _m = 3; goto P999; /* 0 */
+ case 14: /* STATE 21 - line 270 "pan.___" - [(run cleaner())] (29:0:1 - 1) */
+ IfNotBlocked
+ reached[4][21] = 1;
+ if (!(addproc(3)))
+ continue;
+ /* merge: i = 0(0, 22, 29) */
+ reached[4][22] = 1;
+ (trpt+1)->bup.oval = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 30, 29) */
+ reached[4][30] = 1;
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 15: /* STATE 23 - line 273 "pan.___" - [((i<4))] (25:0:1 - 1) */
+ IfNotBlocked
+ reached[4][23] = 1;
+ if (!((((int)((P4 *)this)->i)<4)))
+ continue;
+ /* merge: refcount = (refcount+1)(0, 24, 25) */
+ reached[4][24] = 1;
+ (trpt+1)->bup.oval = ((int)now.refcount);
+ now.refcount = (((int)now.refcount)+1);
+#ifdef VAR_RANGES
+ logval("refcount", ((int)now.refcount));
+#endif
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 16: /* STATE 25 - line 275 "pan.___" - [(run tracer())] (29:0:1 - 1) */
+ IfNotBlocked
+ reached[4][25] = 1;
+ if (!(addproc(1)))
+ continue;
+ /* merge: i = (i+1)(0, 26, 29) */
+ reached[4][26] = 1;
+ (trpt+1)->bup.oval = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = (((int)((P4 *)this)->i)+1);
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 30, 29) */
+ reached[4][30] = 1;
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 17: /* STATE 27 - line 277 "pan.___" - [((i>=4))] (39:0:2 - 1) */
+ IfNotBlocked
+ reached[4][27] = 1;
+ if (!((((int)((P4 *)this)->i)>=4)))
+ continue;
+ /* dead 1: i */ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((P4 *)this)->i;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P4 *)this)->i = 0;
+ /* merge: goto :b8(39, 28, 39) */
+ reached[4][28] = 1;
+ ;
+ /* merge: i = 0(39, 32, 39) */
+ reached[4][32] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 40, 39) */
+ reached[4][40] = 1;
+ ;
+ _m = 3; goto P999; /* 3 */
+ case 18: /* STATE 32 - line 279 "pan.___" - [i = 0] (0:39:1 - 3) */
+ IfNotBlocked
+ reached[4][32] = 1;
+ (trpt+1)->bup.oval = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 40, 39) */
+ reached[4][40] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 19: /* STATE 33 - line 281 "pan.___" - [((i<1))] (35:0:1 - 1) */
+ IfNotBlocked
+ reached[4][33] = 1;
+ if (!((((int)((P4 *)this)->i)<1)))
+ continue;
+ /* merge: refcount = (refcount+1)(0, 34, 35) */
+ reached[4][34] = 1;
+ (trpt+1)->bup.oval = ((int)now.refcount);
+ now.refcount = (((int)now.refcount)+1);
+#ifdef VAR_RANGES
+ logval("refcount", ((int)now.refcount));
+#endif
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 20: /* STATE 35 - line 283 "pan.___" - [(run switcher())] (39:0:1 - 1) */
+ IfNotBlocked
+ reached[4][35] = 1;
+ if (!(addproc(0)))
+ continue;
+ /* merge: i = (i+1)(0, 36, 39) */
+ reached[4][36] = 1;
+ (trpt+1)->bup.oval = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = (((int)((P4 *)this)->i)+1);
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 40, 39) */
+ reached[4][40] = 1;
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 21: /* STATE 37 - line 285 "pan.___" - [((i>=1))] (41:0:1 - 1) */
+ IfNotBlocked
+ reached[4][37] = 1;
+ if (!((((int)((P4 *)this)->i)>=1)))
+ continue;
+ /* dead 1: i */ (trpt+1)->bup.oval = ((P4 *)this)->i;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P4 *)this)->i = 0;
+ /* merge: goto :b9(0, 38, 41) */
+ reached[4][38] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 22: /* STATE 43 - line 288 "pan.___" - [-end-] (0:0:0 - 1) */
+ IfNotBlocked
+ reached[4][43] = 1;
+ if (!delproc(1, II)) continue;
+ _m = 3; goto P999; /* 0 */
+
+ /* PROC cleaner */
+ case 23: /* STATE 1 - line 237 "pan.___" - [((refcount==0))] (3:0:1 - 1) */
+ IfNotBlocked
+ reached[3][1] = 1;
+ if (!((((int)now.refcount)==0)))
+ continue;
+ /* merge: refcount = (refcount+1)(0, 2, 3) */
+ reached[3][2] = 1;
+ (trpt+1)->bup.oval = ((int)now.refcount);
+ now.refcount = (((int)now.refcount)+1);
+#ifdef VAR_RANGES
+ logval("refcount", ((int)now.refcount));
+#endif
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 24: /* STATE 3 - line 239 "pan.___" - [(run switcher())] (7:0:0 - 1) */
+ IfNotBlocked
+ reached[3][3] = 1;
+ if (!(addproc(0)))
+ continue;
+ /* merge: goto :b5(0, 4, 7) */
+ reached[3][4] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 25: /* STATE 9 - line 243 "pan.___" - [-end-] (0:0:0 - 1) */
+ IfNotBlocked
+ reached[3][9] = 1;
+ if (!delproc(1, II)) continue;
+ _m = 3; goto P999; /* 0 */
+
+ /* PROC reader */
+ case 26: /* STATE 1 - line 200 "pan.___" - [((((((write_off/(4/2))-(read_off/(4/2)))>0)&&(((write_off/(4/2))-(read_off/(4/2)))<(255/2)))&&(((commit_count[((read_off%4)/(4/2))]-(4/2))-(((read_off/4)*4)/2))==0)))] (0:0:0 - 1) */
+ IfNotBlocked
+ reached[2][1] = 1;
+ if (!((((((((int)now.write_off)/(4/2))-(((int)now.read_off)/(4/2)))>0)&&(((((int)now.write_off)/(4/2))-(((int)now.read_off)/(4/2)))<(255/2)))&&(((((int)now.commit_count[ Index(((((int)now.read_off)%4)/(4/2)), 2) ])-(4/2))-(((((int)now.read_off)/4)*4)/2))==0))))
+ continue;
+ _m = 3; goto P999; /* 0 */
+ case 27: /* STATE 2 - line 202 "pan.___" - [i = 0] (0:0:1 - 1) */
+ IfNotBlocked
+ reached[2][2] = 1;
+ (trpt+1)->bup.oval = ((int)((P2 *)this)->i);
+ ((P2 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval("reader:i", ((int)((P2 *)this)->i));
+#endif
+ ;
+ _m = 3; goto P999; /* 0 */
+ case 28: /* STATE 3 - line 204 "pan.___" - [((i<(4/2)))] (9:0:2 - 1) */
+ IfNotBlocked
+ reached[2][3] = 1;
+ if (!((((int)((P2 *)this)->i)<(4/2))))
+ continue;
+ /* merge: assert((buffer_use[((read_off+i)%4)]==0))(9, 4, 9) */
+ reached[2][4] = 1;
+ assert((((int)now.buffer_use[ Index(((((int)now.read_off)+((int)((P2 *)this)->i))%4), 4) ])==0), "(buffer_use[((read_off+i)%4)]==0)", II, tt, t);
+ /* merge: buffer_use[((read_off+i)%4)] = 1(9, 5, 9) */
+ reached[2][5] = 1;
+ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((int)now.buffer_use[ Index(((((int)now.read_off)+((int)((P2 *)this)->i))%4), 4) ]);
+ now.buffer_use[ Index(((now.read_off+((P2 *)this)->i)%4), 4) ] = 1;
+#ifdef VAR_RANGES
+ logval("buffer_use[((read_off+reader:i)%4)]", ((int)now.buffer_use[ Index(((((int)now.read_off)+((int)((P2 *)this)->i))%4), 4) ]));
+#endif
+ ;
+ /* merge: i = (i+1)(9, 6, 9) */
+ reached[2][6] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P2 *)this)->i);
+ ((P2 *)this)->i = (((int)((P2 *)this)->i)+1);
+#ifdef VAR_RANGES
+ logval("reader:i", ((int)((P2 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 10, 9) */
+ reached[2][10] = 1;
+ ;
+ _m = 3; goto P999; /* 4 */
+ case 29: /* STATE 7 - line 208 "pan.___" - [((i>=(4/2)))] (11:0:1 - 1) */
+ IfNotBlocked
+ reached[2][7] = 1;
+ if (!((((int)((P2 *)this)->i)>=(4/2))))
+ continue;
+ /* dead 1: i */ (trpt+1)->bup.oval = ((P2 *)this)->i;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P2 *)this)->i = 0;
+ /* merge: goto :b3(0, 8, 11) */
+ reached[2][8] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+/* STATE 13 - line 216 "pan.___" - [i = 0] (0:0 - 1) same as 27 (0:0 - 1) */
+ case 30: /* STATE 14 - line 218 "pan.___" - [((i<(4/2)))] (19:0:2 - 1) */
+ IfNotBlocked
+ reached[2][14] = 1;
+ if (!((((int)((P2 *)this)->i)<(4/2))))
+ continue;
+ /* merge: buffer_use[((read_off+i)%4)] = 0(19, 15, 19) */
+ reached[2][15] = 1;
+ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((int)now.buffer_use[ Index(((((int)now.read_off)+((int)((P2 *)this)->i))%4), 4) ]);
+ now.buffer_use[ Index(((now.read_off+((P2 *)this)->i)%4), 4) ] = 0;
+#ifdef VAR_RANGES
+ logval("buffer_use[((read_off+reader:i)%4)]", ((int)now.buffer_use[ Index(((((int)now.read_off)+((int)((P2 *)this)->i))%4), 4) ]));
+#endif
+ ;
+ /* merge: i = (i+1)(19, 16, 19) */
+ reached[2][16] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P2 *)this)->i);
+ ((P2 *)this)->i = (((int)((P2 *)this)->i)+1);
+#ifdef VAR_RANGES
+ logval("reader:i", ((int)((P2 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 20, 19) */
+ reached[2][20] = 1;
+ ;
+ _m = 3; goto P999; /* 3 */
+ case 31: /* STATE 17 - line 221 "pan.___" - [((i>=(4/2)))] (0:0:1 - 1) */
+ IfNotBlocked
+ reached[2][17] = 1;
+ if (!((((int)((P2 *)this)->i)>=(4/2))))
+ continue;
+ /* dead 1: i */ (trpt+1)->bup.oval = ((P2 *)this)->i;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P2 *)this)->i = 0;
+ _m = 3; goto P999; /* 0 */
+ case 32: /* STATE 22 - line 223 "pan.___" - [read_off = (read_off+(4/2))] (0:0:1 - 1) */
+ IfNotBlocked
+ reached[2][22] = 1;
+ (trpt+1)->bup.oval = ((int)now.read_off);
+ now.read_off = (((int)now.read_off)+(4/2));
+#ifdef VAR_RANGES
+ logval("read_off", ((int)now.read_off));
+#endif
+ ;
+ _m = 3; goto P999; /* 0 */
+ case 33: /* STATE 24 - line 225 "pan.___" - [((read_off>=(4-events_lost)))] (0:0:0 - 1) */
+ IfNotBlocked
+ reached[2][24] = 1;
+ if (!((((int)now.read_off)>=(4-((int)now.events_lost)))))
+ continue;
+ _m = 3; goto P999; /* 0 */
+ case 34: /* STATE 29 - line 227 "pan.___" - [-end-] (0:0:0 - 3) */
+ IfNotBlocked
+ reached[2][29] = 1;
+ if (!delproc(1, II)) continue;
+ _m = 3; goto P999; /* 0 */
+
+ /* PROC tracer */
+ case 35: /* STATE 1 - line 123 "pan.___" - [prev_off = write_off] (0:10:2 - 1) */
+ IfNotBlocked
+ reached[1][1] = 1;
+ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((int)((P1 *)this)->prev_off);
+ ((P1 *)this)->prev_off = ((int)now.write_off);
+#ifdef VAR_RANGES
+ logval("tracer:prev_off", ((int)((P1 *)this)->prev_off));
+#endif
+ ;
+ /* merge: new_off = (prev_off+size)(10, 2, 10) */
+ reached[1][2] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P1 *)this)->new_off);
+ ((P1 *)this)->new_off = (((int)((P1 *)this)->prev_off)+((int)((P1 *)this)->size));
+#ifdef VAR_RANGES
+ logval("tracer:new_off", ((int)((P1 *)this)->new_off));
+#endif
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 36: /* STATE 4 - line 128 "pan.___" - [((((new_off-read_off)>4)&&((new_off-read_off)<(255/2))))] (0:0:1 - 1) */
+ IfNotBlocked
+ reached[1][4] = 1;
+ if (!((((((int)((P1 *)this)->new_off)-((int)now.read_off))>4)&&((((int)((P1 *)this)->new_off)-((int)now.read_off))<(255/2)))))
+ continue;
+ /* dead 1: new_off */ (trpt+1)->bup.oval = ((P1 *)this)->new_off;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P1 *)this)->new_off = 0;
+ _m = 3; goto P999; /* 0 */
+ case 37: /* STATE 7 - line 130 "pan.___" - [(1)] (27:0:0 - 1) */
+ IfNotBlocked
+ reached[1][7] = 1;
+ if (!(1))
+ continue;
+ /* merge: .(goto)(0, 9, 27) */
+ reached[1][9] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 38: /* STATE 11 - line 135 "pan.___" - [((prev_off!=write_off))] (3:0:1 - 1) */
+ IfNotBlocked
+ reached[1][11] = 1;
+ if (!((((int)((P1 *)this)->prev_off)!=((int)now.write_off))))
+ continue;
+ /* dead 1: prev_off */ (trpt+1)->bup.oval = ((P1 *)this)->prev_off;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P1 *)this)->prev_off = 0;
+ /* merge: goto cmpxchg_loop(0, 12, 3) */
+ reached[1][12] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 39: /* STATE 14 - line 136 "pan.___" - [write_off = new_off] (0:24:2 - 1) */
+ IfNotBlocked
+ reached[1][14] = 1;
+ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((int)now.write_off);
+ now.write_off = ((int)((P1 *)this)->new_off);
+#ifdef VAR_RANGES
+ logval("write_off", ((int)now.write_off));
+#endif
+ ;
+ /* merge: .(goto)(24, 16, 24) */
+ reached[1][16] = 1;
+ ;
+ /* merge: i = 0(24, 17, 24) */
+ reached[1][17] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P1 *)this)->i);
+ ((P1 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval("tracer:i", ((int)((P1 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 25, 24) */
+ reached[1][25] = 1;
+ ;
+ _m = 3; goto P999; /* 3 */
+ case 40: /* STATE 17 - line 138 "pan.___" - [i = 0] (0:24:1 - 2) */
+ IfNotBlocked
+ reached[1][17] = 1;
+ (trpt+1)->bup.oval = ((int)((P1 *)this)->i);
+ ((P1 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval("tracer:i", ((int)((P1 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 25, 24) */
+ reached[1][25] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 41: /* STATE 18 - line 140 "pan.___" - [((i<size))] (24:0:2 - 1) */
+ IfNotBlocked
+ reached[1][18] = 1;
+ if (!((((int)((P1 *)this)->i)<((int)((P1 *)this)->size))))
+ continue;
+ /* merge: assert((buffer_use[((prev_off+i)%4)]==0))(24, 19, 24) */
+ reached[1][19] = 1;
+ assert((((int)now.buffer_use[ Index(((((int)((P1 *)this)->prev_off)+((int)((P1 *)this)->i))%4), 4) ])==0), "(buffer_use[((prev_off+i)%4)]==0)", II, tt, t);
+ /* merge: buffer_use[((prev_off+i)%4)] = 1(24, 20, 24) */
+ reached[1][20] = 1;
+ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((int)now.buffer_use[ Index(((((int)((P1 *)this)->prev_off)+((int)((P1 *)this)->i))%4), 4) ]);
+ now.buffer_use[ Index(((((P1 *)this)->prev_off+((P1 *)this)->i)%4), 4) ] = 1;
+#ifdef VAR_RANGES
+ logval("buffer_use[((tracer:prev_off+tracer:i)%4)]", ((int)now.buffer_use[ Index(((((int)((P1 *)this)->prev_off)+((int)((P1 *)this)->i))%4), 4) ]));
+#endif
+ ;
+ /* merge: i = (i+1)(24, 21, 24) */
+ reached[1][21] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P1 *)this)->i);
+ ((P1 *)this)->i = (((int)((P1 *)this)->i)+1);
+#ifdef VAR_RANGES
+ logval("tracer:i", ((int)((P1 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 25, 24) */
+ reached[1][25] = 1;
+ ;
+ _m = 3; goto P999; /* 4 */
+ case 42: /* STATE 22 - line 144 "pan.___" - [((i>=size))] (26:0:1 - 1) */
+ IfNotBlocked
+ reached[1][22] = 1;
+ if (!((((int)((P1 *)this)->i)>=((int)((P1 *)this)->size))))
+ continue;
+ /* dead 1: i */ (trpt+1)->bup.oval = ((P1 *)this)->i;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P1 *)this)->i = 0;
+ /* merge: goto :b0(0, 23, 26) */
+ reached[1][23] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 43: /* STATE 28 - line 152 "pan.___" - [i = 0] (0:0:1 - 1) */
+ IfNotBlocked
+ reached[1][28] = 1;
+ (trpt+1)->bup.oval = ((int)((P1 *)this)->i);
+ ((P1 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval("tracer:i", ((int)((P1 *)this)->i));
+#endif
+ ;
+ _m = 3; goto P999; /* 0 */
+ case 44: /* STATE 29 - line 154 "pan.___" - [((i<size))] (34:0:2 - 1) */
+ IfNotBlocked
+ reached[1][29] = 1;
+ if (!((((int)((P1 *)this)->i)<((int)((P1 *)this)->size))))
+ continue;
+ /* merge: buffer_use[((prev_off+i)%4)] = 0(34, 30, 34) */
+ reached[1][30] = 1;
+ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((int)now.buffer_use[ Index(((((int)((P1 *)this)->prev_off)+((int)((P1 *)this)->i))%4), 4) ]);
+ now.buffer_use[ Index(((((P1 *)this)->prev_off+((P1 *)this)->i)%4), 4) ] = 0;
+#ifdef VAR_RANGES
+ logval("buffer_use[((tracer:prev_off+tracer:i)%4)]", ((int)now.buffer_use[ Index(((((int)((P1 *)this)->prev_off)+((int)((P1 *)this)->i))%4), 4) ]));
+#endif
+ ;
+ /* merge: i = (i+1)(34, 31, 34) */
+ reached[1][31] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P1 *)this)->i);
+ ((P1 *)this)->i = (((int)((P1 *)this)->i)+1);
+#ifdef VAR_RANGES
+ logval("tracer:i", ((int)((P1 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 35, 34) */
+ reached[1][35] = 1;
+ ;
+ _m = 3; goto P999; /* 3 */
+ case 45: /* STATE 32 - line 157 "pan.___" - [((i>=size))] (44:0:4 - 1) */
+ IfNotBlocked
+ reached[1][32] = 1;
+ if (!((((int)((P1 *)this)->i)>=((int)((P1 *)this)->size))))
+ continue;
+ /* dead 1: i */ (trpt+1)->bup.ovals = grab_ints(4);
+ (trpt+1)->bup.ovals[0] = ((P1 *)this)->i;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P1 *)this)->i = 0;
+ /* merge: goto :b1(44, 33, 44) */
+ reached[1][33] = 1;
+ ;
+ /* merge: tmp_commit = (commit_count[((prev_off%4)/(4/2))]+size)(44, 37, 44) */
+ reached[1][37] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P1 *)this)->tmp_commit);
+ ((P1 *)this)->tmp_commit = (((int)now.commit_count[ Index(((((int)((P1 *)this)->prev_off)%4)/(4/2)), 2) ])+((int)((P1 *)this)->size));
+#ifdef VAR_RANGES
+ logval("tracer:tmp_commit", ((int)((P1 *)this)->tmp_commit));
+#endif
+ ;
+ /* merge: _commit_sum = ((_commit_sum-commit_count[((prev_off%4)/(4/2))])+tmp_commit)(44, 38, 44) */
+ reached[1][38] = 1;
+ (trpt+1)->bup.ovals[2] = ((int)now._commit_sum);
+ now._commit_sum = ((((int)now._commit_sum)-((int)now.commit_count[ Index(((((int)((P1 *)this)->prev_off)%4)/(4/2)), 2) ]))+((int)((P1 *)this)->tmp_commit));
+#ifdef VAR_RANGES
+ logval("_commit_sum", ((int)now._commit_sum));
+#endif
+ ;
+ /* merge: commit_count[((prev_off%4)/(4/2))] = tmp_commit(44, 39, 44) */
+ reached[1][39] = 1;
+ (trpt+1)->bup.ovals[3] = ((int)now.commit_count[ Index(((((int)((P1 *)this)->prev_off)%4)/(4/2)), 2) ]);
+ now.commit_count[ Index(((((P1 *)this)->prev_off%4)/(4/2)), 2) ] = ((int)((P1 *)this)->tmp_commit);
+#ifdef VAR_RANGES
+ logval("commit_count[((tracer:prev_off%4)/(4/2))]", ((int)now.commit_count[ Index(((((int)((P1 *)this)->prev_off)%4)/(4/2)), 2) ]));
+#endif
+ ;
+ _m = 3; goto P999; /* 4 */
+ case 46: /* STATE 37 - line 159 "pan.___" - [tmp_commit = (commit_count[((prev_off%4)/(4/2))]+size)] (0:44:3 - 3) */
+ IfNotBlocked
+ reached[1][37] = 1;
+ (trpt+1)->bup.ovals = grab_ints(3);
+ (trpt+1)->bup.ovals[0] = ((int)((P1 *)this)->tmp_commit);
+ ((P1 *)this)->tmp_commit = (((int)now.commit_count[ Index(((((int)((P1 *)this)->prev_off)%4)/(4/2)), 2) ])+((int)((P1 *)this)->size));
+#ifdef VAR_RANGES
+ logval("tracer:tmp_commit", ((int)((P1 *)this)->tmp_commit));
+#endif
+ ;
+ /* merge: _commit_sum = ((_commit_sum-commit_count[((prev_off%4)/(4/2))])+tmp_commit)(44, 38, 44) */
+ reached[1][38] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)now._commit_sum);
+ now._commit_sum = ((((int)now._commit_sum)-((int)now.commit_count[ Index(((((int)((P1 *)this)->prev_off)%4)/(4/2)), 2) ]))+((int)((P1 *)this)->tmp_commit));
+#ifdef VAR_RANGES
+ logval("_commit_sum", ((int)now._commit_sum));
+#endif
+ ;
+ /* merge: commit_count[((prev_off%4)/(4/2))] = tmp_commit(44, 39, 44) */
+ reached[1][39] = 1;
+ (trpt+1)->bup.ovals[2] = ((int)now.commit_count[ Index(((((int)((P1 *)this)->prev_off)%4)/(4/2)), 2) ]);
+ now.commit_count[ Index(((((P1 *)this)->prev_off%4)/(4/2)), 2) ] = ((int)((P1 *)this)->tmp_commit);
+#ifdef VAR_RANGES
+ logval("commit_count[((tracer:prev_off%4)/(4/2))]", ((int)now.commit_count[ Index(((((int)((P1 *)this)->prev_off)%4)/(4/2)), 2) ]));
+#endif
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 47: /* STATE 40 - line 167 "pan.___" - [((((((prev_off/4)*4)/2)+(4/2))-tmp_commit))] (50:0:3 - 1) */
+ IfNotBlocked
+ reached[1][40] = 1;
+ if (!((((((((int)((P1 *)this)->prev_off)/4)*4)/2)+(4/2))-((int)((P1 *)this)->tmp_commit))))
+ continue;
+ /* dead 1: prev_off */ (trpt+1)->bup.ovals = grab_ints(3);
+ (trpt+1)->bup.ovals[0] = ((P1 *)this)->prev_off;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P1 *)this)->prev_off = 0;
+ /* dead 1: tmp_commit */ (trpt+1)->bup.ovals[1] = ((P1 *)this)->tmp_commit;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P1 *)this)->tmp_commit = 0;
+ /* merge: deliver = 1(50, 41, 50) */
+ reached[1][41] = 1;
+ (trpt+1)->bup.ovals[2] = ((int)deliver);
+ deliver = 1;
+#ifdef VAR_RANGES
+ logval("deliver", ((int)deliver));
+#endif
+ ;
+ /* merge: .(goto)(50, 45, 50) */
+ reached[1][45] = 1;
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 48: /* STATE 45 - line 172 "pan.___" - [.(goto)] (0:50:0 - 2) */
+ IfNotBlocked
+ reached[1][45] = 1;
+ ;
+ _m = 3; goto P999; /* 0 */
+ case 49: /* STATE 43 - line 170 "pan.___" - [(1)] (50:0:0 - 1) */
+ IfNotBlocked
+ reached[1][43] = 1;
+ if (!(1))
+ continue;
+ /* merge: .(goto)(50, 45, 50) */
+ reached[1][45] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 50: /* STATE 48 - line 176 "pan.___" - [events_lost = (events_lost+1)] (0:0:1 - 2) */
+ IfNotBlocked
+ reached[1][48] = 1;
+ (trpt+1)->bup.oval = ((int)now.events_lost);
+ now.events_lost = (((int)now.events_lost)+1);
+#ifdef VAR_RANGES
+ logval("events_lost", ((int)now.events_lost));
+#endif
+ ;
+ _m = 3; goto P999; /* 0 */
+ case 51: /* STATE 49 - line 178 "pan.___" - [refcount = (refcount-1)] (0:0:1 - 2) */
+ IfNotBlocked
+ reached[1][49] = 1;
+ (trpt+1)->bup.oval = ((int)now.refcount);
+ now.refcount = (((int)now.refcount)-1);
+#ifdef VAR_RANGES
+ logval("refcount", ((int)now.refcount));
+#endif
+ ;
+ _m = 3; goto P999; /* 0 */
+ case 52: /* STATE 51 - line 180 "pan.___" - [-end-] (0:0:0 - 1) */
+ IfNotBlocked
+ reached[1][51] = 1;
+ if (!delproc(1, II)) continue;
+ _m = 3; goto P999; /* 0 */
+
+ /* PROC switcher */
+ case 53: /* STATE 1 - line 72 "pan.___" - [prev_off = write_off] (0:9:3 - 1) */
+ IfNotBlocked
+ reached[0][1] = 1;
+ (trpt+1)->bup.ovals = grab_ints(3);
+ (trpt+1)->bup.ovals[0] = ((int)((P0 *)this)->prev_off);
+ ((P0 *)this)->prev_off = ((int)now.write_off);
+#ifdef VAR_RANGES
+ logval("switcher:prev_off", ((int)((P0 *)this)->prev_off));
+#endif
+ ;
+ /* merge: size = ((4/2)-(prev_off%(4/2)))(9, 2, 9) */
+ reached[0][2] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P0 *)this)->size);
+ ((P0 *)this)->size = ((4/2)-(((int)((P0 *)this)->prev_off)%(4/2)));
+#ifdef VAR_RANGES
+ logval("switcher:size", ((int)((P0 *)this)->size));
+#endif
+ ;
+ /* merge: new_off = (prev_off+size)(9, 3, 9) */
+ reached[0][3] = 1;
+ (trpt+1)->bup.ovals[2] = ((int)((P0 *)this)->new_off);
+ ((P0 *)this)->new_off = (((int)((P0 *)this)->prev_off)+((int)((P0 *)this)->size));
+#ifdef VAR_RANGES
+ logval("switcher:new_off", ((int)((P0 *)this)->new_off));
+#endif
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 54: /* STATE 4 - line 77 "pan.___" - [(((((new_off-read_off)>4)&&((new_off-read_off)<(255/2)))||(size==(4/2))))] (30:0:3 - 1) */
+ IfNotBlocked
+ reached[0][4] = 1;
+ if (!(((((((int)((P0 *)this)->new_off)-((int)now.read_off))>4)&&((((int)((P0 *)this)->new_off)-((int)now.read_off))<(255/2)))||(((int)((P0 *)this)->size)==(4/2)))))
+ continue;
+ /* dead 1: new_off */ (trpt+1)->bup.ovals = grab_ints(3);
+ (trpt+1)->bup.ovals[0] = ((P0 *)this)->new_off;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P0 *)this)->new_off = 0;
+ /* dead 1: size */ (trpt+1)->bup.ovals[1] = ((P0 *)this)->size;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P0 *)this)->size = 0;
+ /* merge: refcount = (refcount-1)(30, 5, 30) */
+ reached[0][5] = 1;
+ (trpt+1)->bup.ovals[2] = ((int)now.refcount);
+ now.refcount = (((int)now.refcount)-1);
+#ifdef VAR_RANGES
+ logval("refcount", ((int)now.refcount));
+#endif
+ ;
+ /* merge: goto not_needed(30, 6, 30) */
+ reached[0][6] = 1;
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 55: /* STATE 8 - line 80 "pan.___" - [(1)] (18:0:0 - 1) */
+ IfNotBlocked
+ reached[0][8] = 1;
+ if (!(1))
+ continue;
+ /* merge: .(goto)(0, 10, 18) */
+ reached[0][10] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 56: /* STATE 12 - line 85 "pan.___" - [((prev_off!=write_off))] (11:0:1 - 1) */
+ IfNotBlocked
+ reached[0][12] = 1;
+ if (!((((int)((P0 *)this)->prev_off)!=((int)now.write_off))))
+ continue;
+ /* dead 1: prev_off */ (trpt+1)->bup.oval = ((P0 *)this)->prev_off;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P0 *)this)->prev_off = 0;
+ /* merge: goto cmpxchg_loop(0, 13, 11) */
+ reached[0][13] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 57: /* STATE 17 - line 88 "pan.___" - [.(goto)] (0:29:0 - 1) */
+ IfNotBlocked
+ reached[0][17] = 1;
+ ;
+ _m = 3; goto P999; /* 0 */
+ case 58: /* STATE 15 - line 86 "pan.___" - [write_off = new_off] (0:29:1 - 1) */
+ IfNotBlocked
+ reached[0][15] = 1;
+ (trpt+1)->bup.oval = ((int)now.write_off);
+ now.write_off = ((int)((P0 *)this)->new_off);
+#ifdef VAR_RANGES
+ logval("write_off", ((int)now.write_off));
+#endif
+ ;
+ /* merge: .(goto)(29, 17, 29) */
+ reached[0][17] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 59: /* STATE 19 - line 91 "pan.___" - [tmp_commit = (commit_count[((prev_off%4)/(4/2))]+size)] (0:26:3 - 1) */
+ IfNotBlocked
+ reached[0][19] = 1;
+ (trpt+1)->bup.ovals = grab_ints(3);
+ (trpt+1)->bup.ovals[0] = ((int)((P0 *)this)->tmp_commit);
+ ((P0 *)this)->tmp_commit = (((int)now.commit_count[ Index(((((int)((P0 *)this)->prev_off)%4)/(4/2)), 2) ])+((int)((P0 *)this)->size));
+#ifdef VAR_RANGES
+ logval("switcher:tmp_commit", ((int)((P0 *)this)->tmp_commit));
+#endif
+ ;
+ /* merge: _commit_sum = ((_commit_sum-commit_count[((prev_off%4)/(4/2))])+tmp_commit)(26, 20, 26) */
+ reached[0][20] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)now._commit_sum);
+ now._commit_sum = ((((int)now._commit_sum)-((int)now.commit_count[ Index(((((int)((P0 *)this)->prev_off)%4)/(4/2)), 2) ]))+((int)((P0 *)this)->tmp_commit));
+#ifdef VAR_RANGES
+ logval("_commit_sum", ((int)now._commit_sum));
+#endif
+ ;
+ /* merge: commit_count[((prev_off%4)/(4/2))] = tmp_commit(26, 21, 26) */
+ reached[0][21] = 1;
+ (trpt+1)->bup.ovals[2] = ((int)now.commit_count[ Index(((((int)((P0 *)this)->prev_off)%4)/(4/2)), 2) ]);
+ now.commit_count[ Index(((((P0 *)this)->prev_off%4)/(4/2)), 2) ] = ((int)((P0 *)this)->tmp_commit);
+#ifdef VAR_RANGES
+ logval("commit_count[((switcher:prev_off%4)/(4/2))]", ((int)now.commit_count[ Index(((((int)((P0 *)this)->prev_off)%4)/(4/2)), 2) ]));
+#endif
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 60: /* STATE 22 - line 99 "pan.___" - [((((((prev_off/4)*4)/2)+(4/2))-tmp_commit))] (30:0:4 - 1) */
+ IfNotBlocked
+ reached[0][22] = 1;
+ if (!((((((((int)((P0 *)this)->prev_off)/4)*4)/2)+(4/2))-((int)((P0 *)this)->tmp_commit))))
+ continue;
+ /* dead 1: prev_off */ (trpt+1)->bup.ovals = grab_ints(4);
+ (trpt+1)->bup.ovals[0] = ((P0 *)this)->prev_off;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P0 *)this)->prev_off = 0;
+ /* dead 1: tmp_commit */ (trpt+1)->bup.ovals[1] = ((P0 *)this)->tmp_commit;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P0 *)this)->tmp_commit = 0;
+ /* merge: deliver = 1(30, 23, 30) */
+ reached[0][23] = 1;
+ (trpt+1)->bup.ovals[2] = ((int)deliver);
+ deliver = 1;
+#ifdef VAR_RANGES
+ logval("deliver", ((int)deliver));
+#endif
+ ;
+ /* merge: .(goto)(30, 27, 30) */
+ reached[0][27] = 1;
+ ;
+ /* merge: refcount = (refcount-1)(30, 28, 30) */
+ reached[0][28] = 1;
+ (trpt+1)->bup.ovals[3] = ((int)now.refcount);
+ now.refcount = (((int)now.refcount)-1);
+#ifdef VAR_RANGES
+ logval("refcount", ((int)now.refcount));
+#endif
+ ;
+ _m = 3; goto P999; /* 3 */
+ case 61: /* STATE 27 - line 104 "pan.___" - [.(goto)] (0:30:1 - 2) */
+ IfNotBlocked
+ reached[0][27] = 1;
+ ;
+ /* merge: refcount = (refcount-1)(30, 28, 30) */
+ reached[0][28] = 1;
+ (trpt+1)->bup.oval = ((int)now.refcount);
+ now.refcount = (((int)now.refcount)-1);
+#ifdef VAR_RANGES
+ logval("refcount", ((int)now.refcount));
+#endif
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 62: /* STATE 25 - line 102 "pan.___" - [(1)] (30:0:1 - 1) */
+ IfNotBlocked
+ reached[0][25] = 1;
+ if (!(1))
+ continue;
+ /* merge: .(goto)(30, 27, 30) */
+ reached[0][27] = 1;
+ ;
+ /* merge: refcount = (refcount-1)(30, 28, 30) */
+ reached[0][28] = 1;
+ (trpt+1)->bup.oval = ((int)now.refcount);
+ now.refcount = (((int)now.refcount)-1);
+#ifdef VAR_RANGES
+ logval("refcount", ((int)now.refcount));
+#endif
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 63: /* STATE 31 - line 108 "pan.___" - [-end-] (0:0:0 - 1) */
+ IfNotBlocked
+ reached[0][31] = 1;
+ if (!delproc(1, II)) continue;
+ _m = 3; goto P999; /* 0 */
+ case _T5: /* np_ */
+ if (!((!(trpt->o_pm&4) && !(trpt->tau&128))))
+ continue;
+ /* else fall through */
+ case _T2: /* true */
+ _m = 3; goto P999;
+#undef rand
+ }
+
--- /dev/null
+/* LTTng ltt-tracer.c atomic lockless buffering scheme Promela model v2
+ * Created for the Spin validator.
+ * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ * October 2008
+
+ * TODO : create test cases that will generate an overflow on the offset and
+ * counter type. Counter types smaller than a byte should be used.
+
+ * Promela only has unsigned char, no signed char.
+ * Because detection of difference < 0 depends on a signed type, but we want
+ * compactness, check also for the values being higher than half of the unsigned
+ * char range (and consider them negative). The model, by design, does not use
+ * offsets or counts higher than 127 because we would then have to use a larger
+ * type (short or int).
+ */
+#define HALF_UCHAR (255/2)
+
+/* NUMPROCS 4 : causes event loss with some reader timings.
+ * e.g. 3 events, 1 switch, 1 event (lost, buffer full), read 1 subbuffer
+ */
+#define NUMPROCS 4
+
+/* NUMPROCS 3 : does not cause event loss because buffers are big enough.
+ * #define NUMPROCS 3
+ * e.g. 3 events, 1 switch, read 1 subbuffer
+ */
+
+#define NUMSWITCH 1
+#define BUFSIZE 4
+#define NR_SUBBUFS 2
+#define SUBBUF_SIZE (BUFSIZE / NR_SUBBUFS)
+
+/* Writer counters
+*/
+byte write_off = 0;
+byte commit_count[NR_SUBBUFS];
+
+/* <formal_verif> */
+byte _commit_sum;
+/* </formal_verif> */
+
+/* Reader counters
+*/
+byte read_off = 0;
+
+byte events_lost = 0;
+byte refcount = 0;
+
+bool deliver = 0;
+
+/* buffer slot in-use bit. Detects racy use (more than a single process
+ * accessing a slot at any given step).
+ */
+bool buffer_use[BUFSIZE];
+
+/* Proceed to a sub-subber switch is needed.
+ * Used in a periodical timer interrupt to fill and ship the current subbuffer
+ * to the reader so we can guarantee a steady flow. If a subbuffer is
+ * completely empty, do not switch.
+ * Also used as "finalize" operation to complete the last subbuffer after
+ * all writers have finished so the last subbuffer can be read by the reader.
+ */
+proctype switcher()
+{
+ byte prev_off, new_off, tmp_commit;
+ byte size;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ size = SUBBUF_SIZE - (prev_off % SUBBUF_SIZE);
+ new_off = prev_off + size;
+ if
+ :: (new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR)
+ || size == SUBBUF_SIZE ->
+ refcount = refcount - 1;
+ goto not_needed;
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ }
+
+ atomic {
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ /* <formal_verif> */
+ _commit_sum = _commit_sum - commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE]
+ + tmp_commit;
+ /* </formal_verif> */
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ refcount = refcount - 1;
+ }
+not_needed:
+ skip;
+}
+
+/* tracer
+ * Writes 1 byte of information in the buffer at the current
+ * "write_off" position and then increment the commit_count of the sub-buffer
+ * the information has been written to.
+ */
+proctype tracer()
+{
+ byte size = 1;
+ byte prev_off, new_off, tmp_commit;
+ byte i, j;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ new_off = prev_off + size;
+ }
+ atomic {
+ if
+ :: new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR ->
+ goto lost
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ i = 0;
+ do
+ :: i < size ->
+ assert(buffer_use[(prev_off + i) % BUFSIZE] == 0);
+ buffer_use[(prev_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= size -> break
+ od;
+ }
+
+ /* writing to buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < size ->
+ buffer_use[(prev_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= size -> break
+ od;
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ /* <formal_verif> */
+ _commit_sum = _commit_sum - commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE]
+ + tmp_commit;
+ /* </formal_verif> */
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ }
+ atomic {
+ goto end;
+lost:
+ events_lost++;
+end:
+ refcount = refcount - 1;
+ }
+}
+
+/* reader
+ * Read the information sub-buffer per sub-buffer when available.
+ *
+ * Reads the information as soon as it is ready, or may be delayed by
+ * an asynchronous delivery. Being modeled as a process insures all cases
+ * (scheduled very quickly or very late, causing event loss) are covered.
+ * Only one reader per buffer (normally ensured by a mutex). This is modeled
+ * by using a single reader process.
+ */
+proctype reader()
+{
+ byte i, j;
+
+ do
+ :: (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) > 0
+ && (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) < HALF_UCHAR
+ && (commit_count[(read_off % BUFSIZE) / SUBBUF_SIZE]
+ - SUBBUF_SIZE - (((read_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS)
+ == 0) ->
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ assert(buffer_use[(read_off + i) % BUFSIZE] == 0);
+ buffer_use[(read_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ }
+
+ /* reading from buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ buffer_use[(read_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ read_off = read_off + SUBBUF_SIZE;
+ }
+ :: read_off >= (NUMPROCS - events_lost) -> break;
+ od;
+}
+
+/* Waits for all tracer and switcher processes to finish before finalizing
+ * the buffer. Only after that will the reader be allowed to read the
+ * last subbuffer.
+ */
+proctype cleaner()
+{
+ atomic {
+ do
+ :: refcount == 0 ->
+ refcount = refcount + 1;
+ run switcher(); /* Finalize the last sub-buffer so it can be read. */
+ break;
+ od;
+ }
+}
+
+init {
+ byte i = 0;
+ byte j = 0;
+ byte sum = 0;
+ byte commit_sum = 0;
+
+ atomic {
+ i = 0;
+ do
+ :: i < NR_SUBBUFS ->
+ commit_count[i] = 0;
+ i++
+ :: i >= NR_SUBBUFS -> break
+ od;
+ /* <formal_verif> */
+ _commit_sum = 0;
+ /* </formal_verif> */
+ i = 0;
+ do
+ :: i < BUFSIZE ->
+ buffer_use[i] = 0;
+ i++
+ :: i >= BUFSIZE -> break
+ od;
+ run reader();
+ run cleaner();
+ i = 0;
+ do
+ :: i < NUMPROCS ->
+ refcount = refcount + 1;
+ run tracer();
+ i++
+ :: i >= NUMPROCS -> break
+ od;
+ i = 0;
+ do
+ :: i < NUMSWITCH ->
+ refcount = refcount + 1;
+ run switcher();
+ i++
+ :: i >= NUMSWITCH -> break
+ od;
+ _commit_sum = 0;
+ }
+
+ /* Assertions.
+ */
+ atomic {
+ /* The writer head must always be superior or equal to the reader head.
+ */
+ //assert(write_off - read_off >= 0 && write_off - read_off < HALF_UCHAR);
+ /* The sum of all subbuffer commit counts must always be lower or equal
+ * to the writer head, because space must be reserved before it is
+ * written to and then committed.
+ */
+ assert(write_off - _commit_sum >= 0 && write_off - _commit_sum < HALF_UCHAR);
+
+ /* If we have less writers than the buffer space available, we should
+ * not loose events
+ */
+ assert(NUMPROCS + NUMSWITCH > BUFSIZE || events_lost == 0);
+ }
+}
+
+
--- /dev/null
+#define p (write_off - read_off >= 0)
+#define q (write_off - read_off < HALF_UCHAR)
+
+ /*
+ * Formula As Typed: [] (p && q)
+ * The Never Claim Below Corresponds
+ * To The Negated Formula !([] (p && q))
+ * (formalizing violations of the original)
+ */
+
+never { /* !([] (p && q)) */
+T0_init:
+ if
+ :: (((! ((p))) || (! ((q))))) -> goto accept_all
+ :: (1) -> goto T0_init
+ fi;
+accept_all:
+ skip
+}
+
+#ifdef NOTES
+Use Load to open a file or a template.
+#endif
+#ifdef RESULT
+warning: for p.o. reduction to be valid the never claim must be stutter-invariant
+(never claims generated from LTL formulae are stutter-invariant)
+depth 0: Claim reached state 5 (line 321)
+Running verification -- waiting for output
+ (kill background process 'pan' to abort run)
+ (use /bin/ps to find pid; then: kill -2 pid)
+
+#endif
--- /dev/null
+warning: for p.o. reduction to be valid the never claim must be stutter-invariant
+(never claims generated from LTL formulae are stutter-invariant)
+depth 0: Claim reached state 5 (line 321)
+Depth= 201 States= 1e+06 Transitions= 3.11e+06 Memory= 79.063 t= 25.4 R= 4e+04
+Depth= 201 States= 2e+06 Transitions= 6.44e+06 Memory= 156.895 t= 46.1 R= 4e+04
+pan: resizing hashtable to -w21.. done
+
+(Spin Version 5.1.6 -- 9 May 2008)
+ + Partial Order Reduction
+
+Full statespace search for:
+ never claim +
+ assertion violations + (if within scope of claim)
+ acceptance cycles + (fairness disabled)
+ invalid end states - (disabled by never claim)
+
+State-vector 100 byte, depth reached 203, errors: 0
+ 2590821 states, stored
+ 5924281 states, matched
+ 8515102 transitions (= stored+matched)
+ 9636364 atomic steps
+hash conflicts: 6260639 (resolved)
+
+Stats on memory usage (in Megabytes):
+ 286.613 equivalent memory usage for states (stored*(State-vector + overhead))
+ 202.768 actual memory usage for states (compression: 70.75%)
+ state-vector as stored = 66 byte + 16 byte overhead
+ 8.000 memory used for hash table (-w21)
+ 0.305 memory used for DFS stack (-m10000)
+ 210.891 total actual memory usage
+
+unreached in proctype switcher
+ (0 of 31 states)
+unreached in proctype tracer
+ (0 of 51 states)
+unreached in proctype reader
+ (0 of 29 states)
+unreached in proctype cleaner
+ (0 of 9 states)
+unreached in proctype :init:
+ (0 of 47 states)
+unreached in proctype :never:
+ line 326, "pan.___", state 8, "-end-"
+ (1 of 8 states)
+
+pan: elapsed time 56.4 seconds
+pan: rate 45960.99 states/second
+pan: avg transition delay 6.62e-06 usec
+23.05user 0.18system 0:56.38elapsed 41%CPU (0avgtext+0avgdata 0maxresident)k
+0inputs+0outputs (0major+54128minor)pagefaults 0swaps
--- /dev/null
+#ifdef PEG
+struct T_SRC {
+ char *fl; int ln;
+} T_SRC[NTRANS];
+
+void
+tr_2_src(int m, char *file, int ln)
+{ T_SRC[m].fl = file;
+ T_SRC[m].ln = ln;
+}
+
+void
+putpeg(int n, int m)
+{ printf("%5d trans %4d ", m, n);
+ printf("file %s line %3d\n",
+ T_SRC[n].fl, T_SRC[n].ln);
+}
+#endif
+
+void
+settable(void)
+{ Trans *T;
+ Trans *settr(int, int, int, int, int, char *, int, int, int);
+
+ trans = (Trans ***) emalloc(7*sizeof(Trans **));
+
+ /* proctype 5: :never: */
+
+ trans[5] = (Trans **) emalloc(15*sizeof(Trans *));
+
+ T = trans[5][5] = settr(167,0,0,0,0,"IF", 0, 2, 0);
+ T = T->nxt = settr(167,0,1,0,0,"IF", 0, 2, 0);
+ T->nxt = settr(167,0,3,0,0,"IF", 0, 2, 0);
+ trans[5][1] = settr(163,0,13,3,0,"((((4+1)<=4)&&(events_lost!=0)))", 1, 2, 0);
+ trans[5][2] = settr(164,0,13,1,0,"goto accept_all", 0, 2, 0);
+ trans[5][6] = settr(168,0,11,1,0,".(goto)", 0, 2, 0);
+ trans[5][3] = settr(165,0,11,4,0,"(((4+1)<=4))", 0, 2, 0);
+ trans[5][4] = settr(166,0,11,1,0,"goto T0_S3", 0, 2, 0);
+ T = trans[5][11] = settr(173,0,0,0,0,"IF", 0, 2, 0);
+ T = T->nxt = settr(173,0,7,0,0,"IF", 0, 2, 0);
+ T->nxt = settr(173,0,9,0,0,"IF", 0, 2, 0);
+ trans[5][7] = settr(169,0,13,5,0,"((events_lost!=0))", 1, 2, 0);
+ trans[5][8] = settr(170,0,13,1,0,"goto accept_all", 0, 2, 0);
+ trans[5][12] = settr(174,0,13,1,0,".(goto)", 0, 2, 0);
+ trans[5][9] = settr(171,0,11,1,0,"(1)", 0, 2, 0);
+ trans[5][10] = settr(172,0,11,1,0,"goto T0_S3", 0, 2, 0);
+ trans[5][13] = settr(175,0,14,1,0,"(1)", 0, 2, 0);
+ trans[5][14] = settr(176,0,0,6,6,"-end-", 0, 3500, 0);
+
+ /* proctype 4: :init: */
+
+ trans[4] = (Trans **) emalloc(44*sizeof(Trans *));
+
+ T = trans[ 4][42] = settr(161,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(161,2,1,0,0,"ATOMIC", 1, 2, 0);
+ trans[4][1] = settr(120,2,7,7,7,"i = 0", 1, 2, 0);
+ trans[4][8] = settr(127,2,7,1,0,".(goto)", 1, 2, 0);
+ T = trans[4][7] = settr(126,2,0,0,0,"DO", 1, 2, 0);
+ T = T->nxt = settr(126,2,2,0,0,"DO", 1, 2, 0);
+ T->nxt = settr(126,2,5,0,0,"DO", 1, 2, 0);
+ trans[4][2] = settr(121,2,7,8,8,"((i<2))", 1, 2, 0); /* m: 3 -> 7,0 */
+ reached4[3] = 1;
+ trans[4][3] = settr(0,0,0,0,0,"commit_count[i] = 0",0,0,0);
+ trans[4][4] = settr(0,0,0,0,0,"i = (i+1)",0,0,0);
+ trans[4][5] = settr(124,2,17,9,9,"((i>=2))", 1, 2, 0); /* m: 10 -> 17,0 */
+ reached4[10] = 1;
+ trans[4][6] = settr(125,2,10,1,0,"goto :b6", 1, 2, 0); /* m: 10 -> 0,17 */
+ reached4[10] = 1;
+ trans[4][9] = settr(128,2,10,1,0,"break", 1, 2, 0);
+ trans[4][10] = settr(129,2,17,10,10,"_commit_sum = 0", 1, 2, 0); /* m: 11 -> 0,17 */
+ reached4[11] = 1;
+ trans[4][11] = settr(0,0,0,0,0,"i = 0",0,0,0);
+ trans[4][18] = settr(137,2,17,1,0,".(goto)", 1, 2, 0);
+ T = trans[4][17] = settr(136,2,0,0,0,"DO", 1, 2, 0);
+ T = T->nxt = settr(136,2,12,0,0,"DO", 1, 2, 0);
+ T->nxt = settr(136,2,15,0,0,"DO", 1, 2, 0);
+ trans[4][12] = settr(131,2,17,11,11,"((i<4))", 1, 2, 0); /* m: 13 -> 17,0 */
+ reached4[13] = 1;
+ trans[4][13] = settr(0,0,0,0,0,"buffer_use[i] = 0",0,0,0);
+ trans[4][14] = settr(0,0,0,0,0,"i = (i+1)",0,0,0);
+ trans[4][15] = settr(134,2,20,12,12,"((i>=4))", 1, 2, 0);
+ trans[4][16] = settr(135,2,20,1,0,"goto :b7", 1, 2, 0);
+ trans[4][19] = settr(138,2,20,1,0,"break", 1, 2, 0);
+ trans[4][20] = settr(139,2,21,13,13,"(run reader())", 1, 2, 0);
+ trans[4][21] = settr(140,2,29,14,14,"(run cleaner())", 1, 2, 0); /* m: 22 -> 29,0 */
+ reached4[22] = 1;
+ trans[4][22] = settr(0,0,0,0,0,"i = 0",0,0,0);
+ trans[4][30] = settr(149,2,29,1,0,".(goto)", 1, 2, 0);
+ T = trans[4][29] = settr(148,2,0,0,0,"DO", 1, 2, 0);
+ T = T->nxt = settr(148,2,23,0,0,"DO", 1, 2, 0);
+ T->nxt = settr(148,2,27,0,0,"DO", 1, 2, 0);
+ trans[4][23] = settr(142,2,25,15,15,"((i<4))", 1, 2, 0); /* m: 24 -> 25,0 */
+ reached4[24] = 1;
+ trans[4][24] = settr(0,0,0,0,0,"refcount = (refcount+1)",0,0,0);
+ trans[4][25] = settr(144,2,29,16,16,"(run tracer())", 1, 2, 0); /* m: 26 -> 29,0 */
+ reached4[26] = 1;
+ trans[4][26] = settr(0,0,0,0,0,"i = (i+1)",0,0,0);
+ trans[4][27] = settr(146,2,39,17,17,"((i>=4))", 1, 2, 0); /* m: 32 -> 39,0 */
+ reached4[32] = 1;
+ trans[4][28] = settr(147,2,32,1,0,"goto :b8", 1, 2, 0); /* m: 32 -> 0,39 */
+ reached4[32] = 1;
+ trans[4][31] = settr(150,2,32,1,0,"break", 1, 2, 0);
+ trans[4][32] = settr(151,2,39,18,18,"i = 0", 1, 2, 0);
+ trans[4][40] = settr(159,2,39,1,0,".(goto)", 1, 2, 0);
+ T = trans[4][39] = settr(158,2,0,0,0,"DO", 1, 2, 0);
+ T = T->nxt = settr(158,2,33,0,0,"DO", 1, 2, 0);
+ T->nxt = settr(158,2,37,0,0,"DO", 1, 2, 0);
+ trans[4][33] = settr(152,2,35,19,19,"((i<1))", 1, 2, 0); /* m: 34 -> 35,0 */
+ reached4[34] = 1;
+ trans[4][34] = settr(0,0,0,0,0,"refcount = (refcount+1)",0,0,0);
+ trans[4][35] = settr(154,2,39,20,20,"(run switcher())", 1, 2, 0); /* m: 36 -> 39,0 */
+ reached4[36] = 1;
+ trans[4][36] = settr(0,0,0,0,0,"i = (i+1)",0,0,0);
+ trans[4][37] = settr(156,2,41,21,21,"((i>=1))", 1, 2, 0); /* m: 38 -> 41,0 */
+ reached4[38] = 1;
+ trans[4][38] = settr(157,2,41,1,0,"goto :b9", 1, 2, 0);
+ trans[4][41] = settr(160,0,43,1,0,"break", 1, 2, 0);
+ trans[4][43] = settr(162,0,0,22,22,"-end-", 0, 3500, 0);
+
+ /* proctype 3: cleaner */
+
+ trans[3] = (Trans **) emalloc(10*sizeof(Trans *));
+
+ T = trans[ 3][8] = settr(118,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(118,2,5,0,0,"ATOMIC", 1, 2, 0);
+ trans[3][6] = settr(116,2,5,1,0,".(goto)", 1, 2, 0);
+ T = trans[3][5] = settr(115,2,0,0,0,"DO", 1, 2, 0);
+ T->nxt = settr(115,2,1,0,0,"DO", 1, 2, 0);
+ trans[3][1] = settr(111,2,3,23,23,"((refcount==0))", 1, 2, 0); /* m: 2 -> 3,0 */
+ reached3[2] = 1;
+ trans[3][2] = settr(0,0,0,0,0,"refcount = (refcount+1)",0,0,0);
+ trans[3][3] = settr(113,2,7,24,24,"(run switcher())", 1, 2, 0); /* m: 4 -> 7,0 */
+ reached3[4] = 1;
+ trans[3][4] = settr(114,2,7,1,0,"goto :b5", 1, 2, 0);
+ trans[3][7] = settr(117,0,9,1,0,"break", 1, 2, 0);
+ trans[3][9] = settr(119,0,0,25,25,"-end-", 0, 3500, 0);
+
+ /* proctype 2: reader */
+
+ trans[2] = (Trans **) emalloc(30*sizeof(Trans *));
+
+ trans[2][27] = settr(108,0,26,1,0,".(goto)", 0, 2, 0);
+ T = trans[2][26] = settr(107,0,0,0,0,"DO", 0, 2, 0);
+ T = T->nxt = settr(107,0,1,0,0,"DO", 0, 2, 0);
+ T->nxt = settr(107,0,24,0,0,"DO", 0, 2, 0);
+ trans[2][1] = settr(82,0,12,26,0,"((((((write_off/(4/2))-(read_off/(4/2)))>0)&&(((write_off/(4/2))-(read_off/(4/2)))<(255/2)))&&(((commit_count[((read_off%4)/(4/2))]-(4/2))-(((read_off/4)*4)/2))==0)))", 1, 2, 0);
+ T = trans[ 2][12] = settr(93,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(93,2,2,0,0,"ATOMIC", 1, 2, 0);
+ trans[2][2] = settr(83,2,9,27,27,"i = 0", 1, 2, 0);
+ trans[2][10] = settr(91,2,9,1,0,".(goto)", 1, 2, 0);
+ T = trans[2][9] = settr(90,2,0,0,0,"DO", 1, 2, 0);
+ T = T->nxt = settr(90,2,3,0,0,"DO", 1, 2, 0);
+ T->nxt = settr(90,2,7,0,0,"DO", 1, 2, 0);
+ trans[2][3] = settr(84,2,9,28,28,"((i<(4/2)))", 1, 2, 0); /* m: 4 -> 9,0 */
+ reached2[4] = 1;
+ trans[2][4] = settr(0,0,0,0,0,"assert((buffer_use[((read_off+i)%4)]==0))",0,0,0);
+ trans[2][5] = settr(0,0,0,0,0,"buffer_use[((read_off+i)%4)] = 1",0,0,0);
+ trans[2][6] = settr(0,0,0,0,0,"i = (i+1)",0,0,0);
+ trans[2][7] = settr(88,2,11,29,29,"((i>=(4/2)))", 1, 2, 0); /* m: 8 -> 11,0 */
+ reached2[8] = 1;
+ trans[2][8] = settr(89,2,11,1,0,"goto :b3", 1, 2, 0);
+ trans[2][11] = settr(92,0,23,1,0,"break", 1, 2, 0);
+ T = trans[ 2][23] = settr(104,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(104,2,13,0,0,"ATOMIC", 1, 2, 0);
+ trans[2][13] = /* c */ settr(94,2,19,27,27,"i = 0", 1, 2, 0);
+ trans[2][20] = settr(101,2,19,1,0,".(goto)", 1, 2, 0);
+ T = trans[2][19] = settr(100,2,0,0,0,"DO", 1, 2, 0);
+ T = T->nxt = settr(100,2,14,0,0,"DO", 1, 2, 0);
+ T->nxt = settr(100,2,17,0,0,"DO", 1, 2, 0);
+ trans[2][14] = settr(95,2,19,30,30,"((i<(4/2)))", 1, 2, 0); /* m: 15 -> 19,0 */
+ reached2[15] = 1;
+ trans[2][15] = settr(0,0,0,0,0,"buffer_use[((read_off+i)%4)] = 0",0,0,0);
+ trans[2][16] = settr(0,0,0,0,0,"i = (i+1)",0,0,0);
+ trans[2][17] = settr(98,2,21,31,31,"((i>=(4/2)))", 1, 2, 0);
+ trans[2][18] = settr(99,2,21,1,0,"goto :b4", 1, 2, 0);
+ trans[2][21] = settr(102,2,22,1,0,"break", 1, 2, 0);
+ trans[2][22] = settr(103,0,26,32,32,"read_off = (read_off+(4/2))", 1, 2, 0);
+ trans[2][24] = settr(105,0,29,33,0,"((read_off>=(4-events_lost)))", 1, 2, 0);
+ trans[2][25] = settr(106,0,29,1,0,"goto :b2", 0, 2, 0);
+ trans[2][28] = settr(109,0,29,1,0,"break", 0, 2, 0);
+ trans[2][29] = settr(110,0,0,34,34,"-end-", 0, 3500, 0);
+
+ /* proctype 1: tracer */
+
+ trans[1] = (Trans **) emalloc(52*sizeof(Trans *));
+
+ T = trans[ 1][3] = settr(33,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(33,2,1,0,0,"ATOMIC", 1, 2, 0);
+ trans[1][1] = settr(31,4,10,35,35,"prev_off = write_off", 1, 2, 0); /* m: 2 -> 0,10 */
+ reached1[2] = 1;
+ trans[1][2] = settr(0,0,0,0,0,"new_off = (prev_off+size)",0,0,0);
+ T = trans[ 1][10] = settr(40,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(40,2,8,0,0,"ATOMIC", 1, 2, 0);
+ T = trans[1][8] = settr(38,2,0,0,0,"IF", 1, 2, 0);
+ T = T->nxt = settr(38,2,4,0,0,"IF", 1, 2, 0);
+ T->nxt = settr(38,2,6,0,0,"IF", 1, 2, 0);
+ trans[1][4] = settr(34,2,48,36,36,"((((new_off-read_off)>4)&&((new_off-read_off)<(255/2))))", 1, 2, 0);
+ trans[1][5] = settr(35,2,48,1,0,"goto lost", 1, 2, 0);
+ trans[1][9] = settr(39,0,27,1,0,".(goto)", 1, 2, 0);
+ trans[1][6] = settr(36,2,7,2,0,"else", 1, 2, 0);
+ trans[1][7] = settr(37,4,27,37,37,"(1)", 1, 2, 0); /* m: 9 -> 27,0 */
+ reached1[9] = 1;
+ T = trans[ 1][27] = settr(57,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(57,2,15,0,0,"ATOMIC", 1, 2, 0);
+ T = trans[1][15] = settr(45,2,0,0,0,"IF", 1, 2, 0);
+ T = T->nxt = settr(45,2,11,0,0,"IF", 1, 2, 0);
+ T->nxt = settr(45,2,13,0,0,"IF", 1, 2, 0);
+ trans[1][11] = settr(41,4,3,38,38,"((prev_off!=write_off))", 1, 2, 0); /* m: 12 -> 3,0 */
+ reached1[12] = 1;
+ trans[1][12] = settr(42,0,3,1,0,"goto cmpxchg_loop", 1, 2, 0);
+ trans[1][16] = settr(46,2,17,1,0,".(goto)", 1, 2, 0); /* m: 17 -> 0,24 */
+ reached1[17] = 1;
+ trans[1][13] = settr(43,2,14,2,0,"else", 1, 2, 0);
+ trans[1][14] = settr(44,2,24,39,39,"write_off = new_off", 1, 2, 0); /* m: 17 -> 0,24 */
+ reached1[17] = 1;
+ trans[1][17] = settr(47,2,24,40,40,"i = 0", 1, 2, 0);
+ trans[1][25] = settr(55,2,24,1,0,".(goto)", 1, 2, 0);
+ T = trans[1][24] = settr(54,2,0,0,0,"DO", 1, 2, 0);
+ T = T->nxt = settr(54,2,18,0,0,"DO", 1, 2, 0);
+ T->nxt = settr(54,2,22,0,0,"DO", 1, 2, 0);
+ trans[1][18] = settr(48,2,24,41,41,"((i<size))", 1, 2, 0); /* m: 19 -> 24,0 */
+ reached1[19] = 1;
+ trans[1][19] = settr(0,0,0,0,0,"assert((buffer_use[((prev_off+i)%4)]==0))",0,0,0);
+ trans[1][20] = settr(0,0,0,0,0,"buffer_use[((prev_off+i)%4)] = 1",0,0,0);
+ trans[1][21] = settr(0,0,0,0,0,"i = (i+1)",0,0,0);
+ trans[1][22] = settr(52,2,26,42,42,"((i>=size))", 1, 2, 0); /* m: 23 -> 26,0 */
+ reached1[23] = 1;
+ trans[1][23] = settr(53,2,26,1,0,"goto :b0", 1, 2, 0);
+ trans[1][26] = settr(56,0,46,1,0,"break", 1, 2, 0);
+ T = trans[ 1][46] = settr(76,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(76,2,28,0,0,"ATOMIC", 1, 2, 0);
+ trans[1][28] = settr(58,2,34,43,43,"i = 0", 1, 2, 0);
+ trans[1][35] = settr(65,2,34,1,0,".(goto)", 1, 2, 0);
+ T = trans[1][34] = settr(64,2,0,0,0,"DO", 1, 2, 0);
+ T = T->nxt = settr(64,2,29,0,0,"DO", 1, 2, 0);
+ T->nxt = settr(64,2,32,0,0,"DO", 1, 2, 0);
+ trans[1][29] = settr(59,2,34,44,44,"((i<size))", 1, 2, 0); /* m: 30 -> 34,0 */
+ reached1[30] = 1;
+ trans[1][30] = settr(0,0,0,0,0,"buffer_use[((prev_off+i)%4)] = 0",0,0,0);
+ trans[1][31] = settr(0,0,0,0,0,"i = (i+1)",0,0,0);
+ trans[1][32] = settr(62,2,44,45,45,"((i>=size))", 1, 2, 0); /* m: 37 -> 44,0 */
+ reached1[37] = 1;
+ trans[1][33] = settr(63,2,37,1,0,"goto :b1", 1, 2, 0); /* m: 37 -> 0,44 */
+ reached1[37] = 1;
+ trans[1][36] = settr(66,2,37,1,0,"break", 1, 2, 0);
+ trans[1][37] = settr(67,2,44,46,46,"tmp_commit = (commit_count[((prev_off%4)/(4/2))]+size)", 1, 2, 0); /* m: 38 -> 0,44 */
+ reached1[38] = 1;
+ trans[1][38] = settr(0,0,0,0,0,"_commit_sum = ((_commit_sum-commit_count[((prev_off%4)/(4/2))])+tmp_commit)",0,0,0);
+ trans[1][39] = settr(0,0,0,0,0,"commit_count[((prev_off%4)/(4/2))] = tmp_commit",0,0,0);
+ T = trans[1][44] = settr(74,2,0,0,0,"IF", 1, 2, 0);
+ T = T->nxt = settr(74,2,40,0,0,"IF", 1, 2, 0);
+ T->nxt = settr(74,2,42,0,0,"IF", 1, 2, 0);
+ trans[1][40] = settr(70,4,50,47,47,"((((((prev_off/4)*4)/2)+(4/2))-tmp_commit))", 1, 2, 0); /* m: 41 -> 50,0 */
+ reached1[41] = 1;
+ trans[1][41] = settr(0,0,0,0,0,"deliver = 1",0,0,0);
+ trans[1][45] = settr(75,0,50,48,48,".(goto)", 1, 2, 0);
+ trans[1][42] = settr(72,2,43,2,0,"else", 1, 2, 0);
+ trans[1][43] = settr(73,4,50,49,49,"(1)", 1, 2, 0); /* m: 45 -> 50,0 */
+ reached1[45] = 1;
+ T = trans[ 1][50] = settr(80,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(80,2,47,0,0,"ATOMIC", 1, 2, 0);
+ trans[1][47] = settr(77,2,49,1,0,"goto end", 1, 2, 0);
+ trans[1][48] = settr(78,2,49,50,50,"events_lost = (events_lost+1)", 1, 2, 0);
+ trans[1][49] = settr(79,0,51,51,51,"refcount = (refcount-1)", 1, 2, 0);
+ trans[1][51] = settr(81,0,0,52,52,"-end-", 0, 3500, 0);
+
+ /* proctype 0: switcher */
+
+ trans[0] = (Trans **) emalloc(32*sizeof(Trans *));
+
+ T = trans[ 0][11] = settr(10,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(10,2,1,0,0,"ATOMIC", 1, 2, 0);
+ trans[0][1] = settr(0,2,9,53,53,"prev_off = write_off", 1, 2, 0); /* m: 2 -> 0,9 */
+ reached0[2] = 1;
+ trans[0][2] = settr(0,0,0,0,0,"size = ((4/2)-(prev_off%(4/2)))",0,0,0);
+ trans[0][3] = settr(0,0,0,0,0,"new_off = (prev_off+size)",0,0,0);
+ T = trans[0][9] = settr(8,2,0,0,0,"IF", 1, 2, 0);
+ T = T->nxt = settr(8,2,4,0,0,"IF", 1, 2, 0);
+ T->nxt = settr(8,2,7,0,0,"IF", 1, 2, 0);
+ trans[0][4] = settr(3,4,30,54,54,"(((((new_off-read_off)>4)&&((new_off-read_off)<(255/2)))||(size==(4/2))))", 1, 2, 0); /* m: 5 -> 30,0 */
+ reached0[5] = 1;
+ trans[0][5] = settr(0,0,0,0,0,"refcount = (refcount-1)",0,0,0);
+ trans[0][6] = settr(5,0,30,1,0,"goto not_needed", 1, 2, 0);
+ trans[0][10] = settr(9,0,18,1,0,".(goto)", 1, 2, 0);
+ trans[0][7] = settr(6,2,8,2,0,"else", 1, 2, 0);
+ trans[0][8] = settr(7,4,18,55,55,"(1)", 1, 2, 0); /* m: 10 -> 18,0 */
+ reached0[10] = 1;
+ T = trans[ 0][18] = settr(17,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(17,2,16,0,0,"ATOMIC", 1, 2, 0);
+ T = trans[0][16] = settr(15,2,0,0,0,"IF", 1, 2, 0);
+ T = T->nxt = settr(15,2,12,0,0,"IF", 1, 2, 0);
+ T->nxt = settr(15,2,14,0,0,"IF", 1, 2, 0);
+ trans[0][12] = settr(11,4,11,56,56,"((prev_off!=write_off))", 1, 2, 0); /* m: 13 -> 11,0 */
+ reached0[13] = 1;
+ trans[0][13] = settr(12,0,11,1,0,"goto cmpxchg_loop", 1, 2, 0);
+ trans[0][17] = settr(16,0,29,57,57,".(goto)", 1, 2, 0);
+ trans[0][14] = settr(13,2,15,2,0,"else", 1, 2, 0);
+ trans[0][15] = settr(14,4,29,58,58,"write_off = new_off", 1, 2, 0); /* m: 17 -> 0,29 */
+ reached0[17] = 1;
+ T = trans[ 0][29] = settr(28,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(28,2,19,0,0,"ATOMIC", 1, 2, 0);
+ trans[0][19] = settr(18,2,26,59,59,"tmp_commit = (commit_count[((prev_off%4)/(4/2))]+size)", 1, 2, 0); /* m: 20 -> 0,26 */
+ reached0[20] = 1;
+ trans[0][20] = settr(0,0,0,0,0,"_commit_sum = ((_commit_sum-commit_count[((prev_off%4)/(4/2))])+tmp_commit)",0,0,0);
+ trans[0][21] = settr(0,0,0,0,0,"commit_count[((prev_off%4)/(4/2))] = tmp_commit",0,0,0);
+ T = trans[0][26] = settr(25,2,0,0,0,"IF", 1, 2, 0);
+ T = T->nxt = settr(25,2,22,0,0,"IF", 1, 2, 0);
+ T->nxt = settr(25,2,24,0,0,"IF", 1, 2, 0);
+ trans[0][22] = settr(21,4,30,60,60,"((((((prev_off/4)*4)/2)+(4/2))-tmp_commit))", 1, 2, 0); /* m: 23 -> 30,0 */
+ reached0[23] = 1;
+ trans[0][23] = settr(0,0,0,0,0,"deliver = 1",0,0,0);
+ trans[0][27] = settr(26,4,30,61,61,".(goto)", 1, 2, 0); /* m: 28 -> 0,30 */
+ reached0[28] = 1;
+ trans[0][24] = settr(23,2,25,2,0,"else", 1, 2, 0);
+ trans[0][25] = settr(24,4,30,62,62,"(1)", 1, 2, 0); /* m: 27 -> 30,0 */
+ reached0[27] = 1;
+ trans[0][28] = settr(0,0,0,0,0,"refcount = (refcount-1)",0,0,0);
+ trans[0][30] = settr(29,0,31,1,0,"(1)", 0, 2, 0);
+ trans[0][31] = settr(30,0,0,63,63,"-end-", 0, 3500, 0);
+ /* np_ demon: */
+ trans[_NP_] = (Trans **) emalloc(2*sizeof(Trans *));
+ T = trans[_NP_][0] = settr(9997,0,1,_T5,0,"(np_)", 1,2,0);
+ T->nxt = settr(9998,0,0,_T2,0,"(1)", 0,2,0);
+ T = trans[_NP_][1] = settr(9999,0,1,_T5,0,"(np_)", 1,2,0);
+}
+
+Trans *
+settr( int t_id, int a, int b, int c, int d,
+ char *t, int g, int tpe0, int tpe1)
+{ Trans *tmp = (Trans *) emalloc(sizeof(Trans));
+
+ tmp->atom = a&(6|32); /* only (2|8|32) have meaning */
+ if (!g) tmp->atom |= 8; /* no global references */
+ tmp->st = b;
+ tmp->tpe[0] = tpe0;
+ tmp->tpe[1] = tpe1;
+ tmp->tp = t;
+ tmp->t_id = t_id;
+ tmp->forw = c;
+ tmp->back = d;
+ return tmp;
+}
+
+Trans *
+cpytr(Trans *a)
+{ Trans *tmp = (Trans *) emalloc(sizeof(Trans));
+
+ int i;
+ tmp->atom = a->atom;
+ tmp->st = a->st;
+#ifdef HAS_UNLESS
+ tmp->e_trans = a->e_trans;
+ for (i = 0; i < HAS_UNLESS; i++)
+ tmp->escp[i] = a->escp[i];
+#endif
+ tmp->tpe[0] = a->tpe[0];
+ tmp->tpe[1] = a->tpe[1];
+ for (i = 0; i < 6; i++)
+ { tmp->qu[i] = a->qu[i];
+ tmp->ty[i] = a->ty[i];
+ }
+ tmp->tp = (char *) emalloc(strlen(a->tp)+1);
+ strcpy(tmp->tp, a->tp);
+ tmp->t_id = a->t_id;
+ tmp->forw = a->forw;
+ tmp->back = a->back;
+ return tmp;
+}
+
+#ifndef NOREDUCE
+int
+srinc_set(int n)
+{ if (n <= 2) return LOCAL;
+ if (n <= 2+ DELTA) return Q_FULL_F; /* 's' or nfull */
+ if (n <= 2+2*DELTA) return Q_EMPT_F; /* 'r' or nempty */
+ if (n <= 2+3*DELTA) return Q_EMPT_T; /* empty */
+ if (n <= 2+4*DELTA) return Q_FULL_T; /* full */
+ if (n == 5*DELTA) return GLOBAL;
+ if (n == 6*DELTA) return TIMEOUT_F;
+ if (n == 7*DELTA) return ALPHA_F;
+ Uerror("cannot happen srinc_class");
+ return BAD;
+}
+int
+srunc(int n, int m)
+{ switch(m) {
+ case Q_FULL_F: return n-2;
+ case Q_EMPT_F: return n-2-DELTA;
+ case Q_EMPT_T: return n-2-2*DELTA;
+ case Q_FULL_T: return n-2-3*DELTA;
+ case ALPHA_F:
+ case TIMEOUT_F: return 257; /* non-zero, and > MAXQ */
+ }
+ Uerror("cannot happen srunc");
+ return 0;
+}
+#endif
+int cnt;
+#ifdef HAS_UNLESS
+int
+isthere(Trans *a, int b)
+{ Trans *t;
+ for (t = a; t; t = t->nxt)
+ if (t->t_id == b)
+ return 1;
+ return 0;
+}
+#endif
+#ifndef NOREDUCE
+int
+mark_safety(Trans *t) /* for conditional safety */
+{ int g = 0, i, j, k;
+
+ if (!t) return 0;
+ if (t->qu[0])
+ return (t->qu[1])?2:1; /* marked */
+
+ for (i = 0; i < 2; i++)
+ { j = srinc_set(t->tpe[i]);
+ if (j >= GLOBAL && j != ALPHA_F)
+ return -1;
+ if (j != LOCAL)
+ { k = srunc(t->tpe[i], j);
+ if (g == 0
+ || t->qu[0] != k
+ || t->ty[0] != j)
+ { t->qu[g] = k;
+ t->ty[g] = j;
+ g++;
+ } } }
+ return g;
+}
+#endif
+void
+retrans(int n, int m, int is, short srcln[], uchar reach[], uchar lstate[])
+ /* process n, with m states, is=initial state */
+{ Trans *T0, *T1, *T2, *T3;
+ int i, k;
+#ifndef NOREDUCE
+ int g, h, j, aa;
+#endif
+#ifdef HAS_UNLESS
+ int p;
+#endif
+ if (state_tables >= 4)
+ { printf("STEP 1 proctype %s\n",
+ procname[n]);
+ for (i = 1; i < m; i++)
+ for (T0 = trans[n][i]; T0; T0 = T0->nxt)
+ crack(n, i, T0, srcln);
+ return;
+ }
+ do {
+ for (i = 1, cnt = 0; i < m; i++)
+ { T2 = trans[n][i];
+ T1 = T2?T2->nxt:(Trans *)0;
+/* prescan: */ for (T0 = T1; T0; T0 = T0->nxt)
+/* choice in choice */ { if (T0->st && trans[n][T0->st]
+ && trans[n][T0->st]->nxt)
+ break;
+ }
+#if 0
+ if (T0)
+ printf("\tstate %d / %d: choice in choice\n",
+ i, T0->st);
+#endif
+ if (T0)
+ for (T0 = T1; T0; T0 = T0->nxt)
+ { T3 = trans[n][T0->st];
+ if (!T3->nxt)
+ { T2->nxt = cpytr(T0);
+ T2 = T2->nxt;
+ imed(T2, T0->st, n, i);
+ continue;
+ }
+ do { T3 = T3->nxt;
+ T2->nxt = cpytr(T3);
+ T2 = T2->nxt;
+ imed(T2, T0->st, n, i);
+ } while (T3->nxt);
+ cnt++;
+ }
+ }
+ } while (cnt);
+ if (state_tables >= 3)
+ { printf("STEP 2 proctype %s\n",
+ procname[n]);
+ for (i = 1; i < m; i++)
+ for (T0 = trans[n][i]; T0; T0 = T0->nxt)
+ crack(n, i, T0, srcln);
+ return;
+ }
+ for (i = 1; i < m; i++)
+ { if (trans[n][i] && trans[n][i]->nxt) /* optimize */
+ { T1 = trans[n][i]->nxt;
+#if 0
+ printf("\t\tpull %d (%d) to %d\n",
+ T1->st, T1->forw, i);
+#endif
+ if (!trans[n][T1->st]) continue;
+ T0 = cpytr(trans[n][T1->st]);
+ trans[n][i] = T0;
+ reach[T1->st] = 1;
+ imed(T0, T1->st, n, i);
+ for (T1 = T1->nxt; T1; T1 = T1->nxt)
+ {
+#if 0
+ printf("\t\tpull %d (%d) to %d\n",
+ T1->st, T1->forw, i);
+#endif
+ if (!trans[n][T1->st]) continue;
+ T0->nxt = cpytr(trans[n][T1->st]);
+ T0 = T0->nxt;
+ reach[T1->st] = 1;
+ imed(T0, T1->st, n, i);
+ } } }
+ if (state_tables >= 2)
+ { printf("STEP 3 proctype %s\n",
+ procname[n]);
+ for (i = 1; i < m; i++)
+ for (T0 = trans[n][i]; T0; T0 = T0->nxt)
+ crack(n, i, T0, srcln);
+ return;
+ }
+#ifdef HAS_UNLESS
+ for (i = 1; i < m; i++)
+ { if (!trans[n][i]) continue;
+ /* check for each state i if an
+ * escape to some state p is defined
+ * if so, copy and mark p's transitions
+ * and prepend them to the transition-
+ * list of state i
+ */
+ if (!like_java) /* the default */
+ { for (T0 = trans[n][i]; T0; T0 = T0->nxt)
+ for (k = HAS_UNLESS-1; k >= 0; k--)
+ { if (p = T0->escp[k])
+ for (T1 = trans[n][p]; T1; T1 = T1->nxt)
+ { if (isthere(trans[n][i], T1->t_id))
+ continue;
+ T2 = cpytr(T1);
+ T2->e_trans = p;
+ T2->nxt = trans[n][i];
+ trans[n][i] = T2;
+ } }
+ } else /* outermost unless checked first */
+ { Trans *T4;
+ T4 = T3 = (Trans *) 0;
+ for (T0 = trans[n][i]; T0; T0 = T0->nxt)
+ for (k = HAS_UNLESS-1; k >= 0; k--)
+ { if (p = T0->escp[k])
+ for (T1 = trans[n][p]; T1; T1 = T1->nxt)
+ { if (isthere(trans[n][i], T1->t_id))
+ continue;
+ T2 = cpytr(T1);
+ T2->nxt = (Trans *) 0;
+ T2->e_trans = p;
+ if (T3) T3->nxt = T2;
+ else T4 = T2;
+ T3 = T2;
+ } }
+ if (T4)
+ { T3->nxt = trans[n][i];
+ trans[n][i] = T4;
+ }
+ }
+ }
+#endif
+#ifndef NOREDUCE
+ for (i = 1; i < m; i++)
+ { if (a_cycles)
+ { /* moves through these states are visible */
+ #if PROG_LAB>0 && defined(HAS_NP)
+ if (progstate[n][i])
+ goto degrade;
+ for (T1 = trans[n][i]; T1; T1 = T1->nxt)
+ if (progstate[n][T1->st])
+ goto degrade;
+ #endif
+ if (accpstate[n][i] || visstate[n][i])
+ goto degrade;
+ for (T1 = trans[n][i]; T1; T1 = T1->nxt)
+ if (accpstate[n][T1->st])
+ goto degrade;
+ }
+ T1 = trans[n][i];
+ if (!T1) continue;
+ g = mark_safety(T1); /* V3.3.1 */
+ if (g < 0) goto degrade; /* global */
+ /* check if mixing of guards preserves reduction */
+ if (T1->nxt)
+ { k = 0;
+ for (T0 = T1; T0; T0 = T0->nxt)
+ { if (!(T0->atom&8))
+ goto degrade;
+ for (aa = 0; aa < 2; aa++)
+ { j = srinc_set(T0->tpe[aa]);
+ if (j >= GLOBAL && j != ALPHA_F)
+ goto degrade;
+ if (T0->tpe[aa]
+ && T0->tpe[aa]
+ != T1->tpe[0])
+ k = 1;
+ } }
+ /* g = 0; V3.3.1 */
+ if (k) /* non-uniform selection */
+ for (T0 = T1; T0; T0 = T0->nxt)
+ for (aa = 0; aa < 2; aa++)
+ { j = srinc_set(T0->tpe[aa]);
+ if (j != LOCAL)
+ { k = srunc(T0->tpe[aa], j);
+ for (h = 0; h < 6; h++)
+ if (T1->qu[h] == k
+ && T1->ty[h] == j)
+ break;
+ if (h >= 6)
+ { T1->qu[g%6] = k;
+ T1->ty[g%6] = j;
+ g++;
+ } } }
+ if (g > 6)
+ { T1->qu[0] = 0; /* turn it off */
+ printf("pan: warning, line %d, ",
+ srcln[i]);
+ printf("too many stmnt types (%d)",
+ g);
+ printf(" in selection\n");
+ goto degrade;
+ }
+ }
+ /* mark all options global if >=1 is global */
+ for (T1 = trans[n][i]; T1; T1 = T1->nxt)
+ if (!(T1->atom&8)) break;
+ if (T1)
+degrade: for (T1 = trans[n][i]; T1; T1 = T1->nxt)
+ T1->atom &= ~8; /* mark as unsafe */
+ /* can only mix 'r's or 's's if on same chan */
+ /* and not mixed with other local operations */
+ T1 = trans[n][i];
+ if (!T1 || T1->qu[0]) continue;
+ j = T1->tpe[0];
+ if (T1->nxt && T1->atom&8)
+ { if (j == 5*DELTA)
+ { printf("warning: line %d ", srcln[i]);
+ printf("mixed condition ");
+ printf("(defeats reduction)\n");
+ goto degrade;
+ }
+ for (T0 = T1; T0; T0 = T0->nxt)
+ for (aa = 0; aa < 2; aa++)
+ if (T0->tpe[aa] && T0->tpe[aa] != j)
+ { printf("warning: line %d ", srcln[i]);
+ printf("[%d-%d] mixed %stion ",
+ T0->tpe[aa], j,
+ (j==5*DELTA)?"condi":"selec");
+ printf("(defeats reduction)\n");
+ printf(" '%s' <-> '%s'\n",
+ T1->tp, T0->tp);
+ goto degrade;
+ } }
+ }
+#endif
+ for (i = 1; i < m; i++)
+ { T2 = trans[n][i];
+ if (!T2
+ || T2->nxt
+ || strncmp(T2->tp, ".(goto)", 7)
+ || !stopstate[n][i])
+ continue;
+ stopstate[n][T2->st] = 1;
+ }
+ if (state_tables)
+ { printf("proctype ");
+ if (!strcmp(procname[n], ":init:"))
+ printf("init\n");
+ else
+ printf("%s\n", procname[n]);
+ for (i = 1; i < m; i++)
+ reach[i] = 1;
+ tagtable(n, m, is, srcln, reach);
+ } else
+ for (i = 1; i < m; i++)
+ { int nrelse;
+ if (strcmp(procname[n], ":never:") != 0)
+ { for (T0 = trans[n][i]; T0; T0 = T0->nxt)
+ { if (T0->st == i
+ && strcmp(T0->tp, "(1)") == 0)
+ { printf("error: proctype '%s' ",
+ procname[n]);
+ printf("line %d, state %d: has un",
+ srcln[i], i);
+ printf("conditional self-loop\n");
+ pan_exit(1);
+ } } }
+ nrelse = 0;
+ for (T0 = trans[n][i]; T0; T0 = T0->nxt)
+ { if (strcmp(T0->tp, "else") == 0)
+ nrelse++;
+ }
+ if (nrelse > 1)
+ { printf("error: proctype '%s' state",
+ procname[n]);
+ printf(" %d, inherits %d", i, nrelse);
+ printf(" 'else' stmnts\n");
+ pan_exit(1);
+ } }
+ if (!state_tables && strcmp(procname[n], ":never:") == 0)
+ { int h = 0;
+ for (i = 1; i < m; i++)
+ for (T0 = trans[n][i]; T0; T0 = T0->nxt)
+ if (T0->forw > h) h = T0->forw;
+ h++;
+ frm_st0 = (short *) emalloc(h * sizeof(short));
+ for (i = 1; i < m; i++)
+ for (T0 = trans[n][i]; T0; T0 = T0->nxt)
+ frm_st0[T0->forw] = i;
+ }
+#ifndef LOOPSTATE
+ if (state_tables)
+#endif
+ do_dfs(n, m, is, srcln, reach, lstate);
+#ifdef T_REVERSE
+ /* process n, with m states, is=initial state -- reverse list */
+ if (!state_tables && strcmp(procname[n], ":never:") != 0)
+ { for (i = 1; i < m; i++)
+ { Trans *T4 = (Trans *) 0;
+ T1 = (Trans *) 0;
+ T2 = (Trans *) 0;
+ T3 = (Trans *) 0;
+ for (T0 = trans[n][i]; T0; T0 = T4)
+ { T4 = T0->nxt;
+ if (strcmp(T0->tp, "else") == 0)
+ { T3 = T0;
+ T0->nxt = (Trans *) 0;
+ } else
+ { T0->nxt = T1;
+ if (!T1) { T2 = T0; }
+ T1 = T0;
+ } }
+ if (T2 && T3) { T2->nxt = T3; }
+ trans[n][i] = T1; /* reversed -- else at end */
+ } }
+#endif
+}
+void
+imed(Trans *T, int v, int n, int j) /* set intermediate state */
+{ progstate[n][T->st] |= progstate[n][v];
+ accpstate[n][T->st] |= accpstate[n][v];
+ stopstate[n][T->st] |= stopstate[n][v];
+ mapstate[n][j] = T->st;
+}
+void
+tagtable(int n, int m, int is, short srcln[], uchar reach[])
+{ Trans *z;
+
+ if (is >= m || !trans[n][is]
+ || is <= 0 || reach[is] == 0)
+ return;
+ reach[is] = 0;
+ if (state_tables)
+ for (z = trans[n][is]; z; z = z->nxt)
+ crack(n, is, z, srcln);
+ for (z = trans[n][is]; z; z = z->nxt)
+ {
+#ifdef HAS_UNLESS
+ int i, j;
+#endif
+ tagtable(n, m, z->st, srcln, reach);
+#ifdef HAS_UNLESS
+ for (i = 0; i < HAS_UNLESS; i++)
+ { j = trans[n][is]->escp[i];
+ if (!j) break;
+ tagtable(n, m, j, srcln, reach);
+ }
+#endif
+ }
+}
+void
+dfs_table(int n, int m, int is, short srcln[], uchar reach[], uchar lstate[])
+{ Trans *z;
+
+ if (is >= m || is <= 0 || !trans[n][is])
+ return;
+ if ((reach[is] & (4|8|16)) != 0)
+ { if ((reach[is] & (8|16)) == 16) /* on stack, not yet recorded */
+ { lstate[is] = 1;
+ reach[is] |= 8; /* recorded */
+ if (state_tables)
+ { printf("state %d line %d is a loopstate\n", is, srcln[is]);
+ } }
+ return;
+ }
+ reach[is] |= (4|16); /* visited | onstack */
+ for (z = trans[n][is]; z; z = z->nxt)
+ {
+#ifdef HAS_UNLESS
+ int i, j;
+#endif
+ dfs_table(n, m, z->st, srcln, reach, lstate);
+#ifdef HAS_UNLESS
+ for (i = 0; i < HAS_UNLESS; i++)
+ { j = trans[n][is]->escp[i];
+ if (!j) break;
+ dfs_table(n, m, j, srcln, reach, lstate);
+ }
+#endif
+ }
+ reach[is] &= ~16; /* no longer on stack */
+}
+void
+do_dfs(int n, int m, int is, short srcln[], uchar reach[], uchar lstate[])
+{ int i;
+ dfs_table(n, m, is, srcln, reach, lstate);
+ for (i = 0; i < m; i++)
+ reach[i] &= ~(4|8|16);
+}
+void
+crack(int n, int j, Trans *z, short srcln[])
+{ int i;
+
+ if (!z) return;
+ printf(" state %3d -(tr %3d)-> state %3d ",
+ j, z->forw, z->st);
+ printf("[id %3d tp %3d", z->t_id, z->tpe[0]);
+ if (z->tpe[1]) printf(",%d", z->tpe[1]);
+#ifdef HAS_UNLESS
+ if (z->e_trans)
+ printf(" org %3d", z->e_trans);
+ else if (state_tables >= 2)
+ for (i = 0; i < HAS_UNLESS; i++)
+ { if (!z->escp[i]) break;
+ printf(" esc %d", z->escp[i]);
+ }
+#endif
+ printf("]");
+ printf(" [%s%s%s%s%s] line %d => ",
+ z->atom&6?"A":z->atom&32?"D":"-",
+ accpstate[n][j]?"a" :"-",
+ stopstate[n][j]?"e" : "-",
+ progstate[n][j]?"p" : "-",
+ z->atom & 8 ?"L":"G",
+ srcln[j]);
+ for (i = 0; z->tp[i]; i++)
+ if (z->tp[i] == '\n')
+ printf("\\n");
+ else
+ putchar(z->tp[i]);
+ if (z->qu[0])
+ { printf("\t[");
+ for (i = 0; i < 6; i++)
+ if (z->qu[i])
+ printf("(%d,%d)",
+ z->qu[i], z->ty[i]);
+ printf("]");
+ }
+ printf("\n");
+ fflush(stdout);
+}
+
+#ifdef VAR_RANGES
+#define BYTESIZE 32 /* 2^8 : 2^3 = 256:8 = 32 */
+
+typedef struct Vr_Ptr {
+ char *nm;
+ uchar vals[BYTESIZE];
+ struct Vr_Ptr *nxt;
+} Vr_Ptr;
+Vr_Ptr *ranges = (Vr_Ptr *) 0;
+
+void
+logval(char *s, int v)
+{ Vr_Ptr *tmp;
+
+ if (v<0 || v > 255) return;
+ for (tmp = ranges; tmp; tmp = tmp->nxt)
+ if (!strcmp(tmp->nm, s))
+ goto found;
+ tmp = (Vr_Ptr *) emalloc(sizeof(Vr_Ptr));
+ tmp->nxt = ranges;
+ ranges = tmp;
+ tmp->nm = s;
+found:
+ tmp->vals[(v)/8] |= 1<<((v)%8);
+}
+
+void
+dumpval(uchar X[], int range)
+{ int w, x, i, j = -1;
+
+ for (w = i = 0; w < range; w++)
+ for (x = 0; x < 8; x++, i++)
+ {
+from: if ((X[w] & (1<<x)))
+ { printf("%d", i);
+ j = i;
+ goto upto;
+ } }
+ return;
+ for (w = 0; w < range; w++)
+ for (x = 0; x < 8; x++, i++)
+ {
+upto: if (!(X[w] & (1<<x)))
+ { if (i-1 == j)
+ printf(", ");
+ else
+ printf("-%d, ", i-1);
+ goto from;
+ } }
+ if (j >= 0 && j != 255)
+ printf("-255");
+}
+
+void
+dumpranges(void)
+{ Vr_Ptr *tmp;
+ printf("\nValues assigned within ");
+ printf("interval [0..255]:\n");
+ for (tmp = ranges; tmp; tmp = tmp->nxt)
+ { printf("\t%s\t: ", tmp->nm);
+ dumpval(tmp->vals, BYTESIZE);
+ printf("\n");
+ }
+}
+#endif
--- /dev/null
+/* LTTng ltt-tracer.c atomic lockless buffering scheme Promela model v2
+ * Created for the Spin validator.
+ * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ * October 2008
+
+ * TODO : create test cases that will generate an overflow on the offset and
+ * counter type. Counter types smaller than a byte should be used.
+
+ * Promela only has unsigned char, no signed char.
+ * Because detection of difference < 0 depends on a signed type, but we want
+ * compactness, check also for the values being higher than half of the unsigned
+ * char range (and consider them negative). The model, by design, does not use
+ * offsets or counts higher than 127 because we would then have to use a larger
+ * type (short or int).
+ */
+#define HALF_UCHAR (255/2)
+
+/* NUMPROCS 4 : causes event loss with some reader timings.
+ * e.g. 3 events, 1 switch, 1 event (lost, buffer full), read 1 subbuffer
+ */
+#define NUMPROCS 4
+
+/* NUMPROCS 3 : does not cause event loss because buffers are big enough.
+ * #define NUMPROCS 3
+ * e.g. 3 events, 1 switch, read 1 subbuffer
+ */
+
+#define NUMSWITCH 1
+#define BUFSIZE 4
+#define NR_SUBBUFS 2
+#define SUBBUF_SIZE (BUFSIZE / NR_SUBBUFS)
+
+/* Writer counters
+*/
+byte write_off = 0;
+byte commit_count[NR_SUBBUFS];
+
+/* <formal_verif> */
+byte _commit_sum;
+/* </formal_verif> */
+
+/* Reader counters
+*/
+byte read_off = 0;
+
+byte events_lost = 0;
+byte refcount = 0;
+
+bool deliver = 0;
+
+/* buffer slot in-use bit. Detects racy use (more than a single process
+ * accessing a slot at any given step).
+ */
+bool buffer_use[BUFSIZE];
+
+/* Proceed to a sub-subber switch is needed.
+ * Used in a periodical timer interrupt to fill and ship the current subbuffer
+ * to the reader so we can guarantee a steady flow. If a subbuffer is
+ * completely empty, do not switch.
+ * Also used as "finalize" operation to complete the last subbuffer after
+ * all writers have finished so the last subbuffer can be read by the reader.
+ */
+proctype switcher()
+{
+ byte prev_off, new_off, tmp_commit;
+ byte size;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ size = SUBBUF_SIZE - (prev_off % SUBBUF_SIZE);
+ new_off = prev_off + size;
+ if
+ :: (new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR)
+ || size == SUBBUF_SIZE ->
+ refcount = refcount - 1;
+ goto not_needed;
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ }
+
+ atomic {
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ /* <formal_verif> */
+ _commit_sum = _commit_sum - commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE]
+ + tmp_commit;
+ /* </formal_verif> */
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ refcount = refcount - 1;
+ }
+not_needed:
+ skip;
+}
+
+/* tracer
+ * Writes 1 byte of information in the buffer at the current
+ * "write_off" position and then increment the commit_count of the sub-buffer
+ * the information has been written to.
+ */
+proctype tracer()
+{
+ byte size = 1;
+ byte prev_off, new_off, tmp_commit;
+ byte i, j;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ new_off = prev_off + size;
+ }
+ atomic {
+ if
+ :: new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR ->
+ goto lost
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ i = 0;
+ do
+ :: i < size ->
+ assert(buffer_use[(prev_off + i) % BUFSIZE] == 0);
+ buffer_use[(prev_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= size -> break
+ od;
+ }
+
+ /* writing to buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < size ->
+ buffer_use[(prev_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= size -> break
+ od;
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ /* <formal_verif> */
+ _commit_sum = _commit_sum - commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE]
+ + tmp_commit;
+ /* </formal_verif> */
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ }
+ atomic {
+ goto end;
+lost:
+ events_lost++;
+end:
+ refcount = refcount - 1;
+ }
+}
+
+/* reader
+ * Read the information sub-buffer per sub-buffer when available.
+ *
+ * Reads the information as soon as it is ready, or may be delayed by
+ * an asynchronous delivery. Being modeled as a process insures all cases
+ * (scheduled very quickly or very late, causing event loss) are covered.
+ * Only one reader per buffer (normally ensured by a mutex). This is modeled
+ * by using a single reader process.
+ */
+proctype reader()
+{
+ byte i, j;
+
+ do
+ :: (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) > 0
+ && (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) < HALF_UCHAR
+ && (commit_count[(read_off % BUFSIZE) / SUBBUF_SIZE]
+ - SUBBUF_SIZE - (((read_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS)
+ == 0) ->
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ assert(buffer_use[(read_off + i) % BUFSIZE] == 0);
+ buffer_use[(read_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ }
+
+ /* reading from buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ buffer_use[(read_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ read_off = read_off + SUBBUF_SIZE;
+ }
+ :: read_off >= (NUMPROCS - events_lost) -> break;
+ od;
+}
+
+/* Waits for all tracer and switcher processes to finish before finalizing
+ * the buffer. Only after that will the reader be allowed to read the
+ * last subbuffer.
+ */
+proctype cleaner()
+{
+ atomic {
+ do
+ :: refcount == 0 ->
+ refcount = refcount + 1;
+ run switcher(); /* Finalize the last sub-buffer so it can be read. */
+ break;
+ od;
+ }
+}
+
+init {
+ byte i = 0;
+ byte j = 0;
+ byte sum = 0;
+ byte commit_sum = 0;
+
+ atomic {
+ i = 0;
+ do
+ :: i < NR_SUBBUFS ->
+ commit_count[i] = 0;
+ i++
+ :: i >= NR_SUBBUFS -> break
+ od;
+ /* <formal_verif> */
+ _commit_sum = 0;
+ /* </formal_verif> */
+ i = 0;
+ do
+ :: i < BUFSIZE ->
+ buffer_use[i] = 0;
+ i++
+ :: i >= BUFSIZE -> break
+ od;
+ run reader();
+ run cleaner();
+ i = 0;
+ do
+ :: i < NUMPROCS ->
+ refcount = refcount + 1;
+ run tracer();
+ i++
+ :: i >= NUMPROCS -> break
+ od;
+ i = 0;
+ do
+ :: i < NUMSWITCH ->
+ refcount = refcount + 1;
+ run switcher();
+ i++
+ :: i >= NUMSWITCH -> break
+ od;
+ _commit_sum = 0;
+ }
+
+ /* Assertions.
+ */
+ atomic {
+ /* The writer head must always be superior or equal to the reader head.
+ */
+ //assert(write_off - read_off >= 0 && write_off - read_off < HALF_UCHAR);
+ /* The sum of all subbuffer commit counts must always be lower or equal
+ * to the writer head, because space must be reserved before it is
+ * written to and then committed.
+ */
+ assert(write_off - _commit_sum >= 0 && write_off - _commit_sum < HALF_UCHAR);
+
+ /* If we have less writers than the buffer space available, we should
+ * not loose events
+ */
+ assert(NUMPROCS + NUMSWITCH > BUFSIZE || events_lost == 0);
+ }
+}
+
+
--- /dev/null
+;; promela-mode.el --- major mode for editing PROMELA program files
+;; $Revision: 1.11 $ $Date: 2001/07/09 18:36:45 $ $Author: engstrom $
+
+;; Author: Eric Engstrom <eric.engstrom@honeywell.com>
+;; Maintainer: Eric Engstrom
+;; Keywords: spin, promela, tools
+
+;; Copyright (C) 1998-2003 Eric Engstrom / Honeywell Laboratories
+
+;; ... Possibly insert GPL here someday ...
+
+;;; Commentary:
+
+;; This file contains code for a GNU Emacs major mode for editing
+;; PROMELA (SPIN) program files.
+
+;; Type "C-h m" in Emacs (while in a buffer in promela-mode) for
+;; information on how to configure indentation and fontification,
+;; or look at the configuration variables below.
+
+;; To use, place promela-mode.el in a directory in your load-path.
+;; Then, put the following lines into your .emacs and promela-mode
+;; will be automatically loaded when editing a PROMELA program.
+
+;; (autoload 'promela-mode "promela-mode" "PROMELA mode" nil t)
+;; (setq auto-mode-alist
+;; (append
+;; (list (cons "\\.promela$" 'promela-mode)
+;; (cons "\\.spin$" 'promela-mode)
+;; (cons "\\.pml$" 'promela-mode)
+;; ;; (cons "\\.other-extensions$" 'promela-mode)
+;; )
+;; auto-mode-alist))
+
+;; If you wish for promela-mode to be used for files with other
+;; extensions you add your own patterned after the code above.
+
+;; Note that promela-mode adhears to the font-lock "standards" and
+;; defines several "levels" of fontification or colorization. The
+;; default is fairly gaudy, so I can imagine that some folks would
+;; like a bit less. FMI: see `font-lock-maximum-decoration'
+
+;; This mode is known to work under the following versions of emacs:
+;; - XEmacs: 19.16, 20.x, 21.x
+;; - FSF/GNU Emacs: 19.34
+;; - NTEmacs (FSF): 20.[67]
+;; That is not to say there are no bugs specific to one of those versions :-)
+
+;; Please send any comments, bugs, patches or other requests to
+;; Eric Engstrom at engstrom@htc.honeywell.com
+
+;; To-Do:
+;; - compile/syntax-check/verify? (suggested by R.Goldman)
+;; - indentation - splitting lines at logical operators (M. Rangarajan)
+;; [ This might "devolve" to indentation after "->" or ";"
+;; being as is, but anything else indent even more? ]
+;; :: SomeReallyLongArrayRef[this].typedefField != SomeReallyLongConstant -> /* some-comment */
+;; [ Suggestion would be to break the first line after the !=, therefore: ]
+;; :: SomeReallyLongArrayRef[this].typedefField
+;; != SomeReallyLongConstant -> /* some-comment */
+;; [ at this point I'm not so sure about this change... EE: 2001/05/19 ]
+\f
+;;; -------------------------------------------------------------------------
+;;; Code:
+
+;; NOTE: same as CVS revision:
+(defconst promela-mode-version "$Revision: 1.11 $"
+ "Promela-mode version number.")
+
+;; -------------------------------------------------------------------------
+;; The following constant values can be modified by the user in a .emacs file
+
+(defconst promela-block-indent 2
+ "*Controls indentation of lines within a block (`{') construct")
+
+(defconst promela-selection-indent 2
+ "*Controls indentation of options within a selection (`if')
+or iteration (`do') construct")
+
+(defconst promela-selection-option-indent 3
+ "*Controls indentation of lines after options within selection or
+iteration construct (`::')")
+
+(defconst promela-comment-col 32
+ "*Defines the desired comment column for comments to the right of text.")
+
+(defconst promela-tab-always-indent t
+ "*Non-nil means TAB in Promela mode should always reindent the current line,
+regardless of where in the line point is when the TAB command is used.")
+
+(defconst promela-auto-match-delimiter t
+ "*Non-nil means typing an open-delimiter (i.e. parentheses, brace, quote, etc)
+should also insert the matching closing delmiter character.")
+
+;; That should be about it for most users...
+;; unless you wanna hack elisp, the rest of this is probably uninteresting
+
+\f
+;; -------------------------------------------------------------------------
+;; help determine what emacs we have here...
+
+(defconst promela-xemacsp (string-match "XEmacs" (emacs-version))
+ "Non-nil if we are running in the XEmacs environment.")
+
+;;;(defconst promela-xemacs20p (and promela-xemacsp (>= emacs-major-version 20))
+;; "Non-nil if we are running in an XEmacs environment version 20 or greater.")
+
+;; -------------------------------------------------------------------------
+;; promela-mode font faces/definitions
+
+;; make use of font-lock stuff, so say that explicitly
+(require 'font-lock)
+
+;; BLECH! YUCK! I just wish these guys could agree to something....
+;; Faces available in: ntemacs emacs xemacs xemacs xemacs
+;; font-lock- xxx -face 20.6 19.34 19.16 20.x 21.x
+;; -builtin- X
+;; -constant- X
+;; -comment- X X X X X
+;; -doc-string- X X X
+;; -function-name- X X X X X
+;; -keyword- X X X X X
+;; -preprocessor- X X X
+;; -reference- X X X X
+;; -signal-name- X X!20.0
+;; -string- X X X X X
+;; -type- X X X X X
+;; -variable-name- X X X X X
+;; -warning- X X
+
+;;; Compatibility on faces between versions of emacs-en
+(unless promela-xemacsp
+
+ (defvar font-lock-preprocessor-face 'font-lock-preprocessor-face
+ "Face name to use for preprocessor statements.")
+ ;; For consistency try to define the preprocessor face == builtin face
+ (condition-case nil
+ (copy-face 'font-lock-builtin-face 'font-lock-preprocessor-face)
+ (error
+ (defface font-lock-preprocessor-face
+ '((t (:foreground "blue" :italic nil :underline t)))
+ "Face Lock mode face used to highlight preprocessor statements."
+ :group 'font-lock-highlighting-faces)))
+
+ (defvar font-lock-reference-face 'font-lock-reference-face
+ "Face name to use for constants and reference and label names.")
+ ;; For consistency try to define the reference face == constant face
+ (condition-case nil
+ (copy-face 'font-lock-constant-face 'font-lock-reference-face)
+ (error
+ (defface font-lock-reference-face
+ '((((class grayscale) (background light))
+ (:foreground "LightGray" :bold t :underline t))
+ (((class grayscale) (background dark))
+ (:foreground "Gray50" :bold t :underline t))
+ (((class color) (background light)) (:foreground "CadetBlue"))
+ (((class color) (background dark)) (:foreground "Aquamarine"))
+ (t (:bold t :underline t)))
+ "Font Lock mode face used to highlight constancs, references and labels."
+ :group 'font-lock-highlighting-faces)))
+
+ )
+
+;; send-poll "symbol" face is custom to promela-mode
+;; but check for existence to allow someone to override it
+(defvar promela-fl-send-poll-face 'promela-fl-send-poll-face
+ "Face name to use for Promela Send or Poll symbols: `!' or `?'")
+(copy-face (if promela-xemacsp 'modeline 'region)
+ 'promela-fl-send-poll-face)
+
+;; some emacs-en don't define or have regexp-opt available.
+(unless (functionp 'regexp-opt)
+ (defmacro regexp-opt (strings)
+ "Cheap imitation of `regexp-opt' since it's not availble in this emacs"
+ `(mapconcat 'identity ,strings "\\|")))
+
+\f
+;; -------------------------------------------------------------------------
+;; promela-mode font lock specifications/regular-expressions
+;; - for help, look at definition of variable 'font-lock-keywords
+;; - some fontification ideas from -- [engstrom:20010309.1435CST]
+;; Pat Tullman (tullmann@cs.utah.edu) and
+;; Ny Aina Razermera Mamy (ainarazr@cs.uoregon.edu)
+;; both had promela-mode's that I discovered after starting this one...
+;; (but neither did any sort of indentation ;-)
+
+(defconst promela-font-lock-keywords-1 nil
+ "Subdued level highlighting for Promela mode.")
+
+(defconst promela-font-lock-keywords-2 nil
+ "Medium level highlighting for Promela mode.")
+
+(defconst promela-font-lock-keywords-3 nil
+ "Gaudy level highlighting for Promela mode.")
+
+;; set each of those three variables now..
+(let ((promela-keywords
+ (eval-when-compile
+ (regexp-opt
+ '("active" "assert" "atomic" "break" "d_step"
+ "do" "dproctype" "else" "empty" "enabled"
+ "eval" "fi" "full" "goto" "hidden" "if" "init"
+ "inline" "len" "local" "mtype" "nempty" "never"
+ "nfull" "od" "of" "pcvalue" "printf" "priority"
+ "proctype" "provided" "run" "show" "skip"
+ "timeout" "trace" "typedef" "unless" "xr" "xs"))))
+ (promela-types
+ (eval-when-compile
+ (regexp-opt '("bit" "bool" "byte" "short"
+ "int" "unsigned" "chan")))))
+
+ ;; really simple fontification (strings and comments come for "free")
+ (setq promela-font-lock-keywords-1
+ (list
+ ;; Keywords:
+ (cons (concat "\\<\\(" promela-keywords "\\)\\>")
+ 'font-lock-keyword-face)
+ ;; Types:
+ (cons (concat "\\<\\(" promela-types "\\)\\>")
+ 'font-lock-type-face)
+ ;; Special constants:
+ '("\\<_\\(np\\|pid\\|last\\)\\>" . font-lock-reference-face)))
+
+ ;; more complex fontification
+ ;; add function (proctype) names, lables and goto statements
+ ;; also add send/receive/poll fontification
+ (setq promela-font-lock-keywords-2
+ (append promela-font-lock-keywords-1
+ (list
+ ;; ANY Pre-Processor directive (lazy method: any line beginning with "#[a-z]+")
+ '("^\\(#[ \t]*[a-z]+\\)" 1 'font-lock-preprocessor-face t)
+
+ ;; "Functions" (proctype-s and inline-s)
+ (list (concat "\\<\\("
+ (eval-when-compile
+ (regexp-opt '("run" "dproctype" "proctype" "inline")))
+ "\\)\\>[ \t]*\\(\\sw+\\)?")
+ ;;'(1 'font-lock-keyword-face nil)
+ '(2 'font-lock-function-name-face nil t))
+
+ ;; Labels and GOTO labels
+ '("^\\(\\sw+\\):" 1 'font-lock-reference-face)
+ '("\\<\\(goto\\)\\>[ \t]+\\(\\sw+\\)"
+ ;;(1 'font-lock-keyword-face nil)
+ (2 'font-lock-reference-face nil t))
+
+ ;; Send, Receive and Poll
+ '("\\(\\sw+\\)\\(\\[[^\\?!]+\\]\\)?\\(\\??\\?\\|!?!\\)\\(\\sw+\\)"
+ (1 'font-lock-variable-name-face nil t)
+ (3 'promela-fl-send-poll-face nil t)
+ (4 'font-lock-reference-face nil t)
+ )
+ )))
+
+ ;; most complex fontification
+ ;; add pre-processor directives, typed variables and hidden/typedef decls.
+ (setq promela-font-lock-keywords-3
+ (append promela-font-lock-keywords-2
+ (list
+ ;; ANY Pre-Processor directive (lazy method: any line beginning with "#[a-z]+")
+ ;;'("^\\(#[ \t]*[a-z]+\\)" 1 'font-lock-preprocessor-face t)
+ ;; "defined" in an #if or #elif and associated macro names
+ '("^#[ \t]*\\(el\\)?if\\>"
+ ("\\<\\(defined\\)\\>[ \t]*(?\\(\\sw+\\)" nil nil
+ (1 'font-lock-preprocessor-face nil t)
+ (2 'font-lock-reference-face nil t)))
+ '("^#[ \t]*ifn?def\\>"
+ ("[ \t]*\\(\\sw+\\)" nil nil
+ (1 'font-lock-reference-face nil t)))
+ ;; Filenames in #include <...> directives
+ '("^#[ \t]*include[ \t]+<\\([^>\"\n]+\\)>" 1 'font-lock-string-face nil t)
+ ;; Defined functions and constants/types (non-functions)
+ '("^#[ \t]*define[ \t]+"
+ ("\\(\\sw+\\)(" nil nil (1 'font-lock-function-name-face nil t))
+ ("\\(\\sw+\\)[ \t]+\\(\\sw+\\)" nil nil (1 'font-lock-variable-name-face)
+ (2 'font-lock-reference-face nil t))
+ ("\\(\\sw+\\)[^(]?" nil nil (1 'font-lock-reference-face nil t)))
+
+ ;; Types AND variables
+ ;; - room for improvement: (i.e. don't currently):
+ ;; highlight user-defined types and asociated variable declarations
+ (list (concat "\\<\\(" promela-types "\\)\\>")
+ ;;'(1 'font-lock-type-face)
+ ;; now match the variables after the type definition, if any
+ '(promela-match-variable-or-declaration
+ nil nil
+ (1 'font-lock-variable-name-face) ;; nil t)
+ (2 font-lock-reference-face nil t)))
+
+ ;; Typedef/hidden types and declarations
+ '("\\<\\(typedef\\|hidden\\)\\>[ \t]*\\(\\sw+\\)?"
+ ;;(1 'font-lock-keyword-face nil)
+ (2 'font-lock-type-face nil t)
+ ;; now match the variables after the type definition, if any
+ (promela-match-variable-or-declaration
+ nil nil
+ (1 'font-lock-variable-name-face nil t)
+ (2 'font-lock-reference-face nil t)))
+ )))
+ )
+
+(defvar promela-font-lock-keywords promela-font-lock-keywords-1
+ "Default expressions to highlight in Promela mode.")
+
+;; Font-lock matcher functions:
+(defun promela-match-variable-or-declaration (limit)
+ "Match, and move over, any declaration/definition item after point.
+Matches after point, but ignores leading whitespace characters.
+Does not move further than LIMIT.
+
+The expected syntax of a declaration/definition item is `word' (preceded
+by optional whitespace) optionally followed by a `= value' (preceded and
+followed by more optional whitespace)
+
+Thus the regexp matches after point: word [ = value ]
+ ^^^^ ^^^^^
+Where the match subexpressions are: 1 2
+
+The item is delimited by (match-beginning 1) and (match-end 1).
+If (match-beginning 2) is non-nil, the item is followed by a `value'."
+ (when (looking-at "[ \t]*\\(\\sw+\\)[ \t]*=?[ \t]*\\(\\sw+\\)?[ \t]*,?")
+ (goto-char (min limit (match-end 0)))))
+
+\f
+;; -------------------------------------------------------------------------
+;; "install" promela-mode font lock specifications
+
+;; FMI: look up 'font-lock-defaults
+(defconst promela-font-lock-defaults
+ '(
+ (promela-font-lock-keywords
+ promela-font-lock-keywords-1
+ promela-font-lock-keywords-2
+ promela-font-lock-keywords-3) ;; font-lock stuff (keywords)
+ nil ;; keywords-only flag
+ nil ;; case-fold keyword searching
+ ;;((?_ . "w") (?$ . ".")) ;; mods to syntax table
+ nil ;; mods to syntax table (see below)
+ nil ;; syntax-begin
+ (font-lock-mark-block-function . mark-defun))
+)
+
+;; "install" the font-lock-defaults based upon version of emacs we have
+(cond (promela-xemacsp
+ (put 'promela-mode 'font-lock-defaults promela-font-lock-defaults))
+ ((not (assq 'promela-mode font-lock-defaults-alist))
+ (setq font-lock-defaults-alist
+ (cons
+ (cons 'promela-mode promela-font-lock-defaults)
+ font-lock-defaults-alist))))
+
+\f
+;; -------------------------------------------------------------------------
+;; other promela-mode specific definitions
+
+(defconst promela-defun-prompt-regexp
+ "^[ \t]*\\(d?proctype\\|init\\|inline\\|never\\|trace\\|typedef\\|mtype\\s-+=\\)[^{]*"
+ "Regexp describing the beginning of a Promela top-level definition.")
+
+(defvar promela-mode-syntax-table nil
+ "Syntax table in use in PROMELA-mode buffers.")
+(if promela-mode-syntax-table
+ ()
+ (setq promela-mode-syntax-table (make-syntax-table))
+ (modify-syntax-entry ?\\ "\\" promela-mode-syntax-table)
+ (modify-syntax-entry ?/ ". 14" promela-mode-syntax-table)
+ (modify-syntax-entry ?* ". 23" promela-mode-syntax-table)
+ (modify-syntax-entry ?+ "." promela-mode-syntax-table)
+ (modify-syntax-entry ?- "." promela-mode-syntax-table)
+ (modify-syntax-entry ?= "." promela-mode-syntax-table)
+ (modify-syntax-entry ?% "." promela-mode-syntax-table)
+ (modify-syntax-entry ?< "." promela-mode-syntax-table)
+ (modify-syntax-entry ?> "." promela-mode-syntax-table)
+ (modify-syntax-entry ?& "." promela-mode-syntax-table)
+ (modify-syntax-entry ?| "." promela-mode-syntax-table)
+ (modify-syntax-entry ?. "_" promela-mode-syntax-table)
+ (modify-syntax-entry ?_ "w" promela-mode-syntax-table)
+ (modify-syntax-entry ?\' "\"" promela-mode-syntax-table)
+ )
+
+(defvar promela-mode-abbrev-table nil
+ "*Abbrev table in use in promela-mode buffers.")
+(if promela-mode-abbrev-table
+ nil
+ (define-abbrev-table 'promela-mode-abbrev-table
+ '(
+;; Commented out for now - need to think about what abbrevs make sense
+;; ("assert" "ASSERT" promela-check-expansion 0)
+;; ("d_step" "D_STEP" promela-check-expansion 0)
+;; ("break" "BREAK" promela-check-expansion 0)
+;; ("do" "DO" promela-check-expansion 0)
+;; ("proctype" "PROCTYPE" promela-check-expansion 0)
+ )))
+
+(defvar promela-mode-map nil
+ "Keymap for promela-mode.")
+(if promela-mode-map
+ nil
+ (setq promela-mode-map (make-sparse-keymap))
+ (define-key promela-mode-map "\t" 'promela-indent-command)
+ (define-key promela-mode-map "\C-m" 'promela-newline-and-indent)
+ ;(define-key promela-mode-map 'backspace 'backward-delete-char-untabify)
+ (define-key promela-mode-map "\C-c\C-p" 'promela-beginning-of-block)
+ ;(define-key promela-mode-map "\C-c\C-n" 'promela-end-of-block)
+ (define-key promela-mode-map "\M-\C-a" 'promela-beginning-of-defun)
+ ;(define-key promela-mode-map "\M-\C-e" 'promela-end-of-defun)
+ (define-key promela-mode-map "\C-c(" 'promela-toggle-auto-match-delimiter)
+ (define-key promela-mode-map "{" 'promela-open-delimiter)
+ (define-key promela-mode-map "}" 'promela-close-delimiter)
+ (define-key promela-mode-map "(" 'promela-open-delimiter)
+ (define-key promela-mode-map ")" 'promela-close-delimiter)
+ (define-key promela-mode-map "[" 'promela-open-delimiter)
+ (define-key promela-mode-map "]" 'promela-close-delimiter)
+ (define-key promela-mode-map ";" 'promela-insert-and-indent)
+ (define-key promela-mode-map ":" 'promela-insert-and-indent)
+ ;;
+ ;; this is preliminary at best - use at your own risk:
+ (define-key promela-mode-map "\C-c\C-s" 'promela-syntax-check)
+ ;;
+ ;;(define-key promela-mode-map "\C-c\C-d" 'promela-mode-toggle-debug)
+ ;;(define-key promela-mode-map "\C-c\C-r" 'promela-mode-revert-buffer)
+ )
+
+(defvar promela-matching-delimiter-alist
+ '( (?( . ?))
+ (?[ . ?])
+ (?{ . "\n}")
+ ;(?< . ?>)
+ (?\' . ?\')
+ (?\` . ?\`)
+ (?\" . ?\") )
+ "List of pairs of matching open/close delimiters - for auto-insert")
+
+\f
+;; -------------------------------------------------------------------------
+;; Promela-mode itself
+
+(defun promela-mode ()
+ "Major mode for editing PROMELA code.
+\\{promela-mode-map}
+
+Variables controlling indentation style:
+ promela-block-indent
+ Relative offset of lines within a block (`{') construct.
+
+ promela-selection-indent
+ Relative offset of option lines within a selection (`if')
+ or iteration (`do') construct.
+
+ promela-selection-option-indent
+ Relative offset of lines after/within options (`::') within
+ selection or iteration constructs.
+
+ promela-comment-col
+ Defines the desired comment column for comments to the right of text.
+
+ promela-tab-always-indent
+ Non-nil means TAB in PROMELA mode should always reindent the current
+ line, regardless of where in the line the point is when the TAB
+ command is used.
+
+ promela-auto-match-delimiter
+ Non-nil means typing an open-delimiter (i.e. parentheses, brace,
+ quote, etc) should also insert the matching closing delmiter
+ character.
+
+Turning on PROMELA mode calls the value of the variable promela-mode-hook with
+no args, if that value is non-nil.
+
+For example: '
+ (setq promela-mode-hook '(lambda ()
+ (setq promela-block-indent 2)
+ (setq promela-selection-indent 0)
+ (setq promela-selection-option-indent 2)
+ (local-set-key \"\\C-m\" 'promela-indent-newline-indent)
+ ))'
+
+will indent block two steps, will make selection options aligned with DO/IF
+and sub-option lines indent to a column after the `::'. Also, lines will
+be reindented when you hit RETURN.
+
+Note that promela-mode adhears to the font-lock \"standards\" and
+defines several \"levels\" of fontification or colorization. The
+default is fairly gaudy, so if you would prefer a bit less, please see
+the documentation for the variable: `font-lock-maximum-decoration'.
+"
+ (interactive)
+ (kill-all-local-variables)
+ (setq mode-name "Promela")
+ (setq major-mode 'promela-mode)
+ (use-local-map promela-mode-map)
+ (set-syntax-table promela-mode-syntax-table)
+ (setq local-abbrev-table promela-mode-abbrev-table)
+
+ ;; Make local variables
+ (make-local-variable 'case-fold-search)
+ (make-local-variable 'paragraph-start)
+ (make-local-variable 'paragraph-separate)
+ (make-local-variable 'paragraph-ignore-fill-prefix)
+ (make-local-variable 'indent-line-function)
+ (make-local-variable 'indent-region-function)
+ (make-local-variable 'parse-sexp-ignore-comments)
+ (make-local-variable 'comment-start)
+ (make-local-variable 'comment-end)
+ (make-local-variable 'comment-column)
+ (make-local-variable 'comment-start-skip)
+ (make-local-variable 'comment-indent-hook)
+ (make-local-variable 'defun-prompt-regexp)
+ (make-local-variable 'compile-command)
+ ;; Now set their values
+ (setq case-fold-search t
+ paragraph-start (concat "^$\\|" page-delimiter)
+ paragraph-separate paragraph-start
+ paragraph-ignore-fill-prefix t
+ indent-line-function 'promela-indent-command
+ ;;indent-region-function 'promela-indent-region
+ parse-sexp-ignore-comments t
+ comment-start "/* "
+ comment-end " */"
+ comment-column 32
+ comment-start-skip "/\\*+ *"
+ ;;comment-start-skip "/\\*+ *\\|// *"
+ ;;comment-indent-hook 'promela-comment-indent
+ defun-prompt-regexp promela-defun-prompt-regexp
+ )
+
+ ;; Turn on font-lock mode
+ ;; (and promela-font-lock-mode (font-lock-mode))
+ (font-lock-mode)
+
+ ;; Finally, run the hooks and be done.
+ (run-hooks 'promela-mode-hook))
+
+\f
+;; -------------------------------------------------------------------------
+;; Interactive functions
+;;
+
+(defun promela-mode-version ()
+ "Print the current version of promela-mode in the minibuffer"
+ (interactive)
+ (message (concat "Promela-Mode: " promela-mode-version)))
+
+(defun promela-beginning-of-block ()
+ "Move backward to start of containing block.
+Containing block may be `{', `do' or `if' construct, or comment."
+ (interactive)
+ (goto-char (promela-find-start-of-containing-block-or-comment)))
+
+(defun promela-beginning-of-defun (&optional arg)
+ "Move backward to the beginning of a defun.
+With argument, do it that many times.
+Negative arg -N means move forward to Nth following beginning of defun.
+Returns t unless search stops due to beginning or end of buffer.
+
+See also 'beginning-of-defun.
+
+This is a Promela-mode specific version since default (in xemacs 19.16 and
+NT-Emacs 20) don't seem to skip comments - they will stop inside them.
+
+Also, this makes sure that the beginning of the defun is actually the
+line which starts the proctype/init/etc., not just the open-brace."
+ (interactive "p")
+ (beginning-of-defun arg)
+ (if (not (looking-at promela-defun-prompt-regexp))
+ (re-search-backward promela-defun-prompt-regexp nil t))
+ (if (promela-inside-comment-p)
+ (goto-char (promela-find-start-of-containing-comment))))
+
+(defun promela-indent-command ()
+ "Indent the current line as PROMELA code."
+ (interactive)
+ (if (and (not promela-tab-always-indent)
+ (save-excursion
+ (skip-chars-backward " \t")
+ (not (bolp))))
+ (tab-to-tab-stop)
+ (promela-indent-line)))
+
+(defun promela-newline-and-indent ()
+ "Promela-mode specific newline-and-indent which expands abbrevs before
+running a regular newline-and-indent."
+ (interactive)
+ (if abbrev-mode
+ (expand-abbrev))
+ (newline-and-indent))
+
+(defun promela-indent-newline-indent ()
+ "Promela-mode specific newline-and-indent which expands abbrevs and
+indents the current line before running a regular newline-and-indent."
+ (interactive)
+ (save-excursion (promela-indent-command))
+ (if abbrev-mode
+ (expand-abbrev))
+ (newline-and-indent))
+
+(defun promela-insert-and-indent ()
+ "Insert the last character typed and re-indent the current line"
+ (interactive)
+ (insert last-command-char)
+ (save-excursion (promela-indent-command)))
+
+(defun promela-open-delimiter ()
+ "Inserts the open and matching close delimiters, indenting as appropriate."
+ (interactive)
+ (insert last-command-char)
+ (if (and promela-auto-match-delimiter (not (promela-inside-comment-p)))
+ (save-excursion
+ (insert (cdr (assq last-command-char promela-matching-delimiter-alist)))
+ (promela-indent-command))))
+
+(defun promela-close-delimiter ()
+ "Inserts and indents a close delimiter."
+ (interactive)
+ (insert last-command-char)
+ (if (not (promela-inside-comment-p))
+ (save-excursion (promela-indent-command))))
+
+(defun promela-toggle-auto-match-delimiter ()
+ "Toggle auto-insertion of parens and other delimiters.
+See variable `promela-auto-insert-matching-delimiter'"
+ (interactive)
+ (setq promela-auto-match-delimiter
+ (not promela-auto-match-delimiter))
+ (message (concat "Promela auto-insert matching delimiters "
+ (if promela-auto-match-delimiter
+ "enabled" "disabled"))))
+
+\f
+;; -------------------------------------------------------------------------
+;; Compilation/Verification functions
+
+;; all of this is in serious "beta" mode - don't trust it ;-)
+(setq
+ promela-compile-command "spin "
+ promela-syntax-check-args "-a -v "
+)
+
+;;(setq compilation-error-regexp-alist
+;; (append compilation-error-regexp-alist
+;; '(("spin: +line +\\([0-9]+\\) +\"\\([^\"]+\\)\"" 2 1))))
+
+(defun promela-syntax-check ()
+ (interactive)
+ (compile (concat promela-compile-command
+ promela-syntax-check-args
+ (buffer-name))))
+
+\f
+;; -------------------------------------------------------------------------
+;; Indentation support functions
+
+(defun promela-indent-around-label ()
+ "Indent the current line as PROMELA code,
+but make sure to consider the label at the beginning of the line."
+ (beginning-of-line)
+ (delete-horizontal-space) ; delete any leading whitespace
+ (if (not (looking-at "\\sw+:\\([ \t]*\\)"))
+ (error "promela-indent-around-label: no label on this line")
+ (goto-char (match-beginning 1))
+ (let* ((space (length (match-string 1)))
+ (indent (promela-calc-indent))
+ (wanted (max 0 (- indent (current-column)))))
+ (if (>= space wanted)
+ (delete-region (point) (+ (point) (- space wanted)))
+ (goto-char (+ (point) space))
+ (indent-to-column indent)))))
+
+;; Note that indentation is based ENTIRELY upon the indentation of the
+;; previous line(s), esp. the previous non-blank line and the line
+;; starting the current containgng block...
+(defun promela-indent-line ()
+ "Indent the current line as PROMELA code.
+Return the amount the by which the indentation changed."
+ (beginning-of-line)
+ (if (looking-at "[ \t]*\\sw+:")
+ (promela-indent-around-label)
+ (let ((indent (promela-calc-indent))
+ beg
+ shift-amt
+ (pos (- (point-max) (point))))
+ (setq beg (point))
+ (skip-chars-forward " \t")
+ (setq shift-amt (- indent (current-column)))
+ (if (zerop shift-amt)
+ (if (> (- (point-max) pos) (point))
+ (goto-char (- (point-max) pos)))
+ (delete-region beg (point))
+ (indent-to indent)
+ (if (> (- (point-max) pos) (point))
+ (goto-char (- (point-max) pos))))
+ shift-amt)))
+
+(defun promela-calc-indent ()
+ "Return the appropriate indentation for this line as an int."
+ (save-excursion
+ (beginning-of-line)
+ (let* ((orig-point (point))
+ (state (promela-parse-partial-sexp))
+ (paren-depth (nth 0 state))
+ (paren-point (or (nth 1 state) 1))
+ (paren-char (char-after paren-point)))
+ ;;(what-cursor-position)
+ (cond
+ ;; Indent not-at-all - inside a string
+ ((nth 3 state)
+ (current-indentation))
+ ;; Indent inside a comment
+ ((nth 4 state)
+ (promela-calc-indent-within-comment))
+ ;; looking at a pre-processor directive - indent=0
+ ((looking-at "[ \t]*#\\(define\\|if\\(n?def\\)?\\|else\\|endif\\)")
+ 0)
+ ;; If we're not inside a "true" block (i.e. "{}"), then indent=0
+ ;; I think this is fair, since no (indentable) code in promela
+ ;; exists outside of a proctype or similar "{ .. }" structure.
+ ((zerop paren-depth)
+ 0)
+ ;; Indent relative to non curly-brace "paren"
+ ;; [ NOTE: I'm saving this, but don't use it any more.
+ ;; Now, we let parens be indented like curly braces
+ ;;((and (>= paren-depth 1) (not (char-equal ?\{ paren-char)))
+ ;; (goto-char paren-point)
+ ;; (1+ (current-column)))
+ ;;
+ ;; Last option: indent relative to contaning block(s)
+ (t
+ (goto-char orig-point)
+ (promela-calc-indent-within-block paren-point))))))
+
+(defun promela-calc-indent-within-block (&optional limit)
+ "Return the appropriate indentation for this line, assume within block.
+with optional arg, limit search back to `limit'"
+ (save-excursion
+ (let* ((stop (or limit 1))
+ (block-point (promela-find-start-of-containing-block stop))
+ (block-type (promela-block-type-after block-point))
+ (indent-point (point))
+ (indent-type (promela-block-type-after indent-point)))
+ (if (not block-type) 0
+ ;;(message "paren: %d (%d); block: %s (%d); indent: %s (%d); stop: %d"
+ ;; paren-depth paren-point block-type block-point
+ ;; indent-type indent-point stop)
+ (goto-char block-point)
+ (cond
+ ;; Indent (options) inside "if" or "do"
+ ((memq block-type '(selection iteration))
+ (if (re-search-forward "\\(do\\|if\\)[ \t]*::" indent-point t)
+ (- (current-column) 2)
+ (+ (current-column) promela-selection-indent)))
+ ;; indent (generic code) inside "::" option
+ ((eq 'option block-type)
+ (if (and (not indent-type)
+ (re-search-forward "::.*->[ \t]*\\sw"
+ (save-excursion (end-of-line) (point))
+ t))
+ (1- (current-column))
+ (+ (current-column) promela-selection-option-indent))
+ )
+ ;; indent code inside "{"
+ ((eq 'block block-type)
+ (cond
+ ;; if we are indenting the end of a block,
+ ;; use indentation of start-of-block
+ ((equal 'block-end indent-type)
+ (current-indentation))
+ ;; if the start of the code inside the block is not at eol
+ ;; then indent to the same column as the block start +some
+ ;; [ but ignore comments after "{" ]
+ ((and (not (promela-effective-eolp (1+ (point))))
+ (not (looking-at "{[ \t]*/\\*")))
+ (forward-char) ; skip block-start
+ (skip-chars-forward "{ \t") ; skip whitespace, if any
+ (current-column))
+ ;; anything else we indent +promela-block-indent from
+ ;; the indentation of the start of block (where we are now)
+ (t
+ (+ (current-indentation)
+ promela-block-indent))))
+ ;; dunno what kind of block this is - sound an error
+ (t
+ (error "promela-calc-indent-within-block: unknown block type: %s" block-type)
+ (current-indentation)))))))
+
+(defun promela-calc-indent-within-comment ()
+ "Return the indentation amount for line, assuming that the
+current line is to be regarded as part of a block comment."
+ (save-excursion
+ (beginning-of-line)
+ (skip-chars-forward " \t")
+ (let ((indenting-end-of-comment (looking-at "\\*/"))
+ (indenting-blank-line (eolp)))
+ ;; if line is NOT blank and next char is NOT a "*'
+ (if (not (or indenting-blank-line (= (following-char) ?\*)))
+ ;; leave indent alone
+ (current-column)
+ ;; otherwise look back for _PREVIOUS_ possible nested comment start
+ (let ((comment-start (save-excursion
+ (re-search-backward comment-start-skip))))
+ ;; and see if there is an appropriate middle-comment "*"
+ (if (re-search-backward "^[ \t]+\\*" comment-start t)
+ (current-indentation)
+ ;; guess not, so indent relative to comment start
+ (goto-char comment-start)
+ (if indenting-end-of-comment
+ (current-column)
+ (1+ (current-column)))))))))
+
+\f
+;; -------------------------------------------------------------------------
+;; Misc other support functions
+
+(defun promela-parse-partial-sexp (&optional start limit)
+ "Return the partial parse state of current defun or from optional start
+to end limit"
+ (save-excursion
+ (let ((end (or limit (point))))
+ (if start
+ (goto-char start)
+ (promela-beginning-of-defun))
+ (parse-partial-sexp (point) end))))
+
+;;(defun promela-at-end-of-block-p ()
+;; "Return t if cursor is at the end of a promela block"
+;; (save-excursion
+;; (let ((eol (progn (end-of-line) (point))))
+;; (beginning-of-line)
+;; (skip-chars-forward " \t")
+;; ;;(re-search-forward "\\(}\\|\\b\\(od\\|fi\\)\\b\\)" eol t))))
+;; (looking-at "[ \t]*\\(od\\|fi\\)\\b"))))
+
+(defun promela-inside-comment-p ()
+ "Check if the point is inside a comment block."
+ (save-excursion
+ (let ((origpoint (point))
+ state)
+ (goto-char 1)
+ (while (> origpoint (point))
+ (setq state (parse-partial-sexp (point) origpoint 0)))
+ (nth 4 state))))
+
+(defun promela-inside-comment-or-string-p ()
+ "Check if the point is inside a comment or a string."
+ (save-excursion
+ (let ((origpoint (point))
+ state)
+ (goto-char 1)
+ (while (> origpoint (point))
+ (setq state (parse-partial-sexp (point) origpoint 0)))
+ (or (nth 3 state) (nth 4 state)))))
+
+
+(defun promela-effective-eolp (&optional point)
+ "Check if we are at the effective end-of-line, ignoring whitespace"
+ (save-excursion
+ (if point (goto-char point))
+ (skip-chars-forward " \t")
+ (eolp)))
+
+(defun promela-check-expansion ()
+ "If abbrev was made within a comment or a string, de-abbrev!"
+ (if promela-inside-comment-or-string-p
+ (unexpand-abbrev)))
+
+(defun promela-block-type-after (&optional point)
+ "Return the type of block after current point or parameter as a symbol.
+Return one of 'iteration `do', 'selection `if', 'option `::',
+'block `{' or `}' or nil if none of the above match."
+ (save-excursion
+ (goto-char (or point (point)))
+ (skip-chars-forward " \t")
+ (cond
+ ((looking-at "do\\b") 'iteration)
+ ;;((looking-at "od\\b") 'iteration-end)
+ ((looking-at "if\\b") 'selection)
+ ;;((looking-at "fi\\b") 'selection-end)
+ ((looking-at "::") 'option)
+ ((looking-at "[{(]") 'block)
+ ((looking-at "[})]") 'block-end)
+ (t nil))))
+
+(defun promela-find-start-of-containing-comment (&optional limit)
+ "Return the start point of the containing comment block.
+Stop at `limit' or beginning of buffer."
+ (let ((stop (or limit 1)))
+ (save-excursion
+ (while (and (>= (point) stop)
+ (nth 4 (promela-parse-partial-sexp)))
+ (re-search-backward comment-start-skip stop t))
+ (point))))
+
+(defun promela-find-start-of-containing-block (&optional limit)
+ "Return the start point of the containing `do', `if', `::' or
+`{' block or containing comment.
+Stop at `limit' or beginning of buffer."
+ (save-excursion
+ (skip-chars-forward " \t")
+ (let* ((type (promela-block-type-after))
+ (stop (or limit
+ (save-excursion (promela-beginning-of-defun) (point))))
+ (state (promela-parse-partial-sexp stop))
+ (level (if (looking-at "\\(od\\|fi\\)\\b")
+ 2
+ (if (zerop (nth 0 state)) 0 1))))
+ ;;(message "find-start-of-containing-block: type: %s; level %d; stop %d"
+ ;; type level stop)
+ (while (and (> (point) stop) (not (zerop level)))
+ (re-search-backward
+ "\\({\\|}\\|::\\|\\b\\(do\\|od\\|if\\|fi\\)\\b\\)"
+ stop 'move)
+ ;;(message "looking from %d back-to %d" (point) stop)
+ (setq state (promela-parse-partial-sexp stop))
+ (setq level (+ level
+ (cond ((or (nth 3 state) (nth 4 state)) 0)
+ ((and (= 1 level) (looking-at "::")
+ (not (equal type 'option))) -1)
+ ((looking-at "\\({\\|\\(do\\|if\\)\\b\\)") -1)
+ ((looking-at "\\(}\\|\\(od\\|fi\\)\\b\\)") +1)
+ (t 0)))))
+ (point))))
+
+(defun promela-find-start-of-containing-block-or-comment (&optional limit)
+ "Return the start point of the containing comment or
+the start of the containing `do', `if', `::' or `{' block.
+Stop at limit or beginning of buffer."
+ (if (promela-inside-comment-p)
+ (promela-find-start-of-containing-comment limit)
+ (promela-find-start-of-containing-block limit)))
+
+;; -------------------------------------------------------------------------
+;; Debugging/testing
+
+;; (defun promela-mode-toggle-debug ()
+;; (interactive)
+;; (make-local-variable 'debug-on-error)
+;; (setq debug-on-error (not debug-on-error)))
+
+;;(defun promela-mode-revert-buffer ()
+;; (interactive)
+;; (revert-buffer t t))
+
+;; -------------------------------------------------------------------------
+;;###autoload
+
+(provide 'promela-mode)
+
+\f
+;;----------------------------------------------------------------------
+;; Change History:
+;;
+;; $Log: promela-mode.el,v $
+;; Revision 1.11 2001/07/09 18:36:45 engstrom
+;; - added comments on use of font-lock-maximum-decoration
+;; - moved basic preprocess directive fontification to "level 2"
+;;
+;; Revision 1.10 2001/05/22 16:29:59 engstrom
+;; - fixed error introduced in fontification levels stuff (xemacs only)
+;;
+;; Revision 1.9 2001/05/22 16:21:29 engstrom
+;; - commented out the compilation / syntax check stuff for now
+;;
+;; Revision 1.8 2001/05/22 16:18:49 engstrom
+;; - Munched history in preparation for first non-Honeywell release
+;; - Added "levels" of fontification to be controlled by the std. variable:
+;; 'font-lock-maximum-decoration'
+;;
+;; Revision 1.7 2001/04/20 01:41:46 engstrom
+;; Revision 1.6 2001/04/06 23:57:18 engstrom
+;; Revision 1.5 2001/04/04 20:04:15 engstrom
+;; Revision 1.4 2001/03/15 02:22:18 engstrom
+;; Revision 1.3 2001/03/09 19:39:51 engstrom
+;; Revision 1.2 2001/03/01 18:07:47 engstrom
+;; Revision 1.1 2001/02/01 xx:xx:xx engstrom
+;; migrated to CVS versioning...
+;; Pre-CVS-History:
+;; 99-10-04 V0.4 EDE Fixed bug in end-of-block indentation
+;; Simplified indentation code significantly
+;; 99-09-2x V0.3 EDE Hacked on indentation more while at FM'99
+;; 99-09-16 V0.2 EDE Hacked, hacked, hacked on indentation
+;; 99-04-01 V0.1 EDE Introduced (less-than) half-baked indentation
+;; 98-11-05 V0.0 EDE Created - much code stolen from rexx-mode.el
+;; Mostly just a fontification mode -
+;; (indentation is HARD ;-)
+;;
+;; EOF promela-mode.el
--- /dev/null
+#!/bin/bash
+
+#avail. mem
+MEM=15360
+
+#spin -a model.spin
+#cc -DMEMLIM=${MEM} -DSAFETY -o pan pan.c
+#./pan
+
+#first LTL formula
+cat defines > pan.ltl
+/usr/local/bin/spin -f "!($(cat model_03_write_read_off.spin.ltl | grep -v ^//))" >> pan.ltl
+/usr/local/bin/spin -a -X -N pan.ltl model.spin
+
+gcc -w -o pan -D_POSIX_SOURCE -DMEMLIM=1850 -DXUSAFE -DNOFAIR pan.c
+time ./pan -v -X -m10000 -w19 -a -c1
+
+#second LTL formula
+cat defines > pan.ltl
+/usr/local/bin/spin -f "!($(cat model_03_write_commit_sum.spin.ltl | grep -v ^//))" >> pan.ltl
+/usr/local/bin/spin -a -X -N pan.ltl model.spin
+
+gcc -w -o pan -D_POSIX_SOURCE -DMEMLIM=1850 -DXUSAFE -DNOFAIR pan.c
+time ./pan -v -X -m10000 -w19 -a -c1
+
+#3rd
+cat defines > pan.ltl
+/usr/local/bin/spin -f "!($(cat model_03_events_lost.spin.ltl | grep -v ^//))" >> pan.ltl
+/usr/local/bin/spin -a -X -N pan.ltl model.spin
+
+gcc -w -o pan -D_POSIX_SOURCE -DMEMLIM=1850 -DXUSAFE -DNOFAIR pan.c
+time ./pan -v -X -m10000 -w19 -a -c1
+
+#4th
+cat defines > pan.ltl
+/usr/local/bin/spin -f "!($(cat model_03_no_events_lost.spin.ltl | grep -v ^//))" >> pan.ltl
+/usr/local/bin/spin -a -X -N pan.ltl model.spin
+
+gcc -w -o pan -D_POSIX_SOURCE -DMEMLIM=1850 -DXUSAFE -DNOFAIR pan.c
+time ./pan -v -X -m10000 -w19 -a -c1
+
+
+
+
--- /dev/null
+# makefile
+
+COPTIONS=-DSAFETY
+
+
+default:
+ make commit_sum | tee commit_sum.log
+ make read_write | tee read_write.log
+ make events_lost | tee events_lost.log
+ make no_events_lost | tee no_events_lost.log
+
+
+no_events_lost: clean no_events_lost_ltl run
+
+no_events_lost_ltl:
+ cat defines > pan.ltl
+ cat no_events_lost.def > pan.spin
+ spin -f "!(`cat no_events_lost.ltl | grep -v ^//`)" >> pan.ltl
+
+
+
+events_lost: clean events_lost_ltl run
+
+events_lost_ltl:
+ cat defines > pan.ltl
+ spin -f "!(`cat events_lost.ltl | grep -v ^//`)" >> pan.ltl
+
+
+
+read_write: clean read_write_ltl run
+
+read_write_ltl:
+ cat defines > pan.ltl
+ spin -f "!(`cat read_write.ltl | grep -v ^//`)" >> pan.ltl
+
+
+
+commit_sum: clean commit_sum_ltl run
+
+commit_sum_ltl:
+ cat defines > pan.ltl
+ spin -f "!(`cat commit_sum.ltl | grep -v ^//`)" >> pan.ltl
+
+
+
+run: pan
+ ./pan -v -X -m100000 -w21 -a -c1
+
+pan: pan.c
+ gcc -w -o pan -D_POSIX_SOURCE -DMEMLIM=750 -DXUSAFE -DNOFAIR pan.c
+
+pan.c: pan.ltl model.spin
+ cat model.spin >> pan.spin
+ spin -a -X -N pan.ltl pan.spin
+
+
+
+clean:
+ rm -f pan* trail.out
--- /dev/null
+make[1]: Entering directory `/home/compudj/repository/trunk/verif/nico-md-merge'
+rm -f pan* trail.out
+cat defines > pan.ltl
+spin -f "!(`cat commit_sum.ltl | grep -v ^//`)" >> pan.ltl
+spin -a -X -N pan.ltl model.spin
+Exit-Status 0
+gcc -w -o pan -D_POSIX_SOURCE -DMEMLIM=750 -DXUSAFE -DNOFAIR pan.c
+./pan -v -X -m100000 -w21 -a -c1
+warning: for p.o. reduction to be valid the never claim must be stutter-invariant
+(never claims generated from LTL formulae are stutter-invariant)
+depth 0: Claim reached state 5 (line 302)
+
+(Spin Version 5.1.6 -- 9 May 2008)
+ + Partial Order Reduction
+
+Full statespace search for:
+ never claim +
+ assertion violations + (if within scope of claim)
+ acceptance cycles + (fairness disabled)
+ invalid end states - (disabled by never claim)
+
+State-vector 92 byte, depth reached 178, errors: 0
+ 117886 states, stored
+ 210653 states, matched
+ 328539 transitions (= stored+matched)
+ 440774 atomic steps
+hash conflicts: 3201 (resolved)
+
+Stats on memory usage (in Megabytes):
+ 12.142 equivalent memory usage for states (stored*(State-vector + overhead))
+ 8.971 actual memory usage for states (compression: 73.88%)
+ state-vector as stored = 64 byte + 16 byte overhead
+ 8.000 memory used for hash table (-w21)
+ 3.052 memory used for DFS stack (-m100000)
+ 19.939 total actual memory usage
+
+unreached in proctype switcher
+ line 81, "pan.___", state 8, "(1)"
+ line 87, "pan.___", state 15, "write_off = new_off"
+ line 84, "pan.___", state 18, "((prev_off!=write_off))"
+ line 84, "pan.___", state 18, "else"
+ line 97, "pan.___", state 21, "commit_count[((prev_off%4)/(4/2))] = tmp_commit"
+ line 103, "pan.___", state 25, "(1)"
+ line 98, "pan.___", state 26, "((((((prev_off/4)*4)/2)+(4/2))-tmp_commit))"
+ line 98, "pan.___", state 26, "else"
+ line 91, "pan.___", state 29, "tmp_commit = (commit_count[((prev_off%4)/(4/2))]+size)"
+ (7 of 31 states)
+unreached in proctype tracer
+ line 177, "pan.___", state 48, "events_lost = (events_lost+1)"
+ (1 of 51 states)
+unreached in proctype reader
+ (0 of 29 states)
+unreached in proctype cleaner
+ (0 of 9 states)
+unreached in proctype :init:
+ line 284, "pan.___", state 35, "(run switcher())"
+ (1 of 43 states)
+unreached in proctype :never:
+ line 307, "pan.___", state 8, "-end-"
+ (1 of 8 states)
+
+pan: elapsed time 0.91 seconds
+pan: rate 129545.05 states/second
+pan: avg transition delay 2.7698e-06 usec
+make[1]: Leaving directory `/home/compudj/repository/trunk/verif/nico-md-merge'
--- /dev/null
+// The sum of all subbuffer commit counts must always be lower or equal
+// to the writer head, because space must be reserved before it is
+// written to and then committed.
+// assert(write_off - _commit_sum >= 0 && write_off - _commit_sum < HALF_UCHAR);
+
+[] (wcsum1 && wcsum2)
--- /dev/null
+#define rwoff1 (write_off - read_off >= 0)
+#define rwoff2 (write_off - read_off < HALF_UCHAR)
+
+#define wcsum1 (write_off - _commit_sum >= 0)
+#define wcsum2 (write_off - _commit_sum < HALF_UCHAR)
+
+#define buffer_large_enough (NUMPROCS + NUMSWITCH <= BUFSIZE)
+#define have_events_lost (events_lost != 0)
--- /dev/null
+make[1]: Entering directory `/home/compudj/repository/trunk/verif/nico-md-merge'
+rm -f pan* trail.out
+cat defines > pan.ltl
+spin -f "!(`cat events_lost.ltl | grep -v ^//`)" >> pan.ltl
+spin -a -X -N pan.ltl model.spin
+Exit-Status 0
+gcc -w -o pan -D_POSIX_SOURCE -DMEMLIM=750 -DXUSAFE -DNOFAIR pan.c
+./pan -v -X -m100000 -w21 -a -c1
+warning: for p.o. reduction to be valid the never claim must be stutter-invariant
+(never claims generated from LTL formulae are stutter-invariant)
+depth 0: Claim reached state 5 (line 302)
+
+(Spin Version 5.1.6 -- 9 May 2008)
+ + Partial Order Reduction
+
+Full statespace search for:
+ never claim +
+ assertion violations + (if within scope of claim)
+ acceptance cycles + (fairness disabled)
+ invalid end states - (disabled by never claim)
+
+State-vector 92 byte, depth reached 178, errors: 0
+ 117886 states, stored
+ 210653 states, matched
+ 328539 transitions (= stored+matched)
+ 440774 atomic steps
+hash conflicts: 3201 (resolved)
+
+Stats on memory usage (in Megabytes):
+ 12.142 equivalent memory usage for states (stored*(State-vector + overhead))
+ 8.971 actual memory usage for states (compression: 73.88%)
+ state-vector as stored = 64 byte + 16 byte overhead
+ 8.000 memory used for hash table (-w21)
+ 3.052 memory used for DFS stack (-m100000)
+ 19.939 total actual memory usage
+
+unreached in proctype switcher
+ line 81, "pan.___", state 8, "(1)"
+ line 87, "pan.___", state 15, "write_off = new_off"
+ line 84, "pan.___", state 18, "((prev_off!=write_off))"
+ line 84, "pan.___", state 18, "else"
+ line 97, "pan.___", state 21, "commit_count[((prev_off%4)/(4/2))] = tmp_commit"
+ line 103, "pan.___", state 25, "(1)"
+ line 98, "pan.___", state 26, "((((((prev_off/4)*4)/2)+(4/2))-tmp_commit))"
+ line 98, "pan.___", state 26, "else"
+ line 91, "pan.___", state 29, "tmp_commit = (commit_count[((prev_off%4)/(4/2))]+size)"
+ (7 of 31 states)
+unreached in proctype tracer
+ line 177, "pan.___", state 48, "events_lost = (events_lost+1)"
+ (1 of 51 states)
+unreached in proctype reader
+ (0 of 29 states)
+unreached in proctype cleaner
+ (0 of 9 states)
+unreached in proctype :init:
+ line 284, "pan.___", state 35, "(run switcher())"
+ (1 of 43 states)
+unreached in proctype :never:
+ line 307, "pan.___", state 8, "-end-"
+ (1 of 8 states)
+
+pan: elapsed time 0.86 seconds
+pan: rate 137076.74 states/second
+pan: avg transition delay 2.6176e-06 usec
+make[1]: Leaving directory `/home/compudj/repository/trunk/verif/nico-md-merge'
--- /dev/null
+// If we have less writers than the buffer space available, we should
+// not loose events.
+// assert(NUMPROCS + NUMSWITCH > BUFSIZE || events_lost == 0);
+
+[]((have_events_lost) -> (!buffer_large_enough))
--- /dev/null
+models/model_03.spin
\ No newline at end of file
--- /dev/null
+-2:5:-2
+-4:-4:-4
+1:0:165
+2:1:120
+3:1:121
+4:1:121
+5:1:124
+6:1:131
+7:1:131
+8:1:131
+9:1:131
+10:1:134
+11:1:139
+12:1:140
+13:1:142
+14:1:144
+15:1:142
+16:1:144
+17:1:142
+18:1:144
+19:1:142
+20:1:144
+21:1:146
+22:1:152
+23:1:154
+24:1:156
+25:1:160
+26:0:165
+27:7:31
+28:0:165
+29:7:36
+30:7:37
+31:0:165
+32:7:43
+33:7:44
+34:7:48
+35:7:52
+36:7:56
+37:0:165
+38:8:0
+39:8:6
+40:8:7
+41:0:165
+42:8:13
+43:8:14
+44:0:165
+45:8:18
+46:8:21
+47:0:165
+48:8:29
+49:0:165
+50:8:30
+51:0:165
+52:7:58
+53:7:59
+54:7:62
+55:7:72
+56:7:73
+57:0:165
+58:7:77
+59:7:79
+60:0:165
+61:7:81
+62:0:165
+63:6:31
+64:0:165
+65:6:36
+66:6:37
+67:0:165
+68:6:43
+69:6:44
+70:6:48
+71:6:52
+72:6:56
+73:0:165
+74:6:58
+75:6:59
+76:6:62
+77:6:70
+78:0:165
+79:6:77
+80:6:79
+81:0:165
+82:6:81
+83:0:165
+84:5:31
+85:0:165
+86:5:36
+87:5:37
+88:0:165
+89:5:43
+90:5:44
+91:5:48
+92:5:52
+93:5:56
+94:0:165
+95:5:58
+96:5:59
+97:5:62
+98:5:72
+99:5:73
+100:0:165
+101:5:77
+102:5:79
+103:0:165
+104:5:81
+105:0:165
+106:4:31
+107:0:165
+108:4:34
+109:4:78
+110:4:79
+111:0:163
+112:4:81
+113:0:169
+114:6:52
--- /dev/null
+/* LTTng ltt-tracer.c atomic lockless buffering scheme Promela model v2
+ * Created for the Spin validator.
+ * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ * October 2008
+
+ * TODO : create test cases that will generate an overflow on the offset and
+ * counter type. Counter types smaller than a byte should be used.
+
+ * Promela only has unsigned char, no signed char.
+ * Because detection of difference < 0 depends on a signed type, but we want
+ * compactness, check also for the values being higher than half of the unsigned
+ * char range (and consider them negative). The model, by design, does not use
+ * offsets or counts higher than 127 because we would then have to use a larger
+ * type (short or int).
+ */
+#define HALF_UCHAR (255/2)
+
+/* NUMPROCS 4 : causes event loss with some reader timings.
+ * e.g. 3 events, 1 switch, 1 event (lost, buffer full), read 1 subbuffer
+ */
+#define NUMPROCS 4
+
+/* NUMPROCS 3 : does not cause event loss because buffers are big enough.
+ * #define NUMPROCS 3
+ * e.g. 3 events, 1 switch, read 1 subbuffer
+ */
+
+#define NUMSWITCH 1
+#define BUFSIZE 4
+#define NR_SUBBUFS 2
+#define SUBBUF_SIZE (BUFSIZE / NR_SUBBUFS)
+
+/* Writer counters
+*/
+byte write_off = 0;
+byte commit_count[NR_SUBBUFS];
+
+/* Reader counters
+*/
+byte read_off = 0;
+
+byte events_lost = 0;
+byte refcount = 0;
+
+bool deliver = 0;
+
+/* buffer slot in-use bit. Detects racy use (more than a single process
+ * accessing a slot at any given step).
+ */
+bool buffer_use[BUFSIZE];
+
+/* Proceed to a sub-subber switch is needed.
+ * Used in a periodical timer interrupt to fill and ship the current subbuffer
+ * to the reader so we can guarantee a steady flow. If a subbuffer is
+ * completely empty, do not switch.
+ * Also used as "finalize" operation to complete the last subbuffer after
+ * all writers have finished so the last subbuffer can be read by the reader.
+ */
+proctype switcher()
+{
+ byte prev_off, new_off, tmp_commit;
+ byte size;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ size = SUBBUF_SIZE - (prev_off % SUBBUF_SIZE);
+ new_off = prev_off + size;
+ if
+ :: (new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR)
+ || size == SUBBUF_SIZE ->
+ refcount = refcount - 1;
+ goto not_needed;
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ }
+
+ atomic {
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ refcount = refcount - 1;
+ }
+not_needed:
+ skip;
+}
+
+/* tracer
+ * Writes 1 byte of information in the buffer at the current
+ * "write_off" position and then increment the commit_count of the sub-buffer
+ * the information has been written to.
+ */
+proctype tracer()
+{
+ byte size = 1;
+ byte prev_off, new_off, tmp_commit;
+ byte i, j;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ new_off = prev_off + size;
+ }
+ atomic {
+ if
+ :: new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR ->
+ goto lost
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ i = 0;
+ do
+ :: i < size ->
+ assert(buffer_use[(prev_off + i) % BUFSIZE] == 0);
+ buffer_use[(prev_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= size -> break
+ od;
+ }
+
+ /* writing to buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < size ->
+ buffer_use[(prev_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= size -> break
+ od;
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ }
+ atomic {
+ goto end;
+lost:
+ events_lost++;
+end:
+ refcount = refcount - 1;
+ }
+}
+
+/* reader
+ * Read the information sub-buffer per sub-buffer when available.
+ *
+ * Reads the information as soon as it is ready, or may be delayed by
+ * an asynchronous delivery. Being modeled as a process insures all cases
+ * (scheduled very quickly or very late, causing event loss) are covered.
+ * Only one reader per buffer (normally ensured by a mutex). This is modeled
+ * by using a single reader process.
+ */
+proctype reader()
+{
+ byte i, j;
+
+ do
+ :: (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) > 0
+ && (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) < HALF_UCHAR
+ && (commit_count[(read_off % BUFSIZE) / SUBBUF_SIZE]
+ - SUBBUF_SIZE - (((read_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS)
+ == 0) ->
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ assert(buffer_use[(read_off + i) % BUFSIZE] == 0);
+ buffer_use[(read_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ }
+
+ /* reading from buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ buffer_use[(read_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ read_off = read_off + SUBBUF_SIZE;
+ }
+ :: read_off >= (NUMPROCS - events_lost) -> break;
+ od;
+}
+
+/* Waits for all tracer and switcher processes to finish before finalizing
+ * the buffer. Only after that will the reader be allowed to read the
+ * last subbuffer.
+ */
+proctype cleaner()
+{
+ atomic {
+ do
+ :: refcount == 0 ->
+ refcount = refcount + 1;
+ run switcher(); /* Finalize the last sub-buffer so it can be read. */
+ break;
+ od;
+ }
+}
+
+init {
+ byte i = 0;
+ byte j = 0;
+ byte sum = 0;
+ byte commit_sum = 0;
+
+ atomic {
+ i = 0;
+ do
+ :: i < NR_SUBBUFS ->
+ commit_count[i] = 0;
+ i++
+ :: i >= NR_SUBBUFS -> break
+ od;
+ i = 0;
+ do
+ :: i < BUFSIZE ->
+ buffer_use[i] = 0;
+ i++
+ :: i >= BUFSIZE -> break
+ od;
+ run reader();
+ run cleaner();
+ i = 0;
+ do
+ :: i < NUMPROCS ->
+ refcount = refcount + 1;
+ run tracer();
+ i++
+ :: i >= NUMPROCS -> break
+ od;
+ i = 0;
+ do
+ :: i < NUMSWITCH ->
+ refcount = refcount + 1;
+ run switcher();
+ i++
+ :: i >= NUMSWITCH -> break
+ od;
+ }
+
+ /* Assertions.
+ */
+ atomic {
+ /* The writer head must always be superior or equal to the reader head.
+ */
+ assert(write_off - read_off >= 0 && write_off - read_off < HALF_UCHAR);
+ j = 0;
+ commit_sum = 0;
+ do
+ :: j < NR_SUBBUFS ->
+ commit_sum = commit_sum + commit_count[j];
+ /* The commit count of a particular subbuffer must always be higher
+ * or equal to the retrieve_count of this subbuffer.
+ * assert(commit_count[j] - retrieve_count[j] >= 0 &&
+ * commit_count[j] - retrieve_count[j] < HALF_UCHAR);
+ */
+ j++
+ :: j >= NR_SUBBUFS -> break
+ od;
+ /* The sum of all subbuffer commit counts must always be lower or equal
+ * to the writer head, because space must be reserved before it is
+ * written to and then committed.
+ */
+ assert(write_off - commit_sum >= 0 && write_off - commit_sum < HALF_UCHAR);
+
+ /* If we have less writers than the buffer space available, we should
+ * not lose events
+ */
+ assert(NUMPROCS + NUMSWITCH > BUFSIZE || events_lost == 0);
+ }
+}
+
--- /dev/null
+/* LTTng ltt-tracer.c atomic lockless buffering scheme Promela model v2
+ * Created for the Spin validator.
+ * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ * October 2008
+
+ * TODO : create test cases that will generate an overflow on the offset and
+ * counter type. Counter types smaller than a byte should be used.
+
+ * Promela only has unsigned char, no signed char.
+ * Because detection of difference < 0 depends on a signed type, but we want
+ * compactness, check also for the values being higher than half of the unsigned
+ * char range (and consider them negative). The model, by design, does not use
+ * offsets or counts higher than 127 because we would then have to use a larger
+ * type (short or int).
+ */
+#define HALF_UCHAR (255/2)
+
+/* NUMPROCS 4 : causes event loss with some reader timings.
+ * e.g. 3 events, 1 switch, 1 event (lost, buffer full), read 1 subbuffer
+ */
+#define NUMPROCS 4
+
+/* NUMPROCS 3 : does not cause event loss because buffers are big enough.
+ * #define NUMPROCS 3
+ * e.g. 3 events, 1 switch, read 1 subbuffer
+ */
+
+#define NUMSWITCH 1
+#define BUFSIZE 4
+#define NR_SUBBUFS 2
+#define SUBBUF_SIZE (BUFSIZE / NR_SUBBUFS)
+
+/* Writer counters
+*/
+byte write_off = 0;
+byte commit_count[NR_SUBBUFS];
+
+/* Reader counters
+*/
+byte read_off = 0;
+
+byte events_lost = 0;
+byte refcount = 0;
+
+bool deliver = 0;
+
+/* buffer slot in-use bit. Detects racy use (more than a single process
+ * accessing a slot at any given step).
+ */
+bool buffer_use[BUFSIZE];
+
+/* Proceed to a sub-subber switch is needed.
+ * Used in a periodical timer interrupt to fill and ship the current subbuffer
+ * to the reader so we can guarantee a steady flow. If a subbuffer is
+ * completely empty, do not switch.
+ * Also used as "finalize" operation to complete the last subbuffer after
+ * all writers have finished so the last subbuffer can be read by the reader.
+ */
+proctype switcher()
+{
+ byte prev_off, new_off, tmp_commit;
+ byte size;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ size = SUBBUF_SIZE - (prev_off % SUBBUF_SIE);
+ new_off = prev_off + size;
+ if
+ :: (new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR)
+ || size == SUBBUF_SIZE ->
+ refcount = refcount - 1;
+ goto not_needed;
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ }
+
+ atomic {
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ refcount = refcount - 1;
+ }
+not_needed:
+ skip;
+}
+
+/* tracer
+ * Writes 1 byte of information in the buffer at the current
+ * "write_off" position and then increment the commit_count of the sub-buffer
+ * the information has been written to.
+ */
+proctype tracer()
+{
+ byte size = 1;
+ byte prev_off, new_off, tmp_commit;
+ byte i, j;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ new_off = prev_off + size;
+ }
+ atomic {
+ if
+ :: new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR ->
+ goto lost
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ i = 0;
+ do
+ :: i < size ->
+ assert(buffer_use[(prev_off + i) % BUFSIZE] == 0);
+ buffer_use[(prev_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= size -> break
+ od;
+ }
+
+ /* writing to buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < size ->
+ buffer_use[(prev_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= size -> break
+ od;
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ }
+ atomic {
+ goto end;
+lost:
+ events_lost++;
+end:
+ refcount = refcount - 1;
+ }
+}
+
+/* reader
+ * Read the information sub-buffer per sub-buffer when available.
+ *
+ * Reads the information as soon as it is ready, or may be delayed by
+ * an asynchronous delivery. Being modeled as a process insures all cases
+ * (scheduled very quickly or very late, causing event loss) are covered.
+ * Only one reader per buffer (normally ensured by a mutex). This is modeled
+ * by using a single reader process.
+ */
+proctype reader()
+{
+ byte i, j;
+
+ do
+ :: (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) > 0
+ && (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) < HALF_UCHAR
+ && (commit_count[(read_off % BUFSIZE) / SUBBUF_SIZE]
+ - SUBBUF_SIZE - (((read_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS)
+ == 0) ->
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ assert(buffer_use[(read_off + i) % BUFSIZE] == 0);
+ buffer_use[(read_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ }
+
+ /* reading from buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ buffer_use[(read_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ read_off = read_off + SUBBUF_SIZE;
+ }
+ :: read_off >= (NUMPROCS - events_lost) -> break;
+ od;
+}
+
+/* Waits for all tracer and switcher processes to finish before finalizing
+ * the buffer. Only after that will the reader be allowed to read the
+ * last subbuffer.
+ */
+proctype cleaner()
+{
+ atomic {
+ do
+ :: refcount == 0 ->
+ refcount = refcount + 1;
+ run switcher(); /* Finalize the last sub-buffer so it can be read. */
+ break;
+ od;
+ }
+}
+
+init {
+ byte i = 0;
+ byte j = 0;
+ byte sum = 0;
+ byte commit_sum = 0;
+
+ atomic {
+ i = 0;
+ do
+ :: i < NR_SUBBUFS ->
+ commit_count[i] = 0;
+ i++
+ :: i >= NR_SUBBUFS -> break
+ od;
+ i = 0;
+ do
+ :: i < BUFSIZE ->
+ buffer_use[i] = 0;
+ i++
+ :: i >= BUFSIZE -> break
+ od;
+ run reader();
+ run cleaner();
+ i = 0;
+ do
+ :: i < NUMPROCS ->
+ refcount = refcount + 1;
+ run tracer();
+ i++
+ :: i >= NUMPROCS -> break
+ od;
+ i = 0;
+ do
+ :: i < NUMSWITCH ->
+ refcount = refcount + 1;
+ run switcher();
+ i++
+ :: i >= NUMSWITCH -> break
+ od;
+ }
+
+ /* Assertions.
+ */
+ atomic {
+ /* The writer head must always be superior or equal to the reader head.
+ */
+ /*assert(write_off - read_off >= 0 && write_off - read_off < HALF_UCHAR);*/
+ j = 0;
+ commit_sum = 0;
+ do
+ :: j < NR_SUBBUFS ->
+ commit_sum = commit_sum + commit_count[j];
+ j++
+ :: j >= NR_SUBBUFS -> break
+ od;
+ /* The sum of all subbuffer commit counts must always be lower or equal
+ * to the writer head, because space must be reserved before it is
+ * written to and then committed.
+ */
+ assert(write_off - commit_sum >= 0 && write_off - commit_sum < HALF_UCHAR);
+
+ /* If we have less writers than the buffer space available, we should
+ * not loose events
+ */
+ assert(NUMPROCS + NUMSWITCH > BUFSIZE || events_lost == 0);
+ }
+}
+
--- /dev/null
+/* LTTng ltt-tracer.c atomic lockless buffering scheme Promela model v2
+ * Created for the Spin validator.
+ * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ * October 2008
+
+ * TODO : create test cases that will generate an overflow on the offset and
+ * counter type. Counter types smaller than a byte should be used.
+
+ * Promela only has unsigned char, no signed char.
+ * Because detection of difference < 0 depends on a signed type, but we want
+ * compactness, check also for the values being higher than half of the unsigned
+ * char range (and consider them negative). The model, by design, does not use
+ * offsets or counts higher than 127 because we would then have to use a larger
+ * type (short or int).
+ */
+#define HALF_UCHAR (255/2)
+
+/* NUMPROCS 4 : causes event loss with some reader timings.
+ * e.g. 3 events, 1 switch, 1 event (lost, buffer full), read 1 subbuffer
+ */
+#define NUMPROCS 4
+
+/* NUMPROCS 3 : does not cause event loss because buffers are big enough.
+ * #define NUMPROCS 3
+ * e.g. 3 events, 1 switch, read 1 subbuffer
+ */
+
+#define NUMSWITCH 1
+#ifndef BUFSIZE
+#define BUFSIZE 4
+#endif
+#define NR_SUBBUFS 2
+#define SUBBUF_SIZE (BUFSIZE / NR_SUBBUFS)
+
+/* Writer counters
+*/
+byte write_off = 0;
+byte commit_count[NR_SUBBUFS];
+
+/* <formal_verif> */
+byte _commit_sum;
+/* </formal_verif> */
+
+/* Reader counters
+*/
+byte read_off = 0;
+
+byte events_lost = 0;
+byte refcount = 0;
+
+bool deliver = 0;
+
+//#ifdef RACE_TEST
+/* buffer slot in-use bit. Detects racy use (more than a single process
+ * accessing a slot at any given step).
+ */
+bool buffer_use[BUFSIZE];
+//#endif
+
+/* Proceed to a sub-subber switch is needed.
+ * Used in a periodical timer interrupt to fill and ship the current subbuffer
+ * to the reader so we can guarantee a steady flow. If a subbuffer is
+ * completely empty, do not switch.
+ * Also used as "finalize" operation to complete the last subbuffer after
+ * all writers have finished so the last subbuffer can be read by the reader.
+ */
+proctype switcher()
+{
+ byte prev_off, new_off, tmp_commit;
+ byte size;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ size = SUBBUF_SIZE - (prev_off % SUBBUF_SIZE);
+ new_off = prev_off + size;
+ if
+ :: (new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR)
+ || size == SUBBUF_SIZE ->
+ refcount = refcount - 1;
+ goto not_needed;
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ }
+
+ atomic {
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ /* <formal_verif> */
+ _commit_sum = _commit_sum - commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE]
+ + tmp_commit;
+ /* </formal_verif> */
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ refcount = refcount - 1;
+ }
+not_needed:
+ skip;
+}
+
+/* tracer
+ * Writes 1 byte of information in the buffer at the current
+ * "write_off" position and then increment the commit_count of the sub-buffer
+ * the information has been written to.
+ */
+proctype tracer()
+{
+ byte size = 1;
+ byte prev_off, new_off, tmp_commit;
+ byte i, j;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ new_off = prev_off + size;
+ }
+ atomic {
+ if
+ :: new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR ->
+ goto lost
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ i = 0;
+ do
+ :: i < size ->
+ assert(buffer_use[(prev_off + i) % BUFSIZE] == 0);
+ buffer_use[(prev_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= size -> break
+ od;
+ }
+
+ /* writing to buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < size ->
+ buffer_use[(prev_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= size -> break
+ od;
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ /* <formal_verif> */
+ _commit_sum = _commit_sum - commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE]
+ + tmp_commit;
+ /* </formal_verif> */
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ }
+ atomic {
+ goto end;
+lost:
+ events_lost++;
+end:
+ refcount = refcount - 1;
+ }
+}
+
+/* reader
+ * Read the information sub-buffer per sub-buffer when available.
+ *
+ * Reads the information as soon as it is ready, or may be delayed by
+ * an asynchronous delivery. Being modeled as a process insures all cases
+ * (scheduled very quickly or very late, causing event loss) are covered.
+ * Only one reader per buffer (normally ensured by a mutex). This is modeled
+ * by using a single reader process.
+ */
+proctype reader()
+{
+ byte i, j;
+
+ do
+ :: (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) > 0
+ && (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) < HALF_UCHAR
+ && (commit_count[(read_off % BUFSIZE) / SUBBUF_SIZE]
+ - SUBBUF_SIZE - (((read_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS)
+ == 0) ->
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ assert(buffer_use[(read_off + i) % BUFSIZE] == 0);
+ buffer_use[(read_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ }
+
+ /* reading from buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ buffer_use[(read_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ read_off = read_off + SUBBUF_SIZE;
+ }
+ :: read_off >= (NUMPROCS - events_lost) -> break;
+ od;
+}
+
+/* Waits for all tracer and switcher processes to finish before finalizing
+ * the buffer. Only after that will the reader be allowed to read the
+ * last subbuffer.
+ */
+proctype cleaner()
+{
+ atomic {
+ do
+ :: refcount == 0 ->
+ refcount = refcount + 1;
+ run switcher(); /* Finalize the last sub-buffer so it can be read. */
+ break;
+ od;
+ }
+}
+
+init {
+ byte i = 0;
+ byte j = 0;
+ byte sum = 0;
+ byte commit_sum = 0;
+
+ atomic {
+ i = 0;
+ do
+ :: i < NR_SUBBUFS ->
+ commit_count[i] = 0;
+ i++
+ :: i >= NR_SUBBUFS -> break
+ od;
+ /* <formal_verif> */
+ _commit_sum = 0;
+ /* </formal_verif> */
+ i = 0;
+ do
+ :: i < BUFSIZE ->
+ buffer_use[i] = 0;
+ i++
+ :: i >= BUFSIZE -> break
+ od;
+ run reader();
+ run cleaner();
+ i = 0;
+ do
+ :: i < NUMPROCS ->
+ refcount = refcount + 1;
+ run tracer();
+ i++
+ :: i >= NUMPROCS -> break
+ od;
+ i = 0;
+ do
+ :: i < NUMSWITCH ->
+ refcount = refcount + 1;
+ run switcher();
+ i++
+ :: i >= NUMSWITCH -> break
+ od;
+ }
+}
+
--- /dev/null
+#define BUFSIZE 8
--- /dev/null
+make[1]: Entering directory `/home/compudj/repository/trunk/verif/nico-md-merge'
+rm -f pan* trail.out
+cat defines > pan.ltl
+spin -f "!(`cat no_events_lost.ltl | grep -v ^//`)" >> pan.ltl
+spin -a -X -N pan.ltl model.spin
+Exit-Status 0
+gcc -w -o pan -D_POSIX_SOURCE -DMEMLIM=750 -DXUSAFE -DNOFAIR pan.c
+./pan -v -X -m100000 -w21 -a -c1
+warning: for p.o. reduction to be valid the never claim must be stutter-invariant
+(never claims generated from LTL formulae are stutter-invariant)
+depth 0: Claim reached state 5 (line 302)
+
+(Spin Version 5.1.6 -- 9 May 2008)
+ + Partial Order Reduction
+
+Full statespace search for:
+ never claim +
+ assertion violations + (if within scope of claim)
+ acceptance cycles + (fairness disabled)
+ invalid end states - (disabled by never claim)
+
+State-vector 92 byte, depth reached 178, errors: 0
+ 117886 states, stored
+ 210653 states, matched
+ 328539 transitions (= stored+matched)
+ 440774 atomic steps
+hash conflicts: 3201 (resolved)
+
+Stats on memory usage (in Megabytes):
+ 12.142 equivalent memory usage for states (stored*(State-vector + overhead))
+ 8.971 actual memory usage for states (compression: 73.88%)
+ state-vector as stored = 64 byte + 16 byte overhead
+ 8.000 memory used for hash table (-w21)
+ 3.052 memory used for DFS stack (-m100000)
+ 19.939 total actual memory usage
+
+unreached in proctype switcher
+ line 81, "pan.___", state 8, "(1)"
+ line 87, "pan.___", state 15, "write_off = new_off"
+ line 84, "pan.___", state 18, "((prev_off!=write_off))"
+ line 84, "pan.___", state 18, "else"
+ line 97, "pan.___", state 21, "commit_count[((prev_off%4)/(4/2))] = tmp_commit"
+ line 103, "pan.___", state 25, "(1)"
+ line 98, "pan.___", state 26, "((((((prev_off/4)*4)/2)+(4/2))-tmp_commit))"
+ line 98, "pan.___", state 26, "else"
+ line 91, "pan.___", state 29, "tmp_commit = (commit_count[((prev_off%4)/(4/2))]+size)"
+ (7 of 31 states)
+unreached in proctype tracer
+ line 177, "pan.___", state 48, "events_lost = (events_lost+1)"
+ (1 of 51 states)
+unreached in proctype reader
+ (0 of 29 states)
+unreached in proctype cleaner
+ (0 of 9 states)
+unreached in proctype :init:
+ line 284, "pan.___", state 35, "(run switcher())"
+ (1 of 43 states)
+unreached in proctype :never:
+ line 307, "pan.___", state 8, "-end-"
+ (1 of 8 states)
+
+pan: elapsed time 0.85 seconds
+pan: rate 138689.41 states/second
+pan: avg transition delay 2.5872e-06 usec
+make[1]: Leaving directory `/home/compudj/repository/trunk/verif/nico-md-merge'
--- /dev/null
+// If we have less writers than the buffer space available, we should
+// not loose events.
+// assert(NUMPROCS + NUMSWITCH > BUFSIZE || events_lost == 0);
+
+[]((buffer_large_enough) -> (!have_events_lost))
--- /dev/null
+ switch (t->back) {
+ default: Uerror("bad return move");
+ case 0: goto R999; /* nothing to undo */
+
+ /* PROC :never: */
+;
+ ;
+
+ case 4: /* STATE 8 */
+ ;
+ p_restor(II);
+ ;
+ ;
+ goto R999;
+
+ /* PROC :init: */
+
+ case 5: /* STATE 1 */
+ ;
+ ((P4 *)this)->i = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 6: /* STATE 4 */
+ ;
+ ((P4 *)this)->i = trpt->bup.ovals[1];
+ now.commit_count[ Index(((P4 *)this)->i, 2) ] = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 7: /* STATE 11 */
+ ;
+ ((P4 *)this)->i = trpt->bup.ovals[2];
+ now._commit_sum = trpt->bup.ovals[1];
+ /* 0 */ ((P4 *)this)->i = trpt->bup.ovals[0];
+ ;
+ ;
+ ungrab_ints(trpt->bup.ovals, 3);
+ goto R999;
+
+ case 8: /* STATE 11 */
+ ;
+ ((P4 *)this)->i = trpt->bup.ovals[1];
+ now._commit_sum = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 9: /* STATE 14 */
+ ;
+ ((P4 *)this)->i = trpt->bup.ovals[1];
+ now.buffer_use[ Index(((P4 *)this)->i, 8) ] = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 10: /* STATE 15 */
+ ;
+ /* 0 */ ((P4 *)this)->i = trpt->bup.oval;
+ ;
+ ;
+ goto R999;
+
+ case 11: /* STATE 20 */
+ ;
+ ;
+ delproc(0, now._nr_pr-1);
+ ;
+ goto R999;
+
+ case 12: /* STATE 22 */
+ ;
+ ((P4 *)this)->i = trpt->bup.oval;
+ ;
+ delproc(0, now._nr_pr-1);
+ ;
+ goto R999;
+
+ case 13: /* STATE 24 */
+ ;
+ now.refcount = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 14: /* STATE 26 */
+ ;
+ ((P4 *)this)->i = trpt->bup.oval;
+ ;
+ delproc(0, now._nr_pr-1);
+ ;
+ goto R999;
+
+ case 15: /* STATE 32 */
+ ;
+ ((P4 *)this)->i = trpt->bup.ovals[1];
+ /* 0 */ ((P4 *)this)->i = trpt->bup.ovals[0];
+ ;
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 16: /* STATE 32 */
+ ;
+ ((P4 *)this)->i = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 17: /* STATE 34 */
+ ;
+ now.refcount = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 18: /* STATE 36 */
+ ;
+ ((P4 *)this)->i = trpt->bup.oval;
+ ;
+ delproc(0, now._nr_pr-1);
+ ;
+ goto R999;
+
+ case 19: /* STATE 37 */
+ ;
+ /* 0 */ ((P4 *)this)->i = trpt->bup.oval;
+ ;
+ ;
+ goto R999;
+
+ case 20: /* STATE 43 */
+ ;
+ p_restor(II);
+ ;
+ ;
+ goto R999;
+
+ /* PROC cleaner */
+
+ case 21: /* STATE 2 */
+ ;
+ now.refcount = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 22: /* STATE 3 */
+ ;
+ ;
+ delproc(0, now._nr_pr-1);
+ ;
+ goto R999;
+
+ case 23: /* STATE 9 */
+ ;
+ p_restor(II);
+ ;
+ ;
+ goto R999;
+
+ /* PROC reader */
+;
+ ;
+
+ case 25: /* STATE 2 */
+ ;
+ ((P2 *)this)->i = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 26: /* STATE 6 */
+ ;
+ ((P2 *)this)->i = trpt->bup.ovals[1];
+ now.buffer_use[ Index(((now.read_off+((P2 *)this)->i)%8), 8) ] = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 27: /* STATE 7 */
+ ;
+ /* 0 */ ((P2 *)this)->i = trpt->bup.oval;
+ ;
+ ;
+ goto R999;
+
+ case 28: /* STATE 16 */
+ ;
+ ((P2 *)this)->i = trpt->bup.ovals[1];
+ now.buffer_use[ Index(((now.read_off+((P2 *)this)->i)%8), 8) ] = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 29: /* STATE 17 */
+ ;
+ /* 0 */ ((P2 *)this)->i = trpt->bup.oval;
+ ;
+ ;
+ goto R999;
+
+ case 30: /* STATE 22 */
+ ;
+ now.read_off = trpt->bup.oval;
+ ;
+ goto R999;
+;
+ ;
+
+ case 32: /* STATE 29 */
+ ;
+ p_restor(II);
+ ;
+ ;
+ goto R999;
+
+ /* PROC tracer */
+
+ case 33: /* STATE 2 */
+ ;
+ ((P1 *)this)->new_off = trpt->bup.ovals[1];
+ ((P1 *)this)->prev_off = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 34: /* STATE 4 */
+ ;
+ /* 0 */ ((P1 *)this)->new_off = trpt->bup.oval;
+ ;
+ ;
+ goto R999;
+;
+
+ case 35: /* STATE 7 */
+ goto R999;
+
+ case 36: /* STATE 11 */
+ ;
+ /* 0 */ ((P1 *)this)->prev_off = trpt->bup.oval;
+ ;
+ ;
+ goto R999;
+
+ case 37: /* STATE 17 */
+ ;
+ ((P1 *)this)->i = trpt->bup.ovals[1];
+ now.write_off = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 38: /* STATE 17 */
+ ;
+ ((P1 *)this)->i = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 39: /* STATE 21 */
+ ;
+ ((P1 *)this)->i = trpt->bup.ovals[1];
+ now.buffer_use[ Index(((((P1 *)this)->prev_off+((P1 *)this)->i)%8), 8) ] = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 40: /* STATE 22 */
+ ;
+ /* 0 */ ((P1 *)this)->i = trpt->bup.oval;
+ ;
+ ;
+ goto R999;
+
+ case 41: /* STATE 28 */
+ ;
+ ((P1 *)this)->i = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 42: /* STATE 31 */
+ ;
+ ((P1 *)this)->i = trpt->bup.ovals[1];
+ now.buffer_use[ Index(((((P1 *)this)->prev_off+((P1 *)this)->i)%8), 8) ] = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 2);
+ goto R999;
+
+ case 43: /* STATE 39 */
+ ;
+ now.commit_count[ Index(((((P1 *)this)->prev_off%8)/(8/2)), 2) ] = trpt->bup.ovals[3];
+ now._commit_sum = trpt->bup.ovals[2];
+ ((P1 *)this)->tmp_commit = trpt->bup.ovals[1];
+ /* 0 */ ((P1 *)this)->i = trpt->bup.ovals[0];
+ ;
+ ;
+ ungrab_ints(trpt->bup.ovals, 4);
+ goto R999;
+
+ case 44: /* STATE 39 */
+ ;
+ now.commit_count[ Index(((((P1 *)this)->prev_off%8)/(8/2)), 2) ] = trpt->bup.ovals[2];
+ now._commit_sum = trpt->bup.ovals[1];
+ ((P1 *)this)->tmp_commit = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 3);
+ goto R999;
+
+ case 45: /* STATE 41 */
+ ;
+ deliver = trpt->bup.ovals[2];
+ /* 1 */ ((P1 *)this)->tmp_commit = trpt->bup.ovals[1];
+ /* 0 */ ((P1 *)this)->prev_off = trpt->bup.ovals[0];
+ ;
+ ;
+ ungrab_ints(trpt->bup.ovals, 3);
+ goto R999;
+;
+
+ case 46: /* STATE 45 */
+ goto R999;
+;
+
+ case 47: /* STATE 43 */
+ goto R999;
+
+ case 48: /* STATE 48 */
+ ;
+ now.events_lost = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 49: /* STATE 49 */
+ ;
+ now.refcount = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 50: /* STATE 51 */
+ ;
+ p_restor(II);
+ ;
+ ;
+ goto R999;
+
+ /* PROC switcher */
+
+ case 51: /* STATE 3 */
+ ;
+ ((P0 *)this)->new_off = trpt->bup.ovals[2];
+ ((P0 *)this)->size = trpt->bup.ovals[1];
+ ((P0 *)this)->prev_off = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 3);
+ goto R999;
+
+ case 52: /* STATE 5 */
+ ;
+ now.refcount = trpt->bup.ovals[2];
+ /* 1 */ ((P0 *)this)->size = trpt->bup.ovals[1];
+ /* 0 */ ((P0 *)this)->new_off = trpt->bup.ovals[0];
+ ;
+ ;
+ ungrab_ints(trpt->bup.ovals, 3);
+ goto R999;
+;
+
+ case 53: /* STATE 8 */
+ goto R999;
+
+ case 54: /* STATE 12 */
+ ;
+ /* 0 */ ((P0 *)this)->prev_off = trpt->bup.oval;
+ ;
+ ;
+ goto R999;
+;
+
+ case 55: /* STATE 17 */
+ goto R999;
+
+ case 56: /* STATE 15 */
+ ;
+ now.write_off = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 57: /* STATE 21 */
+ ;
+ now.commit_count[ Index(((((P0 *)this)->prev_off%8)/(8/2)), 2) ] = trpt->bup.ovals[2];
+ now._commit_sum = trpt->bup.ovals[1];
+ ((P0 *)this)->tmp_commit = trpt->bup.ovals[0];
+ ;
+ ungrab_ints(trpt->bup.ovals, 3);
+ goto R999;
+
+ case 58: /* STATE 28 */
+ ;
+ now.refcount = trpt->bup.ovals[3];
+ deliver = trpt->bup.ovals[2];
+ /* 1 */ ((P0 *)this)->tmp_commit = trpt->bup.ovals[1];
+ /* 0 */ ((P0 *)this)->prev_off = trpt->bup.ovals[0];
+ ;
+ ;
+ ungrab_ints(trpt->bup.ovals, 4);
+ goto R999;
+
+ case 59: /* STATE 28 */
+ ;
+ now.refcount = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 60: /* STATE 28 */
+ ;
+ now.refcount = trpt->bup.oval;
+ ;
+ goto R999;
+
+ case 61: /* STATE 31 */
+ ;
+ p_restor(II);
+ ;
+ ;
+ goto R999;
+ }
+
--- /dev/null
+/*** Generated by Spin Version 5.1.6 -- 9 May 2008 ***/
+/*** From source: pan.spin ***/
+
+#ifdef SC
+#define _FILE_OFFSET_BITS 64
+#endif
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#if defined(WIN32) || defined(WIN64)
+#include <time.h>
+#else
+#include <unistd.h>
+#include <sys/times.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#define Offsetof(X, Y) ((unsigned long)(&(((X *)0)->Y)))
+#ifndef max
+#define max(a,b) (((a)<(b)) ? (b) : (a))
+#endif
+#ifndef PRINTF
+int Printf(const char *fmt, ...); /* prototype only */
+#endif
+#include "pan.h"
+#ifdef LOOPSTATE
+double cnt_loops;
+#endif
+State A_Root; /* seed-state for cycles */
+State now; /* the full state-vector */
+#undef C_States
+#if defined(C_States) && defined(HAS_TRACK)
+void
+c_update(uchar *p_t_r)
+{
+#ifdef VERBOSE
+ printf("c_update %u\n", p_t_r);
+#endif
+}
+void
+c_revert(uchar *p_t_r)
+{
+#ifdef VERBOSE
+ printf("c_revert %u\n", p_t_r);
+#endif
+}
+#endif
+void
+globinit(void)
+{
+}
+void
+locinit5(int h)
+{
+}
+void
+locinit4(int h)
+{
+}
+void
+locinit3(int h)
+{
+}
+void
+locinit2(int h)
+{
+}
+void
+locinit1(int h)
+{
+}
+void
+locinit0(int h)
+{
+}
+#ifdef CNTRSTACK
+#define onstack_now() (LL[trpt->j6] && LL[trpt->j7])
+#define onstack_put() LL[trpt->j6]++; LL[trpt->j7]++
+#define onstack_zap() LL[trpt->j6]--; LL[trpt->j7]--
+#endif
+#if !defined(SAFETY) && !defined(NOCOMP)
+#define V_A (((now._a_t&1)?2:1) << (now._a_t&2))
+#define A_V (((now._a_t&1)?1:2) << (now._a_t&2))
+int S_A = 0;
+#else
+#define V_A 0
+#define A_V 0
+#define S_A 0
+#endif
+#ifdef MA
+#undef onstack_now
+#undef onstack_put
+#undef onstack_zap
+#define onstack_put() ;
+#define onstack_zap() gstore((char *) &now, vsize, 4)
+#else
+#if defined(FULLSTACK) && !defined(BITSTATE)
+#define onstack_put() trpt->ostate = Lstate
+#define onstack_zap() { \
+ if (trpt->ostate) \
+ trpt->ostate->tagged = \
+ (S_A)? (trpt->ostate->tagged&~V_A) : 0; \
+ }
+#endif
+#endif
+#ifndef NO_V_PROVISO
+#define V_PROVISO
+#endif
+#if !defined(NO_RESIZE) && !defined(AUTO_RESIZE) && !defined(BITSTATE) && !defined(SPACE) && NCORE==1
+ #define AUTO_RESIZE
+#endif
+
+struct H_el {
+ struct H_el *nxt;
+#ifdef FULLSTACK
+ unsigned int tagged;
+ #if defined(BITSTATE) && !defined(NOREDUCE) && !defined(SAFETY)
+ unsigned int proviso;
+ #endif
+#endif
+#if defined(CHECK) || (defined(COLLAPSE) && !defined(FULLSTACK))
+ unsigned long st_id;
+#endif
+#if !defined(SAFETY) || defined(REACH)
+ unsigned int D;
+#endif
+#if NCORE>1
+ /* could cost 1 extra word: 4 bytes if 32-bit and 8 bytes if 64-bit */
+ #ifdef V_PROVISO
+ uchar cpu_id; /* id of cpu that created the state */
+ #endif
+#endif
+#ifdef COLLAPSE
+ #if VECTORSZ<65536
+ unsigned short ln;
+ #else
+ unsigned long ln;
+ #endif
+#endif
+#if defined(AUTO_RESIZE) && !defined(BITSTATE)
+ unsigned long m_K1;
+#endif
+ unsigned long state;
+} **H_tab, **S_Tab;
+
+typedef struct Trail {
+ int st; /* current state */
+ uchar pr; /* process id */
+ uchar tau; /* 8 bit-flags */
+ uchar o_pm; /* 8 more bit-flags */
+#if 0
+ Meaning of bit-flags:
+ tau&1 -> timeout enabled
+ tau&2 -> request to enable timeout 1 level up (in claim)
+ tau&4 -> current transition is a claim move
+ tau&8 -> current transition is an atomic move
+ tau&16 -> last move was truncated on stack
+ tau&32 -> current transition is a preselected move
+ tau&64 -> at least one next state is not on the stack
+ tau&128 -> current transition is a stutter move
+ o_pm&1 -> the current pid moved -- implements else
+ o_pm&2 -> this is an acceptance state
+ o_pm&4 -> this is a progress state
+ o_pm&8 -> fairness alg rule 1 undo mark
+ o_pm&16 -> fairness alg rule 3 undo mark
+ o_pm&32 -> fairness alg rule 2 undo mark
+ o_pm&64 -> the current proc applied rule2
+ o_pm&128 -> a fairness, dummy move - all procs blocked
+#endif
+#ifdef NSUCC
+ uchar n_succ; /* nr of successor states */
+#endif
+#if defined(FULLSTACK) && defined(MA) && !defined(BFS)
+ uchar proviso;
+#endif
+#ifndef BFS
+ uchar o_n, o_ot; /* to save locals */
+#endif
+ uchar o_m;
+#ifdef EVENT_TRACE
+#if nstates_event<256
+ uchar o_event;
+#else
+ unsigned short o_event;
+#endif
+#endif
+ int o_tt;
+#ifndef BFS
+ short o_To;
+#ifdef RANDOMIZE
+ short oo_i;
+#endif
+#endif
+#if defined(HAS_UNLESS) && !defined(BFS)
+ int e_state; /* if escape trans - state of origin */
+#endif
+#if (defined(FULLSTACK) && !defined(MA)) || defined(BFS) || (NCORE>1)
+ struct H_el *ostate; /* pointer to stored state */
+#endif
+#if defined(CNTRSTACK) && !defined(BFS)
+ long j6, j7;
+#endif
+ Trans *o_t;
+#ifdef SCHED
+ /* based on Qadeer&Rehof, Tacas 2005, LNCS 3440, pp. 93-107 */
+ #if NCORE>1
+ #error "-DSCHED cannot be combined with -DNCORE (yet)"
+ #endif
+ int sched_limit;
+#endif
+#ifdef HAS_SORTED
+ short ipt;
+#endif
+ union {
+ int oval;
+ int *ovals;
+ } bup;
+} Trail;
+Trail *trail, *trpt;
+FILE *efd;
+uchar *this;
+long maxdepth=10000;
+long omaxdepth=10000;
+#ifdef SCHED
+int sched_max = 10;
+#endif
+#ifdef PERMUTED
+ uchar permuted = 1;
+#else
+ uchar permuted = 0;
+#endif
+double quota; /* time limit */
+#if NCORE>1
+long z_handoff = -1;
+#endif
+#ifdef SC
+char *stackfile;
+#endif
+uchar *SS, *LL;
+uchar HASH_NR = 0;
+
+double memcnt = (double) 0;
+double memlim = (double) (1<<30); /* 1 GB */
+#if NCORE>1
+double mem_reserved = (double) 0;
+#endif
+
+/* for emalloc: */
+static char *have;
+static long left = 0L;
+static double fragment = (double) 0;
+static unsigned long grow;
+
+unsigned int HASH_CONST[] = {
+ /* asuming 4 bytes per int */
+ 0x88888EEF, 0x00400007,
+ 0x04c11db7, 0x100d4e63,
+ 0x0fc22f87, 0x3ff0c3ff,
+ 0x38e84cd7, 0x02b148e9,
+ 0x98b2e49d, 0xb616d379,
+ 0xa5247fd9, 0xbae92a15,
+ 0xb91c8bc5, 0x8e5880f3,
+ 0xacd7c069, 0xb4c44bb3,
+ 0x2ead1fb7, 0x8e428171,
+ 0xdbebd459, 0x828ae611,
+ 0x6cb25933, 0x86cdd651,
+ 0x9e8f5f21, 0xd5f8d8e7,
+ 0x9c4e956f, 0xb5cf2c71,
+ 0x2e805a6d, 0x33fc3a55,
+ 0xaf203ed1, 0xe31f5909,
+ 0x5276db35, 0x0c565ef7,
+ 0x273d1aa5, 0x8923b1dd,
+ 0
+};
+#if NCORE>1
+extern int core_id;
+#endif
+long mreached=0;
+int done=0, errors=0, Nrun=1;
+int c_init_done=0;
+char *c_stack_start = (char *) 0;
+double nstates=0, nlinks=0, truncs=0, truncs2=0;
+double nlost=0, nShadow=0, hcmp=0, ngrabs=0;
+#if defined(ZAPH) && defined(BITSTATE)
+double zstates = 0;
+#endif
+int c_init_run;
+#ifdef BFS
+double midrv=0, failedrv=0, revrv=0;
+#endif
+unsigned long nr_states=0; /* nodes in DFA */
+long Fa=0, Fh=0, Zh=0, Zn=0;
+long PUT=0, PROBE=0, ZAPS=0;
+long Ccheck=0, Cholds=0;
+int a_cycles=0, upto=1, strict=0, verbose = 0, signoff = 0;
+#ifdef HAS_CODE
+int gui = 0, coltrace = 0, readtrail = 0;
+int whichtrail = 0, onlyproc = -1, silent = 0;
+#endif
+int state_tables=0, fairness=0, no_rck=0, Nr_Trails=0;
+char simvals[128];
+#ifndef INLINE
+int TstOnly=0;
+#endif
+unsigned long mask, nmask;
+#ifdef BITSTATE
+int ssize=23; /* 1 Mb */
+#else
+int ssize=19; /* 512K slots */
+#endif
+int hmax=0, svmax=0, smax=0;
+int Maxbody=0, XX;
+uchar *noptr; /* used by macro Pptr(x) */
+#ifdef VAR_RANGES
+void logval(char *, int);
+void dumpranges(void);
+#endif
+#ifdef MA
+#define INLINE_REV
+extern void dfa_init(unsigned short);
+extern int dfa_member(unsigned long);
+extern int dfa_store(uchar *);
+unsigned int maxgs = 0;
+#endif
+
+#ifdef ALIGNED
+ State comp_now __attribute__ ((aligned (8)));
+ /* gcc 64-bit aligned for Itanium2 systems */
+ /* MAJOR runtime penalty if not used on those systems */
+#else
+ State comp_now; /* compressed state vector */
+#endif
+
+State comp_msk;
+uchar *Mask = (uchar *) &comp_msk;
+#ifdef COLLAPSE
+State comp_tmp;
+static char *scratch = (char *) &comp_tmp;
+#endif
+Stack *stack; /* for queues, processes */
+Svtack *svtack; /* for old state vectors */
+#ifdef BITSTATE
+static unsigned int hfns = 3; /* new default */
+#endif
+static unsigned long j1;
+static unsigned long K1, K2;
+static unsigned long j2, j3, j4;
+#ifdef BITSTATE
+static long udmem;
+#endif
+static long A_depth = 0;
+long depth = 0;
+#if NCORE>1
+long nr_handoffs = 0;
+#endif
+static uchar warned = 0, iterative = 0, exclusive = 0, like_java = 0, every_error = 0;
+static uchar noasserts = 0, noends = 0, bounded = 0;
+#if SYNC>0 && ASYNC==0
+void set_recvs(void);
+int no_recvs(int);
+#endif
+#if SYNC
+#define IfNotBlocked if (boq != -1) continue;
+#define UnBlock boq = -1
+#else
+#define IfNotBlocked /* cannot block */
+#define UnBlock /* don't bother */
+#endif
+
+#ifdef BITSTATE
+int (*bstore)(char *, int);
+int bstore_reg(char *, int);
+int bstore_mod(char *, int);
+#endif
+void active_procs(void);
+void cleanup(void);
+void do_the_search(void);
+void find_shorter(int);
+void iniglobals(void);
+void stopped(int);
+void wrapup(void);
+int *grab_ints(int);
+void ungrab_ints(int *, int);
+#ifndef NOBOUNDCHECK
+#define Index(x, y) Boundcheck(x, y, II, tt, t)
+#else
+#define Index(x, y) x
+#endif
+short Air[] = { (short) Air0, (short) Air1, (short) Air2, (short) Air3, (short) Air4, (short) Air5, (short) Air6 };
+int
+addproc(int n)
+{ int j, h = now._nr_pr;
+#ifndef NOCOMP
+ int k;
+#endif
+ uchar *o_this = this;
+
+#ifndef INLINE
+ if (TstOnly) return (h < MAXPROC);
+#endif
+#ifndef NOBOUNDCHECK
+/* redefine Index only within this procedure */
+#undef Index
+#define Index(x, y) Boundcheck(x, y, 0, 0, 0)
+#endif
+ if (h >= MAXPROC)
+ Uerror("too many processes");
+ switch (n) {
+ case 0: j = sizeof(P0); break;
+ case 1: j = sizeof(P1); break;
+ case 2: j = sizeof(P2); break;
+ case 3: j = sizeof(P3); break;
+ case 4: j = sizeof(P4); break;
+ case 5: j = sizeof(P5); break;
+ case 6: j = sizeof(P6); break;
+ default: Uerror("bad proc - addproc");
+ }
+ if (vsize%WS)
+ proc_skip[h] = WS-(vsize%WS);
+ else
+ proc_skip[h] = 0;
+#ifndef NOCOMP
+ for (k = vsize + (int) proc_skip[h]; k > vsize; k--)
+ Mask[k-1] = 1; /* align */
+#endif
+ vsize += (int) proc_skip[h];
+ proc_offset[h] = vsize;
+#ifdef SVDUMP
+ if (vprefix > 0)
+ { int dummy = 0;
+ write(svfd, (uchar *) &dummy, sizeof(int)); /* mark */
+ write(svfd, (uchar *) &h, sizeof(int));
+ write(svfd, (uchar *) &n, sizeof(int));
+#if VECTORSZ>32000
+ write(svfd, (uchar *) &proc_offset[h], sizeof(int));
+#else
+ write(svfd, (uchar *) &proc_offset[h], sizeof(short));
+#endif
+ write(svfd, (uchar *) &now, vprefix-4*sizeof(int)); /* padd */
+ }
+#endif
+ now._nr_pr += 1;
+ if (fairness && ((int) now._nr_pr + 1 >= (8*NFAIR)/2))
+ { printf("pan: error: too many processes -- current");
+ printf(" max is %d procs (-DNFAIR=%d)\n",
+ (8*NFAIR)/2 - 2, NFAIR);
+ printf("\trecompile with -DNFAIR=%d\n",
+ NFAIR+1);
+ pan_exit(1);
+ }
+ vsize += j;
+#ifndef NOVSZ
+ now._vsz = vsize;
+#endif
+#ifndef NOCOMP
+ for (k = 1; k <= Air[n]; k++)
+ Mask[vsize - k] = 1; /* pad */
+ Mask[vsize-j] = 1; /* _pid */
+#endif
+ hmax = max(hmax, vsize);
+ if (vsize >= VECTORSZ)
+ { printf("pan: error, VECTORSZ too small, recompile pan.c");
+ printf(" with -DVECTORSZ=N with N>%d\n", (int) vsize);
+ Uerror("aborting");
+ }
+ memset((char *)pptr(h), 0, j);
+ this = pptr(h);
+ if (BASE > 0 && h > 0)
+ ((P0 *)this)->_pid = h-BASE;
+ else
+ ((P0 *)this)->_pid = h;
+ switch (n) {
+ case 6: /* np_ */
+ ((P6 *)pptr(h))->_t = 6;
+ ((P6 *)pptr(h))->_p = 0;
+ reached6[0] = 1;
+ accpstate[6][1] = 1;
+ break;
+ case 5: /* :never: */
+ ((P5 *)pptr(h))->_t = 5;
+ ((P5 *)pptr(h))->_p = 5; reached5[5]=1;
+ /* params: */
+ /* locals: */
+#ifdef VAR_RANGES
+#endif
+#ifdef HAS_CODE
+ locinit5(h);
+#endif
+ break;
+ case 4: /* :init: */
+ ((P4 *)pptr(h))->_t = 4;
+ ((P4 *)pptr(h))->_p = 42; reached4[42]=1;
+ /* params: */
+ /* locals: */
+ ((P4 *)pptr(h))->i = 0;
+ ((P4 *)pptr(h))->j = 0;
+ ((P4 *)pptr(h))->sum = 0;
+ ((P4 *)pptr(h))->commit_sum = 0;
+#ifdef VAR_RANGES
+ logval(":init::i", ((P4 *)pptr(h))->i);
+ logval(":init::j", ((P4 *)pptr(h))->j);
+ logval(":init::sum", ((P4 *)pptr(h))->sum);
+ logval(":init::commit_sum", ((P4 *)pptr(h))->commit_sum);
+#endif
+#ifdef HAS_CODE
+ locinit4(h);
+#endif
+ break;
+ case 3: /* cleaner */
+ ((P3 *)pptr(h))->_t = 3;
+ ((P3 *)pptr(h))->_p = 8; reached3[8]=1;
+ /* params: */
+ /* locals: */
+#ifdef VAR_RANGES
+#endif
+#ifdef HAS_CODE
+ locinit3(h);
+#endif
+ break;
+ case 2: /* reader */
+ ((P2 *)pptr(h))->_t = 2;
+ ((P2 *)pptr(h))->_p = 26; reached2[26]=1;
+ /* params: */
+ /* locals: */
+ ((P2 *)pptr(h))->i = 0;
+ ((P2 *)pptr(h))->j = 0;
+#ifdef VAR_RANGES
+ logval("reader:i", ((P2 *)pptr(h))->i);
+ logval("reader:j", ((P2 *)pptr(h))->j);
+#endif
+#ifdef HAS_CODE
+ locinit2(h);
+#endif
+ break;
+ case 1: /* tracer */
+ ((P1 *)pptr(h))->_t = 1;
+ ((P1 *)pptr(h))->_p = 3; reached1[3]=1;
+ /* params: */
+ /* locals: */
+ ((P1 *)pptr(h))->size = 1;
+ ((P1 *)pptr(h))->prev_off = 0;
+ ((P1 *)pptr(h))->new_off = 0;
+ ((P1 *)pptr(h))->tmp_commit = 0;
+ ((P1 *)pptr(h))->i = 0;
+ ((P1 *)pptr(h))->j = 0;
+#ifdef VAR_RANGES
+ logval("tracer:size", ((P1 *)pptr(h))->size);
+ logval("tracer:prev_off", ((P1 *)pptr(h))->prev_off);
+ logval("tracer:new_off", ((P1 *)pptr(h))->new_off);
+ logval("tracer:tmp_commit", ((P1 *)pptr(h))->tmp_commit);
+ logval("tracer:i", ((P1 *)pptr(h))->i);
+ logval("tracer:j", ((P1 *)pptr(h))->j);
+#endif
+#ifdef HAS_CODE
+ locinit1(h);
+#endif
+ break;
+ case 0: /* switcher */
+ ((P0 *)pptr(h))->_t = 0;
+ ((P0 *)pptr(h))->_p = 11; reached0[11]=1;
+ /* params: */
+ /* locals: */
+ ((P0 *)pptr(h))->prev_off = 0;
+ ((P0 *)pptr(h))->new_off = 0;
+ ((P0 *)pptr(h))->tmp_commit = 0;
+ ((P0 *)pptr(h))->size = 0;
+#ifdef VAR_RANGES
+ logval("switcher:prev_off", ((P0 *)pptr(h))->prev_off);
+ logval("switcher:new_off", ((P0 *)pptr(h))->new_off);
+ logval("switcher:tmp_commit", ((P0 *)pptr(h))->tmp_commit);
+ logval("switcher:size", ((P0 *)pptr(h))->size);
+#endif
+#ifdef HAS_CODE
+ locinit0(h);
+#endif
+ break;
+ }
+ this = o_this;
+ return h-BASE;
+#ifndef NOBOUNDCHECK
+#undef Index
+#define Index(x, y) Boundcheck(x, y, II, tt, t)
+#endif
+}
+
+#if defined(BITSTATE) && defined(COLLAPSE)
+/* just to allow compilation, to generate the error */
+long col_p(int i, char *z) { return 0; }
+long col_q(int i, char *z) { return 0; }
+#endif
+#ifndef BITSTATE
+#ifdef COLLAPSE
+long
+col_p(int i, char *z)
+{ int j, k; unsigned long ordinal(char *, long, short);
+ char *x, *y;
+ P0 *ptr = (P0 *) pptr(i);
+ switch (ptr->_t) {
+ case 0: j = sizeof(P0); break;
+ case 1: j = sizeof(P1); break;
+ case 2: j = sizeof(P2); break;
+ case 3: j = sizeof(P3); break;
+ case 4: j = sizeof(P4); break;
+ case 5: j = sizeof(P5); break;
+ case 6: j = sizeof(P6); break;
+ default: Uerror("bad proctype - collapse");
+ }
+ if (z) x = z; else x = scratch;
+ y = (char *) ptr; k = proc_offset[i];
+ for ( ; j > 0; j--, y++)
+ if (!Mask[k++]) *x++ = *y;
+ for (j = 0; j < WS-1; j++)
+ *x++ = 0;
+ x -= j;
+ if (z) return (long) (x - z);
+ return ordinal(scratch, x-scratch, (short) (2+ptr->_t));
+}
+#endif
+#endif
+void
+run(void)
+{ /* int i; */
+ memset((char *)&now, 0, sizeof(State));
+ vsize = (unsigned long) (sizeof(State) - VECTORSZ);
+#ifndef NOVSZ
+ now._vsz = vsize;
+#endif
+/* optional provisioning statements, e.g. to */
+/* set hidden variables, used as constants */
+#ifdef PROV
+#include PROV
+#endif
+ settable();
+ Maxbody = max(Maxbody, ((int) sizeof(P0)));
+ Maxbody = max(Maxbody, ((int) sizeof(P1)));
+ Maxbody = max(Maxbody, ((int) sizeof(P2)));
+ Maxbody = max(Maxbody, ((int) sizeof(P3)));
+ Maxbody = max(Maxbody, ((int) sizeof(P4)));
+ Maxbody = max(Maxbody, ((int) sizeof(P5)));
+ Maxbody = max(Maxbody, ((int) sizeof(P6)));
+ reached[0] = reached0;
+ reached[1] = reached1;
+ reached[2] = reached2;
+ reached[3] = reached3;
+ reached[4] = reached4;
+ reached[5] = reached5;
+ reached[6] = reached6;
+ accpstate[0] = (uchar *) emalloc(nstates0);
+ accpstate[1] = (uchar *) emalloc(nstates1);
+ accpstate[2] = (uchar *) emalloc(nstates2);
+ accpstate[3] = (uchar *) emalloc(nstates3);
+ accpstate[4] = (uchar *) emalloc(nstates4);
+ accpstate[5] = (uchar *) emalloc(nstates5);
+ accpstate[6] = (uchar *) emalloc(nstates6);
+ progstate[0] = (uchar *) emalloc(nstates0);
+ progstate[1] = (uchar *) emalloc(nstates1);
+ progstate[2] = (uchar *) emalloc(nstates2);
+ progstate[3] = (uchar *) emalloc(nstates3);
+ progstate[4] = (uchar *) emalloc(nstates4);
+ progstate[5] = (uchar *) emalloc(nstates5);
+ progstate[6] = (uchar *) emalloc(nstates6);
+ loopstate0 = loopstate[0] = (uchar *) emalloc(nstates0);
+ loopstate1 = loopstate[1] = (uchar *) emalloc(nstates1);
+ loopstate2 = loopstate[2] = (uchar *) emalloc(nstates2);
+ loopstate3 = loopstate[3] = (uchar *) emalloc(nstates3);
+ loopstate4 = loopstate[4] = (uchar *) emalloc(nstates4);
+ loopstate5 = loopstate[5] = (uchar *) emalloc(nstates5);
+ loopstate6 = loopstate[6] = (uchar *) emalloc(nstates6);
+ stopstate[0] = (uchar *) emalloc(nstates0);
+ stopstate[1] = (uchar *) emalloc(nstates1);
+ stopstate[2] = (uchar *) emalloc(nstates2);
+ stopstate[3] = (uchar *) emalloc(nstates3);
+ stopstate[4] = (uchar *) emalloc(nstates4);
+ stopstate[5] = (uchar *) emalloc(nstates5);
+ stopstate[6] = (uchar *) emalloc(nstates6);
+ visstate[0] = (uchar *) emalloc(nstates0);
+ visstate[1] = (uchar *) emalloc(nstates1);
+ visstate[2] = (uchar *) emalloc(nstates2);
+ visstate[3] = (uchar *) emalloc(nstates3);
+ visstate[4] = (uchar *) emalloc(nstates4);
+ visstate[5] = (uchar *) emalloc(nstates5);
+ visstate[6] = (uchar *) emalloc(nstates6);
+ mapstate[0] = (short *) emalloc(nstates0 * sizeof(short));
+ mapstate[1] = (short *) emalloc(nstates1 * sizeof(short));
+ mapstate[2] = (short *) emalloc(nstates2 * sizeof(short));
+ mapstate[3] = (short *) emalloc(nstates3 * sizeof(short));
+ mapstate[4] = (short *) emalloc(nstates4 * sizeof(short));
+ mapstate[5] = (short *) emalloc(nstates5 * sizeof(short));
+ mapstate[6] = (short *) emalloc(nstates6 * sizeof(short));
+#ifdef HAS_CODE
+#ifdef HAS_CODE
+#ifdef HAS_CODE
+#ifdef HAS_CODE
+#ifdef HAS_CODE
+#ifdef HAS_CODE
+#ifdef HAS_CODE
+ NrStates[0] = nstates0;
+ NrStates[1] = nstates1;
+ NrStates[2] = nstates2;
+ NrStates[3] = nstates3;
+ NrStates[4] = nstates4;
+ NrStates[5] = nstates5;
+ NrStates[6] = nstates6;
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+ stopstate[0][endstate0] = 1;
+ stopstate[1][endstate1] = 1;
+ stopstate[2][endstate2] = 1;
+ stopstate[3][endstate3] = 1;
+ stopstate[4][endstate4] = 1;
+ stopstate[5][endstate5] = 1;
+ stopstate[6][endstate6] = 1;
+ accpstate[5][7] = 1;
+ stopstate[1][49] = 1;
+ retrans(0, nstates0, start0, src_ln0, reached0, loopstate0);
+ retrans(1, nstates1, start1, src_ln1, reached1, loopstate1);
+ retrans(2, nstates2, start2, src_ln2, reached2, loopstate2);
+ retrans(3, nstates3, start3, src_ln3, reached3, loopstate3);
+ retrans(4, nstates4, start4, src_ln4, reached4, loopstate4);
+ retrans(5, nstates5, start5, src_ln5, reached5, loopstate5);
+ if (state_tables)
+ { printf("\nTransition Type: ");
+ printf("A=atomic; D=d_step; L=local; G=global\n");
+ printf("Source-State Labels: ");
+ printf("p=progress; e=end; a=accept;\n");
+#ifdef MERGED
+ printf("Note: statement merging was used. Only the first\n");
+ printf(" stmnt executed in each merge sequence is shown\n");
+ printf(" (use spin -a -o3 to disable statement merging)\n");
+#endif
+ pan_exit(0);
+ }
+ iniglobals();
+#if defined(VERI) && !defined(NOREDUCE) && !defined(NP)
+ if (!state_tables
+#ifdef HAS_CODE
+ && !readtrail
+#endif
+#if NCORE>1
+ && core_id == 0
+#endif
+ )
+ { printf("warning: for p.o. reduction to be valid ");
+ printf("the never claim must be stutter-invariant\n");
+ printf("(never claims generated from LTL ");
+ printf("formulae are stutter-invariant)\n");
+ }
+#endif
+ UnBlock; /* disable rendez-vous */
+#ifdef BITSTATE
+ if (udmem)
+ { udmem *= 1024L*1024L;
+ #if NCORE>1
+ if (!readtrail)
+ { void init_SS(unsigned long);
+ init_SS((unsigned long) udmem);
+ } else
+ #endif
+ SS = (uchar *) emalloc(udmem);
+ bstore = bstore_mod;
+ } else
+ #if NCORE>1
+ { void init_SS(unsigned long);
+ init_SS(ONE_L<<(ssize-3));
+ }
+ #else
+ SS = (uchar *) emalloc(ONE_L<<(ssize-3));
+ #endif
+#else
+ hinit();
+#endif
+#if defined(FULLSTACK) && defined(BITSTATE)
+ onstack_init();
+#endif
+#if defined(CNTRSTACK) && !defined(BFS)
+ LL = (uchar *) emalloc(ONE_L<<(ssize-3));
+#endif
+ stack = ( Stack *) emalloc(sizeof(Stack));
+ svtack = (Svtack *) emalloc(sizeof(Svtack));
+ /* a place to point for Pptr of non-running procs: */
+ noptr = (uchar *) emalloc(Maxbody * sizeof(char));
+#ifdef SVDUMP
+ if (vprefix > 0)
+ write(svfd, (uchar *) &vprefix, sizeof(int));
+#endif
+#ifdef VERI
+ Addproc(VERI); /* never - pid = 0 */
+#endif
+ active_procs(); /* started after never */
+#ifdef EVENT_TRACE
+ now._event = start_event;
+ reached[EVENT_TRACE][start_event] = 1;
+#endif
+#ifdef HAS_CODE
+ globinit();
+#endif
+#ifdef BITSTATE
+go_again:
+#endif
+ do_the_search();
+#ifdef BITSTATE
+ if (--Nrun > 0 && HASH_CONST[++HASH_NR])
+ { printf("Run %d:\n", HASH_NR);
+ wrap_stats();
+ printf("\n");
+ memset(SS, 0, ONE_L<<(ssize-3));
+#ifdef CNTRSTACK
+ memset(LL, 0, ONE_L<<(ssize-3));
+#endif
+#ifdef FULLSTACK
+ memset((uchar *) S_Tab, 0,
+ maxdepth*sizeof(struct H_el *));
+#endif
+ nstates=nlinks=truncs=truncs2=ngrabs = 0;
+ nlost=nShadow=hcmp = 0;
+ Fa=Fh=Zh=Zn = 0;
+ PUT=PROBE=ZAPS=Ccheck=Cholds = 0;
+ goto go_again;
+ }
+#endif
+}
+#ifdef HAS_PROVIDED
+int provided(int, uchar, int, Trans *);
+#endif
+#if NCORE>1
+#define GLOBAL_LOCK (0)
+#ifndef CS_N
+#define CS_N (256*NCORE)
+#endif
+#ifdef NGQ
+#define NR_QS (NCORE)
+#define CS_NR (CS_N+1) /* 2^N + 1, nr critical sections */
+#define GQ_RD GLOBAL_LOCK
+#define GQ_WR GLOBAL_LOCK
+#define CS_ID (1 + (int) (j1 & (CS_N-1))) /* mask: 2^N - 1, zero reserved */
+#define QLOCK(n) (1+n)
+#else
+#define NR_QS (NCORE+1)
+#define CS_NR (CS_N+3)
+#define GQ_RD (1)
+#define GQ_WR (2)
+#define CS_ID (3 + (int) (j1 & (CS_N-1)))
+#define QLOCK(n) (3+n)
+#endif
+
+void e_critical(int);
+void x_critical(int);
+
+#ifndef SEP_STATE
+ #define enter_critical(w) e_critical(w)
+ #define leave_critical(w) x_critical(w)
+#else
+ #ifdef NGQ
+ #define enter_critical(w) { if (w < 1+NCORE) e_critical(w); }
+ #define leave_critical(w) { if (w < 1+NCORE) x_critical(w); }
+ #else
+ #define enter_critical(w) { if (w < 3+NCORE) e_critical(w); }
+ #define leave_critical(w) { if (w < 3+NCORE) x_critical(w); }
+ #endif
+#endif
+
+int
+cpu_printf(const char *fmt, ...)
+{ va_list args;
+ enter_critical(GLOBAL_LOCK); /* printing */
+ printf("cpu%d: ", core_id);
+ fflush(stdout);
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+ fflush(stdout);
+ leave_critical(GLOBAL_LOCK);
+ return 1;
+}
+#else
+int
+cpu_printf(const char *fmt, ...)
+{ va_list args;
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+ return 1;
+}
+#endif
+int
+Printf(const char *fmt, ...)
+{ /* Make sure the args to Printf
+ * are always evaluated (e.g., they
+ * could contain a run stmnt)
+ * but do not generate the output
+ * during verification runs
+ * unless explicitly wanted
+ * If this fails on your system
+ * compile SPIN itself -DPRINTF
+ * and this code is not generated
+ */
+#ifdef HAS_CODE
+ if (readtrail)
+ { va_list args;
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+ return 1;
+ }
+#endif
+#ifdef PRINTF
+ va_list args;
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+#endif
+ return 1;
+}
+extern void printm(int);
+#ifndef SC
+#define getframe(i) &trail[i];
+#else
+static long HHH, DDD, hiwater;
+static long CNT1, CNT2;
+static int stackwrite;
+static int stackread;
+static Trail frameptr;
+Trail *
+getframe(int d)
+{
+ if (CNT1 == CNT2)
+ return &trail[d];
+
+ if (d >= (CNT1-CNT2)*DDD)
+ return &trail[d - (CNT1-CNT2)*DDD];
+
+ if (!stackread
+ && (stackread = open(stackfile, 0)) < 0)
+ { printf("getframe: cannot open %s\n", stackfile);
+ wrapup();
+ }
+ if (lseek(stackread, d* (off_t) sizeof(Trail), SEEK_SET) == -1
+ || read(stackread, &frameptr, sizeof(Trail)) != sizeof(Trail))
+ { printf("getframe: frame read error\n");
+ wrapup();
+ }
+ return &frameptr;
+}
+#endif
+#if !defined(SAFETY) && !defined(BITSTATE)
+#if !defined(FULLSTACK) || defined(MA)
+#define depth_of(x) A_depth /* an estimate */
+#else
+int
+depth_of(struct H_el *s)
+{ Trail *t; int d;
+ for (d = 0; d <= A_depth; d++)
+ { t = getframe(d);
+ if (s == t->ostate)
+ return d;
+ }
+ printf("pan: cannot happen, depth_of\n");
+ return depthfound;
+}
+#endif
+#endif
+#if NCORE>1
+extern void cleanup_shm(int);
+volatile unsigned int *search_terminated; /* to signal early termination */
+#endif
+void
+pan_exit(int val)
+{ void stop_timer(void);
+ if (signoff)
+ { printf("--end of output--\n");
+ }
+#if NCORE>1
+ if (search_terminated != NULL)
+ { *search_terminated |= 1; /* pan_exit */
+ }
+#ifdef USE_DISK
+ { void dsk_stats(void);
+ dsk_stats();
+ }
+#endif
+ if (!state_tables && !readtrail)
+ { cleanup_shm(1);
+ }
+#endif
+ if (val == 2)
+ { val = 0;
+ } else
+ { stop_timer();
+ }
+ exit(val);
+}
+#ifdef HAS_CODE
+char *
+transmognify(char *s)
+{ char *v, *w;
+ static char buf[2][2048];
+ int i, toggle = 0;
+ if (!s || strlen(s) > 2047) return s;
+ memset(buf[0], 0, 2048);
+ memset(buf[1], 0, 2048);
+ strcpy(buf[toggle], s);
+ while ((v = strstr(buf[toggle], "{c_code")))
+ { *v = '\0'; v++;
+ strcpy(buf[1-toggle], buf[toggle]);
+ for (w = v; *w != '}' && *w != '\0'; w++) /* skip */;
+ if (*w != '}') return s;
+ *w = '\0'; w++;
+ for (i = 0; code_lookup[i].c; i++)
+ if (strcmp(v, code_lookup[i].c) == 0
+ && strlen(v) == strlen(code_lookup[i].c))
+ { if (strlen(buf[1-toggle])
+ + strlen(code_lookup[i].t)
+ + strlen(w) > 2047)
+ return s;
+ strcat(buf[1-toggle], code_lookup[i].t);
+ break;
+ }
+ strcat(buf[1-toggle], w);
+ toggle = 1 - toggle;
+ }
+ buf[toggle][2047] = '\0';
+ return buf[toggle];
+}
+#else
+char * transmognify(char *s) { return s; }
+#endif
+#ifdef HAS_CODE
+void
+add_src_txt(int ot, int tt)
+{ Trans *t;
+ char *q;
+
+ for (t = trans[ot][tt]; t; t = t->nxt)
+ { printf("\t\t");
+ q = transmognify(t->tp);
+ for ( ; q && *q; q++)
+ if (*q == '\n')
+ printf("\\n");
+ else
+ putchar(*q);
+ printf("\n");
+ }
+}
+void
+wrap_trail(void)
+{ static int wrap_in_progress = 0;
+ int i; short II;
+ P0 *z;
+
+ if (wrap_in_progress++) return;
+
+ printf("spin: trail ends after %ld steps\n", depth);
+ if (onlyproc >= 0)
+ { if (onlyproc >= now._nr_pr) { pan_exit(0); }
+ II = onlyproc;
+ z = (P0 *)pptr(II);
+ printf("%3ld: proc %d (%s) ",
+ depth, II, procname[z->_t]);
+ for (i = 0; src_all[i].src; i++)
+ if (src_all[i].tp == (int) z->_t)
+ { printf(" line %3d",
+ src_all[i].src[z->_p]);
+ break;
+ }
+ printf(" (state %2d)", z->_p);
+ if (!stopstate[z->_t][z->_p])
+ printf(" (invalid end state)");
+ printf("\n");
+ add_src_txt(z->_t, z->_p);
+ pan_exit(0);
+ }
+ printf("#processes %d:\n", now._nr_pr);
+ if (depth < 0) depth = 0;
+ for (II = 0; II < now._nr_pr; II++)
+ { z = (P0 *)pptr(II);
+ printf("%3ld: proc %d (%s) ",
+ depth, II, procname[z->_t]);
+ for (i = 0; src_all[i].src; i++)
+ if (src_all[i].tp == (int) z->_t)
+ { printf(" line %3d",
+ src_all[i].src[z->_p]);
+ break;
+ }
+ printf(" (state %2d)", z->_p);
+ if (!stopstate[z->_t][z->_p])
+ printf(" (invalid end state)");
+ printf("\n");
+ add_src_txt(z->_t, z->_p);
+ }
+ c_globals();
+ for (II = 0; II < now._nr_pr; II++)
+ { z = (P0 *)pptr(II);
+ c_locals(II, z->_t);
+ }
+#ifdef ON_EXIT
+ ON_EXIT;
+#endif
+ pan_exit(0);
+}
+FILE *
+findtrail(void)
+{ FILE *fd;
+ char fnm[512], *q;
+ char MyFile[512];
+ char MySuffix[16];
+ int try_core;
+ int candidate_files;
+
+ if (trailfilename != NULL)
+ { fd = fopen(trailfilename, "r");
+ if (fd == NULL)
+ { printf("pan: cannot find %s\n", trailfilename);
+ pan_exit(1);
+ } /* else */
+ goto success;
+ }
+talk:
+ try_core = 1;
+ candidate_files = 0;
+ tprefix = "trail";
+ strcpy(MyFile, TrailFile);
+ do { /* see if there's more than one possible trailfile */
+ if (whichtrail)
+ { sprintf(fnm, "%s%d.%s",
+ MyFile, whichtrail, tprefix);
+ fd = fopen(fnm, "r");
+ if (fd != NULL)
+ { candidate_files++;
+ if (verbose==100)
+ printf("trail%d: %s\n",
+ candidate_files, fnm);
+ fclose(fd);
+ }
+ if ((q = strchr(MyFile, '.')) != NULL)
+ { *q = '\0';
+ sprintf(fnm, "%s%d.%s",
+ MyFile, whichtrail, tprefix);
+ *q = '.';
+ fd = fopen(fnm, "r");
+ if (fd != NULL)
+ { candidate_files++;
+ if (verbose==100)
+ printf("trail%d: %s\n",
+ candidate_files, fnm);
+ fclose(fd);
+ } }
+ } else
+ { sprintf(fnm, "%s.%s", MyFile, tprefix);
+ fd = fopen(fnm, "r");
+ if (fd != NULL)
+ { candidate_files++;
+ if (verbose==100)
+ printf("trail%d: %s\n",
+ candidate_files, fnm);
+ fclose(fd);
+ }
+ if ((q = strchr(MyFile, '.')) != NULL)
+ { *q = '\0';
+ sprintf(fnm, "%s.%s", MyFile, tprefix);
+ *q = '.';
+ fd = fopen(fnm, "r");
+ if (fd != NULL)
+ { candidate_files++;
+ if (verbose==100)
+ printf("trail%d: %s\n",
+ candidate_files, fnm);
+ fclose(fd);
+ } } }
+ tprefix = MySuffix;
+ sprintf(tprefix, "cpu%d_trail", try_core++);
+ } while (try_core <= NCORE);
+
+ if (candidate_files != 1)
+ { if (verbose != 100)
+ { printf("error: there are %d trail files:\n",
+ candidate_files);
+ verbose = 100;
+ goto talk;
+ } else
+ { printf("pan: rm or mv all except one\n");
+ exit(1);
+ } }
+ try_core = 1;
+ strcpy(MyFile, TrailFile); /* restore */
+ tprefix = "trail";
+try_again:
+ if (whichtrail)
+ { sprintf(fnm, "%s%d.%s", MyFile, whichtrail, tprefix);
+ fd = fopen(fnm, "r");
+ if (fd == NULL && (q = strchr(MyFile, '.')))
+ { *q = '\0';
+ sprintf(fnm, "%s%d.%s",
+ MyFile, whichtrail, tprefix);
+ *q = '.';
+ fd = fopen(fnm, "r");
+ }
+ } else
+ { sprintf(fnm, "%s.%s", MyFile, tprefix);
+ fd = fopen(fnm, "r");
+ if (fd == NULL && (q = strchr(MyFile, '.')))
+ { *q = '\0';
+ sprintf(fnm, "%s.%s", MyFile, tprefix);
+ *q = '.';
+ fd = fopen(fnm, "r");
+ } }
+ if (fd == NULL)
+ { if (try_core < NCORE)
+ { tprefix = MySuffix;
+ sprintf(tprefix, "cpu%d_trail", try_core++);
+ goto try_again;
+ }
+ printf("pan: cannot find trailfile %s\n", fnm);
+ pan_exit(1);
+ }
+success:
+#if NCORE>1 && defined(SEP_STATE)
+ { void set_root(void); /* for partial traces from local root */
+ set_root();
+ }
+#endif
+ return fd;
+}
+
+uchar do_transit(Trans *, short);
+
+void
+getrail(void)
+{ FILE *fd;
+ char *q;
+ int i, t_id, lastnever=-1; short II;
+ Trans *t;
+ P0 *z;
+
+ fd = findtrail(); /* exits if unsuccessful */
+ while (fscanf(fd, "%ld:%d:%d\n", &depth, &i, &t_id) == 3)
+ { if (depth == -1)
+ printf("<<<<<START OF CYCLE>>>>>\n");
+ if (depth < 0)
+ continue;
+ if (i > now._nr_pr)
+ { printf("pan: Error, proc %d invalid pid ", i);
+ printf("transition %d\n", t_id);
+ break;
+ }
+ II = i;
+ z = (P0 *)pptr(II);
+ for (t = trans[z->_t][z->_p]; t; t = t->nxt)
+ if (t->t_id == (T_ID) t_id)
+ break;
+ if (!t)
+ { for (i = 0; i < NrStates[z->_t]; i++)
+ { t = trans[z->_t][i];
+ if (t && t->t_id == (T_ID) t_id)
+ { printf("\tRecovered at state %d\n", i);
+ z->_p = i;
+ goto recovered;
+ } }
+ printf("pan: Error, proc %d type %d state %d: ",
+ II, z->_t, z->_p);
+ printf("transition %d not found\n", t_id);
+ printf("pan: list of possible transitions in this process:\n");
+ if (z->_t >= 0 && z->_t <= _NP_)
+ for (t = trans[z->_t][z->_p]; t; t = t->nxt)
+ printf(" t_id %d -- case %d, [%s]\n",
+ t->t_id, t->forw, t->tp);
+ break; /* pan_exit(1); */
+ }
+recovered:
+ q = transmognify(t->tp);
+ if (gui) simvals[0] = '\0';
+ this = pptr(II);
+ trpt->tau |= 1;
+ if (!do_transit(t, II))
+ { if (onlyproc >= 0 && II != onlyproc)
+ goto moveon;
+ printf("pan: error, next transition UNEXECUTABLE on replay\n");
+ printf(" most likely causes: missing c_track statements\n");
+ printf(" or illegal side-effects in c_expr statements\n");
+ }
+ if (onlyproc >= 0 && II != onlyproc)
+ goto moveon;
+ if (verbose)
+ { printf("%3ld: proc %2d (%s) ", depth, II, procname[z->_t]);
+ for (i = 0; src_all[i].src; i++)
+ if (src_all[i].tp == (int) z->_t)
+ { printf(" line %3d \"%s\" ",
+ src_all[i].src[z->_p], PanSource);
+ break;
+ }
+ printf("(state %d) trans {%d,%d} [%s]\n",
+ z->_p, t_id, t->forw, q?q:"");
+ c_globals();
+ for (i = 0; i < now._nr_pr; i++)
+ { c_locals(i, ((P0 *)pptr(i))->_t);
+ }
+ } else
+ if (strcmp(procname[z->_t], ":never:") == 0)
+ { if (lastnever != (int) z->_p)
+ { for (i = 0; src_all[i].src; i++)
+ if (src_all[i].tp == (int) z->_t)
+ { printf("MSC: ~G %d\n",
+ src_all[i].src[z->_p]);
+ break;
+ }
+ if (!src_all[i].src)
+ printf("MSC: ~R %d\n", z->_p);
+ }
+ lastnever = z->_p;
+ goto sameas;
+ } else
+ if (strcmp(procname[z->_t], ":np_:") != 0)
+ {
+sameas: if (no_rck) goto moveon;
+ if (coltrace)
+ { printf("%ld: ", depth);
+ for (i = 0; i < II; i++)
+ printf("\t\t");
+ printf("%s(%d):", procname[z->_t], II);
+ printf("[%s]\n", q?q:"");
+ } else if (!silent)
+ { if (strlen(simvals) > 0) {
+ printf("%3ld: proc %2d (%s)",
+ depth, II, procname[z->_t]);
+ for (i = 0; src_all[i].src; i++)
+ if (src_all[i].tp == (int) z->_t)
+ { printf(" line %3d \"%s\" ",
+ src_all[i].src[z->_p], PanSource);
+ break;
+ }
+ printf("(state %d) [values: %s]\n", z->_p, simvals);
+ }
+ printf("%3ld: proc %2d (%s)",
+ depth, II, procname[z->_t]);
+ for (i = 0; src_all[i].src; i++)
+ if (src_all[i].tp == (int) z->_t)
+ { printf(" line %3d \"%s\" ",
+ src_all[i].src[z->_p], PanSource);
+ break;
+ }
+ printf("(state %d) [%s]\n", z->_p, q?q:"");
+ /* printf("\n"); */
+ } }
+moveon: z->_p = t->st;
+ }
+ wrap_trail();
+}
+#endif
+int
+f_pid(int pt)
+{ int i;
+ P0 *z;
+ for (i = 0; i < now._nr_pr; i++)
+ { z = (P0 *)pptr(i);
+ if (z->_t == (unsigned) pt)
+ return BASE+z->_pid;
+ }
+ return -1;
+}
+#ifdef VERI
+void check_claim(int);
+#endif
+
+#if !defined(HASH64) && !defined(HASH32)
+ #define HASH32
+#endif
+#if defined(HASH32) && defined(SAFETY) && !defined(SFH) && !defined(SPACE)
+ #define SFH
+#endif
+#if defined(SFH) && (defined(BITSTATE) || defined(COLLAPSE) || defined(HC) || defined(HASH64))
+ #undef SFH
+#endif
+#if defined(SFH) && !defined(NOCOMP)
+ #define NOCOMP /* go for speed */
+#endif
+#if NCORE>1 && !defined(GLOB_HEAP)
+ #define SEP_HEAP /* version 5.1.2 */
+#endif
+
+#ifdef BITSTATE
+int
+bstore_mod(char *v, int n) /* hasharray size not a power of two */
+{ unsigned long x, y;
+ unsigned int i = 1;
+
+ d_hash((uchar *) v, n); /* sets j3, j4, K1, K2 */
+ x = K1; y = j3;
+ for (;;)
+ { if (!(SS[x%udmem]&(1<<y))) break;
+ if (i == hfns) {
+#ifdef DEBUG
+ printf("Old bitstate\n");
+#endif
+ return 1;
+ }
+ x = (x + K2 + i);
+ y = (y + j4) & 7;
+ i++;
+ }
+#ifdef RANDSTOR
+ if (rand()%100 > RANDSTOR) return 0;
+#endif
+ for (;;)
+ { SS[x%udmem] |= (1<<y);
+ if (i == hfns) break;
+ x = (x + K2 + i);
+ y = (y + j4) & 7;
+ i++;
+ }
+#ifdef DEBUG
+ printf("New bitstate\n");
+#endif
+ if (now._a_t&1)
+ { nShadow++;
+ }
+ return 0;
+}
+int
+bstore_reg(char *v, int n) /* extended hashing, Peter Dillinger, 2004 */
+{ unsigned long x, y;
+ unsigned int i = 1;
+
+ d_hash((uchar *) v, n); /* sets j1-j4 */
+ x = j2; y = j3;
+ for (;;)
+ { if (!(SS[x]&(1<<y))) break;
+ if (i == hfns) {
+#ifdef DEBUG
+ printf("Old bitstate\n");
+#endif
+ return 1;
+ }
+ x = (x + j1 + i) & nmask;
+ y = (y + j4) & 7;
+ i++;
+ }
+#ifdef RANDSTOR
+ if (rand()%100 > RANDSTOR) return 0;
+#endif
+ for (;;)
+ { SS[x] |= (1<<y);
+ if (i == hfns) break;
+ x = (x + j1 + i) & nmask;
+ y = (y + j4) & 7;
+ i++;
+ }
+#ifdef DEBUG
+ printf("New bitstate\n");
+#endif
+ if (now._a_t&1)
+ { nShadow++;
+ }
+ return 0;
+}
+#endif
+unsigned long TMODE = 0666; /* file permission bits for trail files */
+
+int trcnt=1;
+char snap[64], fnm[512];
+
+int
+make_trail(void)
+{ int fd;
+ char *q;
+ char MyFile[512];
+ int w_flags = O_CREAT|O_WRONLY|O_TRUNC;
+
+ if (exclusive == 1 && iterative == 0)
+ { w_flags |= O_EXCL;
+ }
+
+ q = strrchr(TrailFile, '/');
+ if (q == NULL) q = TrailFile; else q++;
+ strcpy(MyFile, q); /* TrailFile is not a writable string */
+
+ if (iterative == 0 && Nr_Trails++ > 0)
+ { sprintf(fnm, "%s%d.%s",
+ MyFile, Nr_Trails-1, tprefix);
+ } else
+ {
+#ifdef PUTPID
+ sprintf(fnm, "%s%d.%s", MyFile, getpid(), tprefix);
+#else
+ sprintf(fnm, "%s.%s", MyFile, tprefix);
+#endif
+ }
+ if ((fd = open(fnm, w_flags, TMODE)) < 0)
+ { if ((q = strchr(MyFile, '.')))
+ { *q = '\0';
+ if (iterative == 0 && Nr_Trails-1 > 0)
+ sprintf(fnm, "%s%d.%s",
+ MyFile, Nr_Trails-1, tprefix);
+ else
+ sprintf(fnm, "%s.%s", MyFile, tprefix);
+ *q = '.';
+ fd = open(fnm, w_flags, TMODE);
+ } }
+ if (fd < 0)
+ { printf("pan: cannot create %s\n", fnm);
+ perror("cause");
+ } else
+ {
+#if NCORE>1 && (defined(SEP_STATE) || !defined(FULL_TRAIL))
+ void write_root(void);
+ write_root();
+#else
+ printf("pan: wrote %s\n", fnm);
+#endif
+ }
+ return fd;
+}
+
+#ifndef FREQ
+#define FREQ (1000000)
+#endif
+#ifdef BFS
+#define Q_PROVISO
+#ifndef INLINE_REV
+#define INLINE_REV
+#endif
+
+typedef struct SV_Hold {
+ State *sv;
+ int sz;
+ struct SV_Hold *nxt;
+} SV_Hold;
+
+typedef struct EV_Hold {
+ char *sv;
+ int sz;
+ int nrpr;
+ int nrqs;
+ char *po;
+ char *qo;
+ char *ps, *qs;
+ struct EV_Hold *nxt;
+} EV_Hold;
+
+typedef struct BFS_Trail {
+ Trail *frame;
+ SV_Hold *onow;
+ EV_Hold *omask;
+#ifdef Q_PROVISO
+ struct H_el *lstate;
+#endif
+ short boq;
+ struct BFS_Trail *nxt;
+} BFS_Trail;
+
+BFS_Trail *bfs_trail, *bfs_bot, *bfs_free;
+
+SV_Hold *svhold, *svfree;
+
+#ifdef BFS_DISK
+#ifndef BFS_LIMIT
+ #define BFS_LIMIT 100000
+#endif
+#ifndef BFS_DSK_LIMIT
+ #define BFS_DSK_LIMIT 1000000
+#endif
+#if defined(WIN32) || defined(WIN64)
+ #define RFLAGS (O_RDONLY|O_BINARY)
+ #define WFLAGS (O_CREAT|O_WRONLY|O_TRUNC|O_BINARY)
+#else
+ #define RFLAGS (O_RDONLY)
+ #define WFLAGS (O_CREAT|O_WRONLY|O_TRUNC)
+#endif
+long bfs_size_limit;
+int bfs_dsk_write = -1;
+int bfs_dsk_read = -1;
+long bfs_dsk_writes, bfs_dsk_reads;
+int bfs_dsk_seqno_w, bfs_dsk_seqno_r;
+#endif
+
+uchar do_reverse(Trans *, short, uchar);
+void snapshot(void);
+
+SV_Hold *
+getsv(int n)
+{ SV_Hold *h = (SV_Hold *) 0, *oh;
+
+ oh = (SV_Hold *) 0;
+ for (h = svfree; h; oh = h, h = h->nxt)
+ { if (n == h->sz)
+ { if (!oh)
+ svfree = h->nxt;
+ else
+ oh->nxt = h->nxt;
+ h->nxt = (SV_Hold *) 0;
+ break;
+ }
+ if (n < h->sz)
+ { h = (SV_Hold *) 0;
+ break;
+ }
+ /* else continue */
+ }
+
+ if (!h)
+ { h = (SV_Hold *) emalloc(sizeof(SV_Hold));
+ h->sz = n;
+#ifdef BFS_DISK
+ if (bfs_size_limit >= BFS_LIMIT)
+ { h->sv = (State *) 0; /* means: read disk */
+ bfs_dsk_writes++; /* count */
+ if (bfs_dsk_write < 0 /* file descriptor */
+ || bfs_dsk_writes%BFS_DSK_LIMIT == 0)
+ { char dsk_nm[32];
+ if (bfs_dsk_write >= 0)
+ { (void) close(bfs_dsk_write);
+ }
+ sprintf(dsk_nm, "pan_bfs_%d.tmp", bfs_dsk_seqno_w++);
+ bfs_dsk_write = open(dsk_nm, WFLAGS, 0644);
+ if (bfs_dsk_write < 0)
+ { Uerror("could not create tmp disk file");
+ }
+ printf("pan: created disk file %s\n", dsk_nm);
+ }
+ if (write(bfs_dsk_write, (char *) &now, n) != n)
+ { Uerror("aborting -- disk write failed (disk full?)");
+ }
+ return h; /* no memcpy */
+ }
+ bfs_size_limit++;
+#endif
+ h->sv = (State *) emalloc(sizeof(State) - VECTORSZ + n);
+ }
+
+ memcpy((char *)h->sv, (char *)&now, n);
+ return h;
+}
+
+EV_Hold *
+getsv_mask(int n)
+{ EV_Hold *h;
+ static EV_Hold *kept = (EV_Hold *) 0;
+
+ for (h = kept; h; h = h->nxt)
+ if (n == h->sz
+ && (memcmp((char *) Mask, (char *) h->sv, n) == 0)
+ && (now._nr_pr == h->nrpr)
+ && (now._nr_qs == h->nrqs)
+#if VECTORSZ>32000
+ && (memcmp((char *) proc_offset, (char *) h->po, now._nr_pr * sizeof(int)) == 0)
+ && (memcmp((char *) q_offset, (char *) h->qo, now._nr_qs * sizeof(int)) == 0)
+#else
+ && (memcmp((char *) proc_offset, (char *) h->po, now._nr_pr * sizeof(short)) == 0)
+ && (memcmp((char *) q_offset, (char *) h->qo, now._nr_qs * sizeof(short)) == 0)
+#endif
+ && (memcmp((char *) proc_skip, (char *) h->ps, now._nr_pr * sizeof(uchar)) == 0)
+ && (memcmp((char *) q_skip, (char *) h->qs, now._nr_qs * sizeof(uchar)) == 0))
+ break;
+ if (!h)
+ { h = (EV_Hold *) emalloc(sizeof(EV_Hold));
+ h->sz = n;
+ h->nrpr = now._nr_pr;
+ h->nrqs = now._nr_qs;
+
+ h->sv = (char *) emalloc(n * sizeof(char));
+ memcpy((char *) h->sv, (char *) Mask, n);
+
+ if (now._nr_pr > 0)
+ { h->ps = (char *) emalloc(now._nr_pr * sizeof(int));
+ memcpy((char *) h->ps, (char *) proc_skip, now._nr_pr * sizeof(uchar));
+#if VECTORSZ>32000
+ h->po = (char *) emalloc(now._nr_pr * sizeof(int));
+ memcpy((char *) h->po, (char *) proc_offset, now._nr_pr * sizeof(int));
+#else
+ h->po = (char *) emalloc(now._nr_pr * sizeof(short));
+ memcpy((char *) h->po, (char *) proc_offset, now._nr_pr * sizeof(short));
+#endif
+ }
+ if (now._nr_qs > 0)
+ { h->qs = (char *) emalloc(now._nr_qs * sizeof(int));
+ memcpy((char *) h->qs, (char *) q_skip, now._nr_qs * sizeof(uchar));
+#if VECTORSZ>32000
+ h->qo = (char *) emalloc(now._nr_qs * sizeof(int));
+ memcpy((char *) h->qo, (char *) q_offset, now._nr_qs * sizeof(int));
+#else
+ h->qo = (char *) emalloc(now._nr_qs * sizeof(short));
+ memcpy((char *) h->qo, (char *) q_offset, now._nr_qs * sizeof(short));
+#endif
+ }
+
+ h->nxt = kept;
+ kept = h;
+ }
+ return h;
+}
+
+void
+freesv(SV_Hold *p)
+{ SV_Hold *h, *oh;
+
+ oh = (SV_Hold *) 0;
+ for (h = svfree; h; oh = h, h = h->nxt)
+ if (h->sz >= p->sz)
+ break;
+
+ if (!oh)
+ { p->nxt = svfree;
+ svfree = p;
+ } else
+ { p->nxt = h;
+ oh->nxt = p;
+ }
+}
+
+BFS_Trail *
+get_bfs_frame(void)
+{ BFS_Trail *t;
+
+ if (bfs_free)
+ { t = bfs_free;
+ bfs_free = bfs_free->nxt;
+ t->nxt = (BFS_Trail *) 0;
+ } else
+ { t = (BFS_Trail *) emalloc(sizeof(BFS_Trail));
+ }
+ t->frame = (Trail *) emalloc(sizeof(Trail));
+ return t;
+}
+
+void
+push_bfs(Trail *f, int d)
+{ BFS_Trail *t;
+
+ t = get_bfs_frame();
+ memcpy((char *)t->frame, (char *)f, sizeof(Trail));
+ t->frame->o_tt = d; /* depth */
+
+ t->boq = boq;
+ t->onow = getsv(vsize);
+ t->omask = getsv_mask(vsize);
+#if defined(FULLSTACK) && defined(Q_PROVISO)
+ t->lstate = Lstate;
+#endif
+ if (!bfs_bot)
+ { bfs_bot = bfs_trail = t;
+ } else
+ { bfs_bot->nxt = t;
+ bfs_bot = t;
+ }
+#ifdef CHECK
+ printf("PUSH %u (%d)\n", t->frame, d);
+#endif
+}
+
+Trail *
+pop_bfs(void)
+{ BFS_Trail *t;
+
+ if (!bfs_trail)
+ return (Trail *) 0;
+
+ t = bfs_trail;
+ bfs_trail = t->nxt;
+ if (!bfs_trail)
+ bfs_bot = (BFS_Trail *) 0;
+#if defined(Q_PROVISO) && !defined(BITSTATE) && !defined(NOREDUCE)
+ if (t->lstate) t->lstate->tagged = 0;
+#endif
+
+ t->nxt = bfs_free;
+ bfs_free = t;
+
+ vsize = t->onow->sz;
+ boq = t->boq;
+#ifdef BFS_DISK
+ if (t->onow->sv == (State *) 0)
+ { char dsk_nm[32];
+ bfs_dsk_reads++; /* count */
+ if (bfs_dsk_read >= 0 /* file descriptor */
+ && bfs_dsk_reads%BFS_DSK_LIMIT == 0)
+ { (void) close(bfs_dsk_read);
+ sprintf(dsk_nm, "pan_bfs_%d.tmp", bfs_dsk_seqno_r-1);
+ (void) unlink(dsk_nm);
+ bfs_dsk_read = -1;
+ }
+ if (bfs_dsk_read < 0)
+ { sprintf(dsk_nm, "pan_bfs_%d.tmp", bfs_dsk_seqno_r++);
+ bfs_dsk_read = open(dsk_nm, RFLAGS);
+ if (bfs_dsk_read < 0)
+ { Uerror("could not open temp disk file");
+ } }
+ if (read(bfs_dsk_read, (char *) &now, vsize) != vsize)
+ { Uerror("bad bfs disk file read");
+ }
+#ifndef NOVSZ
+ if (now._vsz != vsize)
+ { Uerror("disk read vsz mismatch");
+ }
+#endif
+ } else
+#endif
+ memcpy((uchar *) &now, (uchar *) t->onow->sv, vsize);
+ memcpy((uchar *) Mask, (uchar *) t->omask->sv, vsize);
+ if (now._nr_pr > 0)
+#if VECTORSZ>32000
+ { memcpy((char *)proc_offset, (char *)t->omask->po, now._nr_pr * sizeof(int));
+#else
+ { memcpy((char *)proc_offset, (char *)t->omask->po, now._nr_pr * sizeof(short));
+#endif
+ memcpy((char *)proc_skip, (char *)t->omask->ps, now._nr_pr * sizeof(uchar));
+ }
+ if (now._nr_qs > 0)
+#if VECTORSZ>32000
+ { memcpy((uchar *)q_offset, (uchar *)t->omask->qo, now._nr_qs * sizeof(int));
+#else
+ { memcpy((uchar *)q_offset, (uchar *)t->omask->qo, now._nr_qs * sizeof(short));
+#endif
+ memcpy((uchar *)q_skip, (uchar *)t->omask->qs, now._nr_qs * sizeof(uchar));
+ }
+#ifdef BFS_DISK
+ if (t->onow->sv != (State *) 0)
+#endif
+ freesv(t->onow); /* omask not freed */
+#ifdef CHECK
+ printf("POP %u (%d)\n", t->frame, t->frame->o_tt);
+#endif
+ return t->frame;
+}
+
+void
+store_state(Trail *ntrpt, int shortcut, short oboq)
+{
+#ifdef VERI
+ Trans *t2 = (Trans *) 0;
+ uchar ot; int tt, E_state;
+ uchar o_opm = trpt->o_pm, *othis = this;
+
+ if (shortcut)
+ {
+#ifdef VERBOSE
+ printf("claim: shortcut\n");
+#endif
+ goto store_it; /* no claim move */
+ }
+
+ this = (((uchar *)&now)+proc_offset[0]); /* 0 = never claim */
+ trpt->o_pm = 0;
+
+ tt = (int) ((P0 *)this)->_p;
+ ot = (uchar) ((P0 *)this)->_t;
+
+#ifdef HAS_UNLESS
+ E_state = 0;
+#endif
+ for (t2 = trans[ot][tt]; t2; t2 = t2?t2->nxt:(Trans *)0)
+ {
+#ifdef HAS_UNLESS
+ if (E_state > 0
+ && E_state != t2->e_trans)
+ break;
+#endif
+ if (do_transit(t2, 0))
+ {
+#ifdef VERBOSE
+ if (!reached[ot][t2->st])
+ printf("depth: %d -- claim move from %d -> %d\n",
+ trpt->o_tt, ((P0 *)this)->_p, t2->st);
+#endif
+#ifdef HAS_UNLESS
+ E_state = t2->e_trans;
+#endif
+ if (t2->st > 0)
+ { ((P0 *)this)->_p = t2->st;
+ reached[ot][t2->st] = 1;
+#ifndef NOCLAIM
+ check_claim(t2->st);
+#endif
+ }
+ if (now._nr_pr == 0) /* claim terminated */
+ uerror("end state in claim reached");
+
+#ifdef PEG
+ peg[t2->forw]++;
+#endif
+ trpt->o_pm |= 1;
+ if (t2->atom&2)
+ Uerror("atomic in claim not supported in BFS mode");
+store_it:
+
+#endif
+
+#ifdef BITSTATE
+ if (!bstore((char *)&now, vsize))
+#else
+#ifdef MA
+ if (!gstore((char *)&now, vsize, 0))
+#else
+ if (!hstore((char *)&now, vsize))
+#endif
+#endif
+ { static long sdone = (long) 0; long ndone;
+ nstates++;
+#ifndef NOREDUCE
+ trpt->tau |= 64;
+#endif
+ ndone = (unsigned long) (nstates/((double) FREQ));
+ if (ndone != sdone && mreached%10 != 0)
+ { snapshot();
+ sdone = ndone;
+#if defined(AUTO_RESIZE) && !defined(BITSTATE) && !defined(MA)
+ if (nstates > ((double)(1<<(ssize+1))))
+ { void resize_hashtable(void);
+ resize_hashtable();
+ }
+#endif
+ }
+#if SYNC
+ if (boq != -1)
+ midrv++;
+ else if (oboq != -1)
+ { Trail *x;
+ x = (Trail *) trpt->ostate; /* pre-rv state */
+ if (x) x->o_pm |= 4; /* mark success */
+ }
+#endif
+ push_bfs(ntrpt, trpt->o_tt+1);
+ } else
+ { truncs++;
+#if !defined(NOREDUCE) && defined(FULLSTACK) && defined(Q_PROVISO)
+#if !defined(BITSTATE)
+ if (Lstate && Lstate->tagged) trpt->tau |= 64;
+#else
+ if (trpt->tau&32)
+ { BFS_Trail *tprov;
+ for (tprov = bfs_trail; tprov; tprov = tprov->nxt)
+ if (tprov->onow->sv != (State *) 0
+ && memcmp((uchar *)&now, (uchar *)tprov->onow->sv, vsize) == 0)
+ { trpt->tau |= 64;
+ break; /* state is in queue */
+ } }
+#endif
+#endif
+ }
+#ifdef VERI
+ ((P0 *)this)->_p = tt; /* reset claim */
+ if (t2)
+ do_reverse(t2, 0, 0);
+ else
+ break;
+ } }
+ this = othis;
+ trpt->o_pm = o_opm;
+#endif
+}
+
+Trail *ntrpt;
+
+void
+bfs(void)
+{ Trans *t; Trail *otrpt, *x;
+ uchar _n, _m, ot, nps = 0;
+ int tt, E_state;
+ short II, From = (short) (now._nr_pr-1), To = BASE;
+ short oboq = boq;
+
+ ntrpt = (Trail *) emalloc(sizeof(Trail));
+ trpt->ostate = (struct H_el *) 0;
+ trpt->tau = 0;
+
+ trpt->o_tt = -1;
+ store_state(ntrpt, 0, oboq); /* initial state */
+
+ while ((otrpt = pop_bfs())) /* also restores now */
+ { memcpy((char *) trpt, (char *) otrpt, sizeof(Trail));
+#if defined(C_States) && (HAS_TRACK==1)
+ c_revert((uchar *) &(now.c_state[0]));
+#endif
+ if (trpt->o_pm & 4)
+ {
+#ifdef VERBOSE
+ printf("Revisit of atomic not needed (%d)\n",
+ trpt->o_pm);
+#endif
+ continue;
+ }
+#ifndef NOREDUCE
+ nps = 0;
+#endif
+ if (trpt->o_pm == 8)
+ { revrv++;
+ if (trpt->tau&8)
+ {
+#ifdef VERBOSE
+ printf("Break atomic (pm:%d,tau:%d)\n",
+ trpt->o_pm, trpt->tau);
+#endif
+ trpt->tau &= ~8;
+ }
+#ifndef NOREDUCE
+ else if (trpt->tau&32)
+ {
+#ifdef VERBOSE
+ printf("Void preselection (pm:%d,tau:%d)\n",
+ trpt->o_pm, trpt->tau);
+#endif
+ trpt->tau &= ~32;
+ nps = 1; /* no preselection in repeat */
+ }
+#endif
+ }
+ trpt->o_pm &= ~(4|8);
+ if (trpt->o_tt > mreached)
+ { mreached = trpt->o_tt;
+ if (mreached%10 == 0)
+ { snapshot();
+ } }
+ depth = trpt->o_tt;
+ if (depth >= maxdepth)
+ {
+#if SYNC
+ Trail *x;
+ if (boq != -1)
+ { x = (Trail *) trpt->ostate;
+ if (x) x->o_pm |= 4; /* not failing */
+ }
+#endif
+ truncs++;
+ if (!warned)
+ { warned = 1;
+ printf("error: max search depth too small\n");
+ }
+ if (bounded)
+ uerror("depth limit reached");
+ continue;
+ }
+#ifndef NOREDUCE
+ if (boq == -1 && !(trpt->tau&8) && nps == 0)
+ for (II = now._nr_pr-1; II >= BASE; II -= 1)
+ {
+Pickup: this = pptr(II);
+ tt = (int) ((P0 *)this)->_p;
+ ot = (uchar) ((P0 *)this)->_t;
+ if (trans[ot][tt]->atom & 8)
+ { t = trans[ot][tt];
+ if (t->qu[0] != 0)
+ { Ccheck++;
+ if (!q_cond(II, t))
+ continue;
+ Cholds++;
+ }
+ From = To = II;
+ trpt->tau |= 32; /* preselect marker */
+#ifdef DEBUG
+ printf("%3d: proc %d PreSelected (tau=%d)\n",
+ depth, II, trpt->tau);
+#endif
+ goto MainLoop;
+ } }
+ trpt->tau &= ~32;
+#endif
+Repeat:
+ if (trpt->tau&8) /* atomic */
+ { From = To = (short ) trpt->pr;
+ nlinks++;
+ } else
+ { From = now._nr_pr-1;
+ To = BASE;
+ }
+MainLoop:
+ _n = _m = 0;
+ for (II = From; II >= To; II -= 1)
+ {
+ this = (((uchar *)&now)+proc_offset[II]);
+ tt = (int) ((P0 *)this)->_p;
+ ot = (uchar) ((P0 *)this)->_t;
+#if SYNC
+ /* no rendezvous with same proc */
+ if (boq != -1 && trpt->pr == II) continue;
+#endif
+ ntrpt->pr = (uchar) II;
+ ntrpt->st = tt;
+ trpt->o_pm &= ~1; /* no move yet */
+#ifdef EVENT_TRACE
+ trpt->o_event = now._event;
+#endif
+#ifdef HAS_PROVIDED
+ if (!provided(II, ot, tt, t)) continue;
+#endif
+#ifdef HAS_UNLESS
+ E_state = 0;
+#endif
+ for (t = trans[ot][tt]; t; t = t->nxt)
+ {
+#ifdef HAS_UNLESS
+ if (E_state > 0
+ && E_state != t->e_trans)
+ break;
+#endif
+ ntrpt->o_t = t;
+
+ oboq = boq;
+
+ if (!(_m = do_transit(t, II)))
+ continue;
+
+ trpt->o_pm |= 1; /* we moved */
+ (trpt+1)->o_m = _m; /* for unsend */
+#ifdef PEG
+ peg[t->forw]++;
+#endif
+#ifdef CHECK
+ printf("%3d: proc %d exec %d, ",
+ depth, II, t->forw);
+ printf("%d to %d, %s %s %s",
+ tt, t->st, t->tp,
+ (t->atom&2)?"atomic":"",
+ (boq != -1)?"rendez-vous":"");
+#ifdef HAS_UNLESS
+ if (t->e_trans)
+ printf(" (escapes to state %d)", t->st);
+#endif
+ printf(" %saccepting [tau=%d]\n",
+ (trpt->o_pm&2)?"":"non-", trpt->tau);
+#endif
+#ifdef HAS_UNLESS
+ E_state = t->e_trans;
+#if SYNC>0
+ if (t->e_trans > 0 && (boq != -1 /* || oboq != -1 */))
+ { fprintf(efd, "error: the use of rendezvous stmnt in the escape clause\n");
+ fprintf(efd, " of an unless stmnt is not compatible with -DBFS\n");
+ pan_exit(1);
+ }
+#endif
+#endif
+ if (t->st > 0) ((P0 *)this)->_p = t->st;
+
+ /* ptr to pred: */ ntrpt->ostate = (struct H_el *) otrpt;
+ ntrpt->st = tt;
+ if (boq == -1 && (t->atom&2)) /* atomic */
+ ntrpt->tau = 8; /* record for next move */
+ else
+ ntrpt->tau = 0;
+
+ store_state(ntrpt, (boq != -1 || (t->atom&2)), oboq);
+#ifdef EVENT_TRACE
+ now._event = trpt->o_event;
+#endif
+
+ /* undo move and continue */
+ trpt++; /* this is where ovals and ipt are set */
+ do_reverse(t, II, _m); /* restore now. */
+ trpt--;
+#ifdef CHECK
+ #if NCORE>1
+ enter_critical(GLOBAL_LOCK); /* in verbose mode only */
+ printf("cpu%d: ", core_id);
+ #endif
+ printf("%3d: proc %d ", depth, II);
+ printf("reverses %d, %d to %d,",
+ t->forw, tt, t->st);
+ printf(" %s [abit=%d,adepth=%d,",
+ t->tp, now._a_t, A_depth);
+ printf("tau=%d,%d]\n",
+ trpt->tau, (trpt-1)->tau);
+ #if NCORE>1
+ leave_critical(GLOBAL_LOCK);
+ #endif
+#endif
+ reached[ot][t->st] = 1;
+ reached[ot][tt] = 1;
+
+ ((P0 *)this)->_p = tt;
+ _n |= _m;
+ } }
+#ifndef NOREDUCE
+ /* preselected - no succ definitely outside stack */
+ if ((trpt->tau&32) && !(trpt->tau&64))
+ { From = now._nr_pr-1; To = BASE;
+#ifdef DEBUG
+ cpu_printf("%3d: proc %d UnSelected (_n=%d, tau=%d)\n",
+ depth, II+1, (int) _n, trpt->tau);
+#endif
+ _n = 0; trpt->tau &= ~32;
+ if (II >= BASE)
+ goto Pickup;
+ goto MainLoop;
+ }
+ trpt->tau &= ~(32|64);
+#endif
+ if (_n != 0)
+ continue;
+#ifdef DEBUG
+ printf("%3d: no move [II=%d, tau=%d, boq=%d, _nr_pr=%d]\n",
+ depth, II, trpt->tau, boq, now._nr_pr);
+#endif
+ if (boq != -1)
+ { failedrv++;
+ x = (Trail *) trpt->ostate; /* pre-rv state */
+ if (!x) continue; /* root state */
+ if ((x->tau&8) || (x->tau&32)) /* break atomic or preselect at parent */
+ { x->o_pm |= 8; /* mark failure */
+ this = (((uchar *)&now)+proc_offset[otrpt->pr]);
+#ifdef VERBOSE
+ printf("\treset state of %d from %d to %d\n",
+ otrpt->pr, ((P0 *)this)->_p, otrpt->st);
+#endif
+ ((P0 *)this)->_p = otrpt->st;
+ unsend(boq); /* retract rv offer */
+ boq = -1;
+ push_bfs(x, x->o_tt);
+#ifdef VERBOSE
+ printf("failed rv, repush with %d\n", x->o_pm);
+#endif
+ }
+#ifdef VERBOSE
+ else printf("failed rv, tau at parent: %d\n", x->tau);
+#endif
+ } else if (now._nr_pr > 0)
+ {
+ if ((trpt->tau&8)) /* atomic */
+ { trpt->tau &= ~(1|8); /* 1=timeout, 8=atomic */
+#ifdef DEBUG
+ printf("%3d: atomic step proc %d blocks\n",
+ depth, II+1);
+#endif
+ goto Repeat;
+ }
+
+ if (!(trpt->tau&1)) /* didn't try timeout yet */
+ { trpt->tau |= 1;
+#ifdef DEBUG
+ printf("%d: timeout\n", depth);
+#endif
+ goto MainLoop;
+ }
+#ifndef VERI
+ if (!noends && !a_cycles && !endstate())
+ uerror("invalid end state");
+#endif
+ } }
+}
+
+void
+putter(Trail *trpt, int fd)
+{ long j;
+
+ if (!trpt) return;
+
+ if (trpt != (Trail *) trpt->ostate)
+ putter((Trail *) trpt->ostate, fd);
+
+ if (trpt->o_t)
+ { sprintf(snap, "%d:%d:%d\n",
+ trcnt++, trpt->pr, trpt->o_t->t_id);
+ j = strlen(snap);
+ if (write(fd, snap, j) != j)
+ { printf("pan: error writing %s\n", fnm);
+ pan_exit(1);
+ } }
+}
+
+void
+nuerror(char *str)
+{ int fd = make_trail();
+ int j;
+
+ if (fd < 0) return;
+#ifdef VERI
+ sprintf(snap, "-2:%d:-2\n", VERI);
+ write(fd, snap, strlen(snap));
+#endif
+#ifdef MERGED
+ sprintf(snap, "-4:-4:-4\n");
+ write(fd, snap, strlen(snap));
+#endif
+ trcnt = 1;
+ putter(trpt, fd);
+ if (ntrpt->o_t)
+ { sprintf(snap, "%d:%d:%d\n",
+ trcnt++, ntrpt->pr, ntrpt->o_t->t_id);
+ j = strlen(snap);
+ if (write(fd, snap, j) != j)
+ { printf("pan: error writing %s\n", fnm);
+ pan_exit(1);
+ } }
+ close(fd);
+ if (errors >= upto && upto != 0)
+ { wrapup();
+ }
+}
+#endif
+#if NCORE>1
+#if defined(WIN32) || defined(WIN64)
+#ifndef _CONSOLE
+ #define _CONSOLE
+#endif
+ #ifdef WIN64
+#undef long
+ #endif
+#include <windows.h>
+
+ #ifdef WIN64
+ #define long long long
+ #endif
+#else
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+#endif
+
+/* code common to cygwin/linux and win32/win64: */
+
+#ifdef VERBOSE
+ #define VVERBOSE (1)
+#else
+ #define VVERBOSE (0)
+#endif
+
+/* the following values must be larger than 256 and must fit in an int */
+#define QUIT 1024 /* terminate now command */
+#define QUERY 512 /* termination status query message */
+#define QUERY_F 513 /* query failed, cannot quit */
+
+#define GN_FRAMES (int) (GWQ_SIZE / (double) sizeof(SM_frame))
+#define LN_FRAMES (int) (LWQ_SIZE / (double) sizeof(SM_frame))
+
+#ifndef VMAX
+ #define VMAX VECTORSZ
+#endif
+#ifndef PMAX
+ #define PMAX 64
+#endif
+#ifndef QMAX
+ #define QMAX 64
+#endif
+
+#if VECTORSZ>32000
+ #define OFFT int
+#else
+ #define OFFT short
+#endif
+
+#ifdef SET_SEG_SIZE
+ /* no longer usefule -- being recomputed for local heap size anyway */
+ double SEG_SIZE = (((double) SET_SEG_SIZE) * 1048576.);
+#else
+ double SEG_SIZE = (1048576.*1024.); /* 1GB default shared memory pool segments */
+#endif
+
+double LWQ_SIZE = 0.; /* initialized in main */
+
+#ifdef SET_WQ_SIZE
+ #ifdef NGQ
+ #warning SET_WQ_SIZE applies to global queue -- ignored
+ double GWQ_SIZE = 0.;
+ #else
+ double GWQ_SIZE = (((double) SET_WQ_SIZE) * 1048576.);
+ /* must match the value in pan_proxy.c, if used */
+ #endif
+#else
+ #ifdef NGQ
+ double GWQ_SIZE = 0.;
+ #else
+ double GWQ_SIZE = (128.*1048576.); /* 128 MB default queue sizes */
+ #endif
+#endif
+
+/* Crash Detection Parameters */
+#ifndef ONESECOND
+ #define ONESECOND (1<<25)
+#endif
+#ifndef SHORT_T
+ #define SHORT_T (0.1)
+#endif
+#ifndef LONG_T
+ #define LONG_T (600)
+#endif
+
+double OneSecond = (double) (ONESECOND); /* waiting for a free slot -- checks crash */
+double TenSeconds = 10. * (ONESECOND); /* waiting for a lock -- check for a crash */
+
+/* Termination Detection Params -- waiting for new state input in Get_Full_Frame */
+double Delay = ((double) SHORT_T) * (ONESECOND); /* termination detection trigger */
+double OneHour = ((double) LONG_T) * (ONESECOND); /* timeout termination detection */
+
+typedef struct SM_frame SM_frame;
+typedef struct SM_results SM_results;
+typedef struct sh_Allocater sh_Allocater;
+
+struct SM_frame { /* about 6K per slot */
+ volatile int m_vsize; /* 0 means free slot */
+ volatile int m_boq; /* >500 is a control message */
+#ifdef FULL_TRAIL
+ volatile struct Stack_Tree *m_stack; /* ptr to previous state */
+#endif
+ volatile uchar m_tau;
+ volatile uchar m_o_pm;
+ volatile int nr_handoffs; /* to compute real_depth */
+ volatile char m_now [VMAX];
+ volatile char m_Mask [(VMAX + 7)/8];
+ volatile OFFT m_p_offset[PMAX];
+ volatile OFFT m_q_offset[QMAX];
+ volatile uchar m_p_skip [PMAX];
+ volatile uchar m_q_skip [QMAX];
+#if defined(C_States) && (HAS_TRACK==1) && (HAS_STACK==1)
+ volatile uchar m_c_stack [StackSize];
+#endif
+};
+
+int proxy_pid; /* id of proxy if nonzero -- receive half */
+int store_proxy_pid;
+short remote_party;
+int proxy_pid_snd; /* id of proxy if nonzero -- send half */
+char o_cmdline[512]; /* to pass options to children */
+
+int iamin[CS_NR+NCORE]; /* non-shared */
+
+#if defined(WIN32) || defined(WIN64)
+int tas(volatile LONG *);
+
+HANDLE proxy_handle_snd; /* for Windows Create and Terminate */
+
+struct sh_Allocater { /* shared memory for states */
+ volatile char *dc_arena; /* to allocate states from */
+ volatile long pattern; /* to detect overruns */
+ volatile long dc_size; /* nr of bytes left */
+ volatile void *dc_start; /* where memory segment starts */
+ volatile void *dc_id; /* to attach, detach, remove shared memory segments */
+ volatile sh_Allocater *nxt; /* linked list of pools */
+};
+DWORD worker_pids[NCORE]; /* root mem of pids of all workers created */
+HANDLE worker_handles[NCORE]; /* for windows Create and Terminate */
+void * shmid [NR_QS]; /* return value from CreateFileMapping */
+void * shmid_M; /* shared mem for state allocation in hashtable */
+
+#ifdef SEP_STATE
+ void *shmid_X;
+#else
+ void *shmid_S; /* shared bitstate arena or hashtable */
+#endif
+#else
+int tas(volatile int *);
+
+struct sh_Allocater { /* shared memory for states */
+ volatile char *dc_arena; /* to allocate states from */
+ volatile long pattern; /* to detect overruns */
+ volatile long dc_size; /* nr of bytes left */
+ volatile char *dc_start; /* where memory segment starts */
+ volatile int dc_id; /* to attach, detach, remove shared memory segments */
+ volatile sh_Allocater *nxt; /* linked list of pools */
+};
+
+int worker_pids[NCORE]; /* root mem of pids of all workers created */
+int shmid [NR_QS]; /* return value from shmget */
+int nibis = 0; /* set after shared mem has been released */
+int shmid_M; /* shared mem for state allocation in hashtable */
+#ifdef SEP_STATE
+ long shmid_X;
+#else
+ int shmid_S; /* shared bitstate arena or hashtable */
+ volatile sh_Allocater *first_pool; /* of shared state memory */
+ volatile sh_Allocater *last_pool;
+#endif
+#endif
+
+struct SM_results { /* for shuttling back final stats */
+ volatile int m_vsize; /* avoid conflicts with frames */
+ volatile int m_boq; /* these 2 fields are not written in record_info */
+ /* probably not all fields really need to be volatile */
+ volatile double m_memcnt;
+ volatile double m_nstates;
+ volatile double m_truncs;
+ volatile double m_truncs2;
+ volatile double m_nShadow;
+ volatile double m_nlinks;
+ volatile double m_ngrabs;
+ volatile double m_nlost;
+ volatile double m_hcmp;
+ volatile double m_frame_wait;
+ volatile int m_hmax;
+ volatile int m_svmax;
+ volatile int m_smax;
+ volatile int m_mreached;
+ volatile int m_errors;
+ volatile int m_VMAX;
+ volatile short m_PMAX;
+ volatile short m_QMAX;
+ volatile uchar m_R; /* reached info for all proctypes */
+};
+
+int core_id = 0; /* internal process nr, to know which q to use */
+unsigned long nstates_put = 0; /* statistics */
+unsigned long nstates_get = 0;
+int query_in_progress = 0; /* termination detection */
+
+double free_wait = 0.; /* waiting for a free frame */
+double frame_wait = 0.; /* waiting for a full frame */
+double lock_wait = 0.; /* waiting for access to cs */
+double glock_wait[3]; /* waiting for access to global lock */
+
+char *sprefix = "rst";
+uchar was_interrupted, issued_kill, writing_trail;
+
+static SM_frame cur_Root; /* current root, to be safe with error trails */
+
+SM_frame *m_workq [NR_QS]; /* per cpu work queues + global q */
+char *shared_mem[NR_QS]; /* return value from shmat */
+#ifdef SEP_HEAP
+char *my_heap;
+long my_size;
+#endif
+volatile sh_Allocater *dc_shared; /* assigned at initialization */
+
+static int vmax_seen, pmax_seen, qmax_seen;
+static double gq_tries, gq_hasroom, gq_hasnoroom;
+
+volatile int *prfree;
+volatile int *prfull;
+volatile int *prcnt;
+volatile int *prmax;
+
+volatile int *sh_lock; /* mutual exclusion locks - in shared memory */
+volatile double *is_alive; /* to detect when processes crash */
+volatile int *grfree, *grfull, *grcnt, *grmax; /* access to shared global q */
+volatile double *gr_readmiss, *gr_writemiss;
+static int lrfree; /* used for temporary recording of slot */
+static int dfs_phase2;
+
+void mem_put(int); /* handoff state to other cpu */
+void mem_put_acc(void); /* liveness mode */
+void mem_get(void); /* get state from work queue */
+void sudden_stop(char *);
+#if 0
+void enter_critical(int);
+void leave_critical(int);
+#endif
+
+void
+record_info(SM_results *r)
+{ int i;
+ uchar *ptr;
+
+#ifdef SEP_STATE
+ if (0)
+ { cpu_printf("nstates %g nshadow %g -- memory %-6.3f Mb\n",
+ nstates, nShadow, memcnt/(1048576.));
+ }
+ r->m_memcnt = 0;
+#else
+ #ifdef BITSTATE
+ r->m_memcnt = 0; /* it's shared */
+ #endif
+ r->m_memcnt = memcnt;
+#endif
+ if (a_cycles && core_id == 1)
+ { r->m_nstates = nstates;
+ r->m_nShadow = nstates;
+ } else
+ { r->m_nstates = nstates;
+ r->m_nShadow = nShadow;
+ }
+ r->m_truncs = truncs;
+ r->m_truncs2 = truncs2;
+ r->m_nlinks = nlinks;
+ r->m_ngrabs = ngrabs;
+ r->m_nlost = nlost;
+ r->m_hcmp = hcmp;
+ r->m_frame_wait = frame_wait;
+ r->m_hmax = hmax;
+ r->m_svmax = svmax;
+ r->m_smax = smax;
+ r->m_mreached = mreached;
+ r->m_errors = errors;
+ r->m_VMAX = vmax_seen;
+ r->m_PMAX = (short) pmax_seen;
+ r->m_QMAX = (short) qmax_seen;
+ ptr = (uchar *) &(r->m_R);
+ for (i = 0; i <= _NP_; i++) /* all proctypes */
+ { memcpy(ptr, reached[i], NrStates[i]*sizeof(uchar));
+ ptr += NrStates[i]*sizeof(uchar);
+ }
+ if (verbose>1)
+ { cpu_printf("Put Results nstates %g (sz %d)\n", nstates, ptr - &(r->m_R));
+ }
+}
+
+void snapshot(void);
+
+void
+retrieve_info(SM_results *r)
+{ int i, j;
+ volatile uchar *ptr;
+
+ snapshot(); /* for a final report */
+
+ enter_critical(GLOBAL_LOCK);
+#ifdef SEP_HEAP
+ if (verbose)
+ { printf("cpu%d: local heap-left %ld KB (%d MB)\n",
+ core_id, (int) (my_size/1024), (int) (my_size/1048576));
+ }
+#endif
+ if (verbose && core_id == 0)
+ { printf("qmax: ");
+ for (i = 0; i < NCORE; i++)
+ { printf("%d ", prmax[i]);
+ }
+#ifndef NGQ
+ printf("G: %d", *grmax);
+#endif
+ printf("\n");
+ }
+ leave_critical(GLOBAL_LOCK);
+
+ memcnt += r->m_memcnt;
+ nstates += r->m_nstates;
+ nShadow += r->m_nShadow;
+ truncs += r->m_truncs;
+ truncs2 += r->m_truncs2;
+ nlinks += r->m_nlinks;
+ ngrabs += r->m_ngrabs;
+ nlost += r->m_nlost;
+ hcmp += r->m_hcmp;
+ /* frame_wait += r->m_frame_wait; */
+ errors += r->m_errors;
+
+ if (hmax < r->m_hmax) hmax = r->m_hmax;
+ if (svmax < r->m_svmax) svmax = r->m_svmax;
+ if (smax < r->m_smax) smax = r->m_smax;
+ if (mreached < r->m_mreached) mreached = r->m_mreached;
+
+ if (vmax_seen < r->m_VMAX) vmax_seen = r->m_VMAX;
+ if (pmax_seen < (int) r->m_PMAX) pmax_seen = (int) r->m_PMAX;
+ if (qmax_seen < (int) r->m_QMAX) qmax_seen = (int) r->m_QMAX;
+
+ ptr = &(r->m_R);
+ for (i = 0; i <= _NP_; i++) /* all proctypes */
+ { for (j = 0; j < NrStates[i]; j++)
+ { if (*(ptr + j) != 0)
+ { reached[i][j] = 1;
+ } }
+ ptr += NrStates[i]*sizeof(uchar);
+ }
+ if (verbose>1)
+ { cpu_printf("Got Results (%d)\n", ptr - &(r->m_R));
+ snapshot();
+ }
+}
+
+#if !defined(WIN32) && !defined(WIN64)
+static void
+rm_shared_segments(void)
+{ int m;
+ volatile sh_Allocater *nxt_pool;
+ /*
+ * mark all shared memory segments for removal
+ * the actual removes wont happen intil last process dies or detaches
+ * the shmctl calls can return -1 if not all procs have detached yet
+ */
+ for (m = 0; m < NR_QS; m++) /* +1 for global q */
+ { if (shmid[m] != -1)
+ { (void) shmctl(shmid[m], IPC_RMID, NULL);
+ } }
+#ifdef SEP_STATE
+ if (shmid_M != -1)
+ { (void) shmctl(shmid_M, IPC_RMID, NULL);
+ }
+#else
+ if (shmid_S != -1)
+ { (void) shmctl(shmid_S, IPC_RMID, NULL);
+ }
+ for (last_pool = first_pool; last_pool != NULL; last_pool = nxt_pool)
+ { shmid_M = (int) (last_pool->dc_id);
+ nxt_pool = last_pool->nxt; /* as a pre-caution only */
+ if (shmid_M != -1)
+ { (void) shmctl(shmid_M, IPC_RMID, NULL);
+ } }
+#endif
+}
+#endif
+
+void
+sudden_stop(char *s)
+{ char b[64];
+ int i;
+
+ printf("cpu%d: stop - %s\n", core_id, s);
+#if !defined(WIN32) && !defined(WIN64)
+ if (proxy_pid != 0)
+ { rm_shared_segments();
+ }
+#endif
+ if (search_terminated != NULL)
+ { if (*search_terminated != 0)
+ { if (verbose)
+ { printf("cpu%d: termination initiated (%d)\n",
+ core_id, *search_terminated);
+ }
+ } else
+ { if (verbose)
+ { printf("cpu%d: initiated termination\n", core_id);
+ }
+ *search_terminated |= 8; /* sudden_stop */
+ }
+ if (core_id == 0)
+ { if (((*search_terminated) & 4) /* uerror in one of the cpus */
+ && !((*search_terminated) & (8|32|128|256))) /* abnormal stop */
+ { if (errors == 0) errors++; /* we know there is at least 1 */
+ }
+ wrapup(); /* incomplete stats, but at least something */
+ }
+ return;
+ } /* else: should rarely happen, take more drastic measures */
+
+ if (core_id == 0) /* local root process */
+ { for (i = 1; i < NCORE; i++) /* not for 0 of course */
+ {
+#if defined(WIN32) || defined(WIN64)
+ DWORD dwExitCode = 0;
+ GetExitCodeProcess(worker_handles[i], &dwExitCode);
+ if (dwExitCode == STILL_ACTIVE)
+ { TerminateProcess(worker_handles[i], 0);
+ }
+ printf("cpu0: terminate %d %d\n",
+ worker_pids[i], (dwExitCode == STILL_ACTIVE));
+#else
+ sprintf(b, "kill -%d %d", SIGKILL, worker_pids[i]);
+ system(b); /* if this is a proxy: receive half */
+ printf("cpu0: %s\n", b);
+#endif
+ }
+ issued_kill++;
+ } else
+ { /* on WIN32/WIN64 -- these merely kills the root process... */
+ if (was_interrupted == 0)
+ { sprintf(b, "kill -%d %d", SIGINT, worker_pids[0]);
+ system(b); /* warn the root process */
+ printf("cpu%d: %s\n", core_id, b);
+ issued_kill++;
+ } }
+}
+
+#define iam_alive() is_alive[core_id]++
+
+extern int crash_test(double);
+extern void crash_reset(void);
+
+int
+someone_crashed(int wait_type)
+{ static double last_value = 0.0;
+ static int count = 0;
+
+ if (search_terminated == NULL
+ || *search_terminated != 0)
+ {
+ if (!(*search_terminated & (8|32|128|256)))
+ { if (count++ < 100*NCORE)
+ { return 0;
+ } }
+ return 1;
+ }
+ /* check left neighbor only */
+ if (last_value == is_alive[(core_id + NCORE - 1) % NCORE])
+ { if (count++ >= 100) /* to avoid unnecessary checks */
+ { return 1;
+ }
+ return 0;
+ }
+ last_value = is_alive[(core_id + NCORE - 1) % NCORE];
+ count = 0;
+ crash_reset();
+ return 0;
+}
+
+void
+sleep_report(void)
+{
+ enter_critical(GLOBAL_LOCK);
+ if (verbose)
+ {
+#ifdef NGQ
+ printf("cpu%d: locks: global %g\tother %g\t",
+ core_id, glock_wait[0], lock_wait - glock_wait[0]);
+#else
+ printf("cpu%d: locks: GL %g, RQ %g, WQ %g, HT %g\t",
+ core_id, glock_wait[0], glock_wait[1], glock_wait[2],
+ lock_wait - glock_wait[0] - glock_wait[1] - glock_wait[2]);
+#endif
+ printf("waits: states %g slots %g\n", frame_wait, free_wait);
+#ifndef NGQ
+ printf("cpu%d: gq [tries %g, room %g, noroom %g]\n", core_id, gq_tries, gq_hasroom, gq_hasnoroom);
+ if (core_id == 0 && (*gr_readmiss >= 1.0 || *gr_readmiss >= 1.0 || *grcnt != 0))
+ printf("cpu0: gq [readmiss: %g, writemiss: %g cnt %d]\n", *gr_readmiss, *gr_writemiss, *grcnt);
+#endif
+ }
+ if (free_wait > 1000000.)
+ #ifndef NGQ
+ if (!a_cycles)
+ { printf("hint: this search may be faster with a larger work-queue\n");
+ printf(" (-DSET_WQ_SIZE=N with N>%g), and/or with -DUSE_DISK\n",
+ GWQ_SIZE/sizeof(SM_frame));
+ printf(" or with a larger value for -zN (N>%d)\n", z_handoff);
+ #else
+ { printf("hint: this search may be faster if compiled without -DNGQ, with -DUSE_DISK, ");
+ printf("or with a larger -zN (N>%d)\n", z_handoff);
+ #endif
+ }
+ leave_critical(GLOBAL_LOCK);
+}
+
+#ifndef MAX_DSK_FILE
+ #define MAX_DSK_FILE 1000000 /* default is max 1M states per file */
+#endif
+
+void
+multi_usage(FILE *fd)
+{ static int warned = 0;
+ if (warned > 0) { return; } else { warned++; }
+ fprintf(fd, "\n");
+ fprintf(fd, "Defining multi-core mode:\n\n");
+ fprintf(fd, " -DDUAL_CORE --> same as -DNCORE=2\n");
+ fprintf(fd, " -DQUAD_CORE --> same as -DNCORE=4\n");
+ fprintf(fd, " -DNCORE=N --> enables multi_core verification if N>1\n");
+ fprintf(fd, "\n");
+ fprintf(fd, "Additional directives supported in multi-core mode:\n\n");
+ fprintf(fd, " -DSEP_STATE --> forces separate statespaces instead of a single shared state space\n");
+ fprintf(fd, " -DNUSE_DISK --> use disk for storing states when a work queue overflows\n");
+ fprintf(fd, " -DMAX_DSK_FILE --> max nr of states per diskfile (%d)\n", MAX_DSK_FILE);
+ fprintf(fd, " -DFULL_TRAIL --> support full error trails (increases memory use)\n");
+ fprintf(fd, "\n");
+ fprintf(fd, "More advanced use (should rarely need changing):\n\n");
+ fprintf(fd, " To change the nr of states that can be stored in the global queue\n");
+ fprintf(fd, " (lower numbers allow for more states to be stored, prefer multiples of 8):\n");
+ fprintf(fd, " -DVMAX=N --> upperbound on statevector for handoffs (N=%d)\n", VMAX);
+ fprintf(fd, " -DPMAX=N --> upperbound on nr of procs (default: N=%d)\n", PMAX);
+ fprintf(fd, " -DQMAX=N --> upperbound on nr of channels (default: N=%d)\n", QMAX);
+ fprintf(fd, "\n");
+ fprintf(fd, " To set the total amount of memory reserved for the global workqueue:\n");
+ fprintf(fd, " -DSET_WQ_SIZE=N --> default: N=128 (defined in MBytes)\n\n");
+ fprintf(fd, " To force the use of a single global heap, instead of separate heaps:\n");
+ fprintf(fd, " -DGLOB_HEAP\n");
+ fprintf(fd, "\n");
+ fprintf(fd, " To define a fct to initialize data before spawning processes (use quotes):\n");
+ fprintf(fd, " \"-DC_INIT=fct()\"\n");
+ fprintf(fd, "\n");
+ fprintf(fd, " Timer settings for termination and crash detection:\n");
+ fprintf(fd, " -DSHORT_T=N --> timeout for termination detection trigger (N=%g)\n", (double) SHORT_T);
+ fprintf(fd, " -DLONG_T=N --> timeout for giving up on termination detection (N=%g)\n", (double) LONG_T);
+ fprintf(fd, " -DONESECOND --> (1<<29) --> timeout waiting for a free slot -- to check for crash\n");
+ fprintf(fd, " -DT_ALERT --> collect stats on crash alert timeouts\n\n");
+ fprintf(fd, "Help with Linux/Windows/Cygwin configuration for multi-core:\n");
+ fprintf(fd, " http://spinroot.com/spin/multicore/V5_Readme.html\n");
+ fprintf(fd, "\n");
+}
+#if NCORE>1 && defined(FULL_TRAIL)
+typedef struct Stack_Tree {
+ uchar pr; /* process that made transition */
+ T_ID t_id; /* id of transition */
+ volatile struct Stack_Tree *prv; /* backward link towards root */
+} Stack_Tree;
+
+struct H_el *grab_shared(int);
+volatile Stack_Tree **stack_last; /* in shared memory */
+char *stack_cache = NULL; /* local */
+int nr_cached = 0; /* local */
+
+#ifndef CACHE_NR
+ #define CACHE_NR 1024
+#endif
+
+volatile Stack_Tree *
+stack_prefetch(void)
+{ volatile Stack_Tree *st;
+
+ if (nr_cached == 0)
+ { stack_cache = (char *) grab_shared(CACHE_NR * sizeof(Stack_Tree));
+ nr_cached = CACHE_NR;
+ }
+ st = (volatile Stack_Tree *) stack_cache;
+ stack_cache += sizeof(Stack_Tree);
+ nr_cached--;
+ return st;
+}
+
+void
+Push_Stack_Tree(short II, T_ID t_id)
+{ volatile Stack_Tree *st;
+
+ st = (volatile Stack_Tree *) stack_prefetch();
+ st->pr = II;
+ st->t_id = t_id;
+ st->prv = (Stack_Tree *) stack_last[core_id];
+ stack_last[core_id] = st;
+}
+
+void
+Pop_Stack_Tree(void)
+{ volatile Stack_Tree *cf = stack_last[core_id];
+
+ if (cf)
+ { stack_last[core_id] = cf->prv;
+ } else if (nr_handoffs * z_handoff + depth > 0)
+ { printf("cpu%d: error pop_stack_tree (depth %d)\n",
+ core_id, depth);
+ }
+}
+#endif
+
+void
+e_critical(int which)
+{ double cnt_start;
+
+ if (readtrail || iamin[which] > 0)
+ { if (!readtrail && verbose)
+ { printf("cpu%d: Double Lock on %d (now %d)\n",
+ core_id, which, iamin[which]+1);
+ fflush(stdout);
+ }
+ iamin[which]++; /* local variable */
+ return;
+ }
+
+ cnt_start = lock_wait;
+
+ while (sh_lock != NULL) /* as long as we have shared memory */
+ { int r = tas(&sh_lock[which]);
+ if (r == 0)
+ { iamin[which] = 1;
+ return; /* locked */
+ }
+
+ lock_wait++;
+#ifndef NGQ
+ if (which < 3) { glock_wait[which]++; }
+#else
+ if (which == 0) { glock_wait[which]++; }
+#endif
+ iam_alive();
+
+ if (lock_wait - cnt_start > TenSeconds)
+ { printf("cpu%d: lock timeout on %d\n", core_id, which);
+ cnt_start = lock_wait;
+ if (someone_crashed(1))
+ { sudden_stop("lock timeout");
+ pan_exit(1);
+ } } }
+}
+
+void
+x_critical(int which)
+{
+ if (iamin[which] != 1)
+ { if (iamin[which] > 1)
+ { iamin[which]--; /* this is thread-local - no races on this one */
+ if (!readtrail && verbose)
+ { printf("cpu%d: Partial Unlock on %d (%d more needed)\n",
+ core_id, which, iamin[which]);
+ fflush(stdout);
+ }
+ return;
+ } else /* iamin[which] <= 0 */
+ { if (!readtrail)
+ { printf("cpu%d: Invalid Unlock iamin[%d] = %d\n",
+ core_id, which, iamin[which]);
+ fflush(stdout);
+ }
+ return;
+ } }
+
+ if (sh_lock != NULL)
+ { iamin[which] = 0;
+ sh_lock[which] = 0; /* unlock */
+ }
+}
+
+void
+#if defined(WIN32) || defined(WIN64)
+start_proxy(char *s, DWORD r_pid)
+#else
+start_proxy(char *s, int r_pid)
+#endif
+{ char Q_arg[16], Z_arg[16], Y_arg[16];
+ char *args[32], *ptr;
+ int argcnt = 0;
+
+ sprintf(Q_arg, "-Q%d", getpid());
+ sprintf(Y_arg, "-Y%d", r_pid);
+ sprintf(Z_arg, "-Z%d", proxy_pid /* core_id */);
+
+ args[argcnt++] = "proxy";
+ args[argcnt++] = s; /* -r or -s */
+ args[argcnt++] = Q_arg;
+ args[argcnt++] = Z_arg;
+ args[argcnt++] = Y_arg;
+
+ if (strlen(o_cmdline) > 0)
+ { ptr = o_cmdline; /* assume args separated by spaces */
+ do { args[argcnt++] = ptr++;
+ if ((ptr = strchr(ptr, ' ')) != NULL)
+ { while (*ptr == ' ')
+ { *ptr++ = '\0';
+ }
+ } else
+ { break;
+ }
+ } while (argcnt < 31);
+ }
+ args[argcnt] = NULL;
+#if defined(WIN32) || defined(WIN64)
+ execvp("pan_proxy", args); /* no return */
+#else
+ execvp("./pan_proxy", args); /* no return */
+#endif
+ Uerror("pan_proxy exec failed");
+}
+/*** end of common code fragment ***/
+
+#if !defined(WIN32) && !defined(WIN64)
+void
+init_shm(void) /* initialize shared work-queues - linux/cygwin */
+{ key_t key[NR_QS];
+ int n, m;
+ int must_exit = 0;
+
+ if (core_id == 0 && verbose)
+ { printf("cpu0: step 3: allocate shared workqueues %g MB\n",
+ ((double) NCORE * LWQ_SIZE + GWQ_SIZE) / (1048576.) );
+ }
+ for (m = 0; m < NR_QS; m++) /* last q is the global q */
+ { double qsize = (m == NCORE) ? GWQ_SIZE : LWQ_SIZE;
+ key[m] = ftok(PanSource, m+1);
+ if (key[m] == -1)
+ { perror("ftok shared queues"); must_exit = 1; break;
+ }
+
+ if (core_id == 0) /* root creates */
+ { /* check for stale copy */
+ shmid[m] = shmget(key[m], (size_t) qsize, 0600);
+ if (shmid[m] != -1) /* yes there is one; remove it */
+ { printf("cpu0: removing stale q%d, status: %d\n",
+ m, shmctl(shmid[m], IPC_RMID, NULL));
+ }
+ shmid[m] = shmget(key[m], (size_t) qsize, 0600|IPC_CREAT|IPC_EXCL);
+ memcnt += qsize;
+ } else /* workers attach */
+ { shmid[m] = shmget(key[m], (size_t) qsize, 0600);
+ /* never called, since we create shm *before* we fork */
+ }
+ if (shmid[m] == -1)
+ { perror("shmget shared queues"); must_exit = 1; break;
+ }
+
+ shared_mem[m] = (char *) shmat(shmid[m], (void *) 0, 0); /* attach */
+ if (shared_mem[m] == (char *) -1)
+ { fprintf(stderr, "error: cannot attach shared wq %d (%d Mb)\n",
+ m+1, (int) (qsize/(1048576.)));
+ perror("shmat shared queues"); must_exit = 1; break;
+ }
+
+ m_workq[m] = (SM_frame *) shared_mem[m];
+ if (core_id == 0)
+ { int nframes = (m == NCORE) ? GN_FRAMES : LN_FRAMES;
+ for (n = 0; n < nframes; n++)
+ { m_workq[m][n].m_vsize = 0;
+ m_workq[m][n].m_boq = 0;
+ } } }
+
+ if (must_exit)
+ { rm_shared_segments();
+ fprintf(stderr, "pan: check './pan --' for usage details\n");
+ pan_exit(1); /* calls cleanup_shm */
+ }
+}
+
+static uchar *
+prep_shmid_S(size_t n) /* either sets SS or H_tab, linux/cygwin */
+{ char *rval;
+#ifndef SEP_STATE
+ key_t key;
+
+ if (verbose && core_id == 0)
+ {
+ #ifdef BITSTATE
+ printf("cpu0: step 1: allocate shared bitstate %g Mb\n",
+ (double) n / (1048576.));
+ #else
+ printf("cpu0: step 1: allocate shared hastable %g Mb\n",
+ (double) n / (1048576.));
+ #endif
+ }
+ #ifdef MEMLIM
+ if (memcnt + (double) n > memlim)
+ { printf("cpu0: S %8g + %d Kb exceeds memory limit of %8g Mb\n",
+ memcnt/1024., n/1024, memlim/(1048576.));
+ printf("cpu0: insufficient memory -- aborting\n");
+ exit(1);
+ }
+ #endif
+
+ key = ftok(PanSource, NCORE+2); /* different from queues */
+ if (key == -1)
+ { perror("ftok shared bitstate or hashtable");
+ fprintf(stderr, "pan: check './pan --' for usage details\n");
+ pan_exit(1);
+ }
+
+ if (core_id == 0) /* root */
+ { shmid_S = shmget(key, n, 0600);
+ if (shmid_S != -1)
+ { printf("cpu0: removing stale segment, status: %d\n",
+ shmctl(shmid_S, IPC_RMID, NULL));
+ }
+ shmid_S = shmget(key, n, 0600 | IPC_CREAT | IPC_EXCL);
+ memcnt += (double) n;
+ } else /* worker */
+ { shmid_S = shmget(key, n, 0600);
+ }
+ if (shmid_S == -1)
+ { perror("shmget shared bitstate or hashtable too large?");
+ fprintf(stderr, "pan: check './pan --' for usage details\n");
+ pan_exit(1);
+ }
+
+ rval = (char *) shmat(shmid_S, (void *) 0, 0); /* attach */
+ if ((char *) rval == (char *) -1)
+ { perror("shmat shared bitstate or hashtable");
+ fprintf(stderr, "pan: check './pan --' for usage details\n");
+ pan_exit(1);
+ }
+#else
+ rval = (char *) emalloc(n);
+#endif
+ return (uchar *) rval;
+}
+
+#define TRY_AGAIN 1
+#define NOT_AGAIN 0
+
+static char shm_prep_result;
+
+static uchar *
+prep_state_mem(size_t n) /* sets memory arena for states linux/cygwin */
+{ char *rval;
+ key_t key;
+ static int cnt = 3; /* start larger than earlier ftok calls */
+
+ shm_prep_result = NOT_AGAIN; /* default */
+ if (verbose && core_id == 0)
+ { printf("cpu0: step 2+: pre-allocate memory arena %d of %6.2g Mb\n",
+ cnt-3, (double) n / (1048576.));
+ }
+ #ifdef MEMLIM
+ if (memcnt + (double) n > memlim)
+ { printf("cpu0: error: M %.0f + %.0f Kb exceeds memory limit of %.0f Mb\n",
+ memcnt/1024.0, (double) n/1024.0, memlim/(1048576.));
+ return NULL;
+ }
+ #endif
+
+ key = ftok(PanSource, NCORE+cnt); cnt++;
+ if (key == -1)
+ { perror("ftok T");
+ printf("pan: check './pan --' for usage details\n");
+ pan_exit(1);
+ }
+
+ if (core_id == 0)
+ { shmid_M = shmget(key, n, 0600);
+ if (shmid_M != -1)
+ { printf("cpu0: removing stale memory segment %d, status: %d\n",
+ cnt-3, shmctl(shmid_M, IPC_RMID, NULL));
+ }
+ shmid_M = shmget(key, n, 0600 | IPC_CREAT | IPC_EXCL);
+ /* memcnt += (double) n; -- only amount actually used is counted */
+ } else
+ { shmid_M = shmget(key, n, 0600);
+
+ }
+ if (shmid_M == -1)
+ { if (verbose)
+ { printf("error: failed to get pool of shared memory %d of %.0f Mb\n",
+ cnt-3, ((double)n)/(1048576.));
+ perror("state mem");
+ printf("pan: check './pan --' for usage details\n");
+ }
+ shm_prep_result = TRY_AGAIN;
+ return NULL;
+ }
+ rval = (char *) shmat(shmid_M, (void *) 0, 0); /* attach */
+
+ if ((char *) rval == (char *) -1)
+ { printf("cpu%d error: failed to attach pool of shared memory %d of %.0f Mb\n",
+ core_id, cnt-3, ((double)n)/(1048576.));
+ perror("state mem");
+ return NULL;
+ }
+ return (uchar *) rval;
+}
+
+void
+init_HT(unsigned long n) /* cygwin/linux version */
+{ volatile char *x;
+ double get_mem;
+#ifndef SEP_STATE
+ volatile char *dc_mem_start;
+ double need_mem, got_mem = 0.;
+#endif
+
+#ifdef SEP_STATE
+ #ifndef MEMLIM
+ if (verbose)
+ { printf("cpu0: steps 0,1: no -DMEMLIM set\n");
+ }
+ #else
+ if (verbose)
+ { printf("cpu0: steps 0,1: -DMEMLIM=%d Mb - (hashtable %g Mb + workqueues %g Mb)\n",
+ MEMLIM, ((double)n/(1048576.)), (((double) NCORE * LWQ_SIZE) + GWQ_SIZE) /(1048576.) );
+ }
+ #endif
+ get_mem = NCORE * sizeof(double) + (1 + CS_NR) * sizeof(void *) + 4*sizeof(void *) + 2*sizeof(double);
+ /* NCORE * is_alive + search_terminated + CS_NR * sh_lock + 6 gr vars */
+ get_mem += 4 * NCORE * sizeof(void *); /* prfree, prfull, prcnt, prmax */
+ #ifdef FULL_TRAIL
+ get_mem += (NCORE) * sizeof(Stack_Tree *); /* NCORE * stack_last */
+ #endif
+ x = (volatile char *) prep_state_mem((size_t) get_mem); /* work queues and basic structs */
+ shmid_X = (long) x;
+ if (x == NULL)
+ { printf("cpu0: could not allocate shared memory, see ./pan --\n");
+ exit(1);
+ }
+ search_terminated = (volatile unsigned int *) x; /* comes first */
+ x += sizeof(void *); /* maintain alignment */
+
+ is_alive = (volatile double *) x;
+ x += NCORE * sizeof(double);
+
+ sh_lock = (volatile int *) x;
+ x += CS_NR * sizeof(void *);
+
+ grfree = (volatile int *) x;
+ x += sizeof(void *);
+ grfull = (volatile int *) x;
+ x += sizeof(void *);
+ grcnt = (volatile int *) x;
+ x += sizeof(void *);
+ grmax = (volatile int *) x;
+ x += sizeof(void *);
+ prfree = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prfull = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prcnt = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prmax = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ gr_readmiss = (volatile double *) x;
+ x += sizeof(double);
+ gr_writemiss = (volatile double *) x;
+ x += sizeof(double);
+
+ #ifdef FULL_TRAIL
+ stack_last = (volatile Stack_Tree **) x;
+ x += NCORE * sizeof(Stack_Tree *);
+ #endif
+
+ #ifndef BITSTATE
+ H_tab = (struct H_el **) emalloc(n);
+ #endif
+#else
+ #ifndef MEMLIM
+ #warning MEMLIM not set
+ #define MEMLIM (2048)
+ #endif
+
+ if (core_id == 0 && verbose)
+ { printf("cpu0: step 0: -DMEMLIM=%d Mb minus hashtable+workqs (%g + %g Mb) leaves %g Mb\n",
+ MEMLIM, ((double)n/(1048576.)), (NCORE * LWQ_SIZE + GWQ_SIZE)/(1048576.),
+ (memlim - memcnt - (double) n - (NCORE * LWQ_SIZE + GWQ_SIZE))/(1048576.));
+ }
+ #ifndef BITSTATE
+ H_tab = (struct H_el **) prep_shmid_S((size_t) n); /* hash_table */
+ #endif
+ need_mem = memlim - memcnt - ((double) NCORE * LWQ_SIZE) - GWQ_SIZE;
+ if (need_mem <= 0.)
+ { Uerror("internal error -- shared state memory");
+ }
+
+ if (core_id == 0 && verbose)
+ { printf("cpu0: step 2: pre-allocate shared state memory %g Mb\n",
+ need_mem/(1048576.));
+ }
+#ifdef SEP_HEAP
+ SEG_SIZE = need_mem / NCORE;
+ if (verbose && core_id == 0)
+ { printf("cpu0: setting segsize to %6g MB\n",
+ SEG_SIZE/(1048576.));
+ }
+ #if defined(CYGWIN) || defined(__CYGWIN__)
+ if (SEG_SIZE > 512.*1024.*1024.)
+ { printf("warning: reducing SEG_SIZE of %g MB to 512MB (exceeds max for Cygwin)\n",
+ SEG_SIZE/(1024.*1024.));
+ SEG_SIZE = 512.*1024.*1024.;
+ }
+ #endif
+#endif
+ mem_reserved = need_mem;
+ while (need_mem > 1024.)
+ { get_mem = need_mem;
+shm_more:
+ if (get_mem > (double) SEG_SIZE)
+ { get_mem = (double) SEG_SIZE;
+ }
+ if (get_mem <= 0.0) break;
+
+ /* for allocating states: */
+ x = dc_mem_start = (volatile char *) prep_state_mem((size_t) get_mem);
+ if (x == NULL)
+ { if (shm_prep_result == NOT_AGAIN
+ || first_pool != NULL
+ || SEG_SIZE < (16. * 1048576.))
+ { break;
+ }
+ SEG_SIZE /= 2.;
+ if (verbose)
+ { printf("pan: lowered segsize to 0.000000\n", SEG_SIZE);
+ }
+ if (SEG_SIZE >= 1024.)
+ { goto shm_more;
+ }
+ break;
+ }
+
+ need_mem -= get_mem;
+ got_mem += get_mem;
+ if (first_pool == NULL)
+ { search_terminated = (volatile unsigned int *) x; /* comes first */
+ x += sizeof(void *); /* maintain alignment */
+
+ is_alive = (volatile double *) x;
+ x += NCORE * sizeof(double);
+
+ sh_lock = (volatile int *) x;
+ x += CS_NR * sizeof(void *);
+
+ grfree = (volatile int *) x;
+ x += sizeof(void *);
+ grfull = (volatile int *) x;
+ x += sizeof(void *);
+ grcnt = (volatile int *) x;
+ x += sizeof(void *);
+ grmax = (volatile int *) x;
+ x += sizeof(void *);
+ prfree = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prfull = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prcnt = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prmax = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ gr_readmiss = (volatile double *) x;
+ x += sizeof(double);
+ gr_writemiss = (volatile double *) x;
+ x += sizeof(double);
+ #ifdef FULL_TRAIL
+ stack_last = (volatile Stack_Tree **) x;
+ x += NCORE * sizeof(Stack_Tree *);
+ #endif
+ if (((long)x)&(sizeof(void *)-1)) /* 64-bit word alignment */
+ { x += sizeof(void *)-(((long)x)&(sizeof(void *)-1));
+ }
+
+ #ifdef COLLAPSE
+ ncomps = (unsigned long *) x;
+ x += (256+2) * sizeof(unsigned long);
+ #endif
+ }
+
+ dc_shared = (sh_Allocater *) x; /* must be in shared memory */
+ x += sizeof(sh_Allocater);
+
+ if (core_id == 0) /* root only */
+ { dc_shared->dc_id = shmid_M;
+ dc_shared->dc_start = dc_mem_start;
+ dc_shared->dc_arena = x;
+ dc_shared->pattern = 1234567; /* protection */
+ dc_shared->dc_size = (long) get_mem - (long) (x - dc_mem_start);
+ dc_shared->nxt = (long) 0;
+
+ if (last_pool == NULL)
+ { first_pool = last_pool = dc_shared;
+ } else
+ { last_pool->nxt = dc_shared;
+ last_pool = dc_shared;
+ }
+ } else if (first_pool == NULL)
+ { first_pool = dc_shared;
+ } }
+
+ if (need_mem > 1024.)
+ { printf("cpu0: could allocate only %g Mb of shared memory (wanted %g more)\n",
+ got_mem/(1048576.), need_mem/(1048576.));
+ }
+
+ if (!first_pool)
+ { printf("cpu0: insufficient memory -- aborting.\n");
+ exit(1);
+ }
+ /* we are still single-threaded at this point, with core_id 0 */
+ dc_shared = first_pool;
+
+#endif
+}
+
+ /* Test and Set assembly code */
+
+ #if defined(i386) || defined(__i386__) || defined(__x86_64__)
+ int
+ tas(volatile int *s) /* tested */
+ { int r;
+ __asm__ __volatile__(
+ "xchgl %0, %1 \n\t"
+ : "=r"(r), "=m"(*s)
+ : "0"(1), "m"(*s)
+ : "memory");
+
+ return r;
+ }
+ #elif defined(__arm__)
+ int
+ tas(volatile int *s) /* not tested */
+ { int r = 1;
+ __asm__ __volatile__(
+ "swpb %0, %0, [%3] \n"
+ : "=r"(r), "=m"(*s)
+ : "0"(r), "r"(s));
+
+ return r;
+ }
+ #elif defined(sparc) || defined(__sparc__)
+ int
+ tas(volatile int *s) /* not tested */
+ { int r = 1;
+ __asm__ __volatile__(
+ " ldstub [%2], %0 \n"
+ : "=r"(r), "=m"(*s)
+ : "r"(s));
+
+ return r;
+ }
+ #elif defined(ia64) || defined(__ia64__)
+ /* Intel Itanium */
+ int
+ tas(volatile int *s) /* tested */
+ { long int r;
+ __asm__ __volatile__(
+ " xchg4 %0=%1,%2 \n"
+ : "=r"(r), "+m"(*s)
+ : "r"(1)
+ : "memory");
+ return (int) r;
+ }
+ #else
+ #error missing definition of test and set operation for this platform
+ #endif
+
+void
+cleanup_shm(int val)
+{ volatile sh_Allocater *nxt_pool;
+ unsigned long cnt = 0;
+ int m;
+
+ if (nibis != 0)
+ { printf("cpu%d: Redundant call to cleanup_shm(%d)\n", core_id, val);
+ return;
+ } else
+ { nibis = 1;
+ }
+ if (search_terminated != NULL)
+ { *search_terminated |= 16; /* cleanup_shm */
+ }
+
+ for (m = 0; m < NR_QS; m++)
+ { if (shmdt((void *) shared_mem[m]) > 0)
+ { perror("shmdt detaching from shared queues");
+ } }
+
+#ifdef SEP_STATE
+ if (shmdt((void *) shmid_X) != 0)
+ { perror("shmdt detaching from shared state memory");
+ }
+#else
+ #ifdef BITSTATE
+ if (SS > 0 && shmdt((void *) SS) != 0)
+ { if (verbose)
+ { perror("shmdt detaching from shared bitstate arena");
+ } }
+ #else
+ if (core_id == 0)
+ { /* before detaching: */
+ for (nxt_pool = dc_shared; nxt_pool != NULL; nxt_pool = nxt_pool->nxt)
+ { cnt += nxt_pool->dc_size;
+ }
+ if (verbose)
+ { printf("cpu0: done, %ld Mb of shared state memory left\n",
+ cnt / (long)(1048576));
+ } }
+
+ if (shmdt((void *) H_tab) != 0)
+ { perror("shmdt detaching from shared hashtable");
+ }
+
+ for (last_pool = first_pool; last_pool != NULL; last_pool = nxt_pool)
+ { nxt_pool = last_pool->nxt;
+ if (shmdt((void *) last_pool->dc_start) != 0)
+ { perror("shmdt detaching from shared state memory");
+ } }
+ first_pool = last_pool = NULL; /* precaution */
+ #endif
+#endif
+ /* detached from shared memory - so cannot use cpu_printf */
+ if (verbose)
+ { printf("cpu%d: done -- got %d states from queue\n",
+ core_id, nstates_get);
+ }
+}
+
+extern void give_up(int);
+extern void Read_Queue(int);
+
+void
+mem_get(void)
+{ SM_frame *f;
+ int is_parent;
+
+#if defined(MA) && !defined(SEP_STATE)
+ #error MA without SEP_STATE is not supported with multi-core
+#endif
+#ifdef BFS
+ #error BFS is not supported with multi-core
+#endif
+#ifdef SC
+ #error SC is not supported with multi-core
+#endif
+ init_shm(); /* we are single threaded when this starts */
+
+ if (core_id == 0 && verbose)
+ { printf("cpu0: step 4: calling fork()\n");
+ }
+ fflush(stdout);
+
+/* if NCORE > 1 the child or the parent should fork N-1 more times
+ * the parent is the only process with core_id == 0 and is_parent > 0
+ * the workers have is_parent = 0 and core_id = 1..NCORE-1
+ */
+ if (core_id == 0)
+ { worker_pids[0] = getpid(); /* for completeness */
+ while (++core_id < NCORE) /* first worker sees core_id = 1 */
+ { is_parent = fork();
+ if (is_parent == -1)
+ { Uerror("fork failed");
+ }
+ if (is_parent == 0) /* this is a worker process */
+ { if (proxy_pid == core_id) /* always non-zero */
+ { start_proxy("-r", 0); /* no return */
+ }
+ goto adapt; /* root process continues spawning */
+ }
+ worker_pids[core_id] = is_parent;
+ }
+ /* note that core_id is now NCORE */
+ if (proxy_pid > 0 && proxy_pid < NCORE)
+ { proxy_pid_snd = fork();
+ if (proxy_pid_snd == -1)
+ { Uerror("proxy fork failed");
+ }
+ if (proxy_pid_snd == 0)
+ { start_proxy("-s", worker_pids[proxy_pid]); /* no return */
+ } } /* else continue */
+ if (is_parent > 0)
+ { core_id = 0; /* reset core_id for root process */
+ }
+ } else /* worker */
+ { static char db0[16]; /* good for up to 10^6 cores */
+ static char db1[16];
+adapt: tprefix = db0; sprefix = db1;
+ sprintf(tprefix, "cpu%d_trail", core_id);
+ sprintf(sprefix, "cpu%d_rst", core_id);
+ memcnt = 0; /* count only additionally allocated memory */
+ }
+ signal(SIGINT, give_up);
+
+ if (proxy_pid == 0) /* not in a cluster setup, pan_proxy must attach */
+ { rm_shared_segments(); /* mark all shared segments for removal on exit */
+ }
+ if (verbose)
+ { cpu_printf("starting core_id %d -- pid %d\n", core_id, getpid());
+ }
+#if defined(SEP_HEAP) && !defined(SEP_STATE)
+ { int i;
+ volatile sh_Allocater *ptr;
+ ptr = first_pool;
+ for (i = 0; i < NCORE && ptr != NULL; i++)
+ { if (i == core_id)
+ { my_heap = (char *) ptr->dc_arena;
+ my_size = (long) ptr->dc_size;
+ if (verbose)
+ cpu_printf("local heap %ld MB\n", my_size/(1048576));
+ break;
+ }
+ ptr = ptr->nxt; /* local */
+ }
+ if (my_heap == NULL)
+ { printf("cpu%d: no local heap\n", core_id);
+ pan_exit(1);
+ } /* else */
+ #if defined(CYGWIN) || defined(__CYGWIN__)
+ ptr = first_pool;
+ for (i = 0; i < NCORE && ptr != NULL; i++)
+ { ptr = ptr->nxt; /* local */
+ }
+ dc_shared = ptr; /* any remainder */
+ #else
+ dc_shared = NULL; /* used all mem for local heaps */
+ #endif
+ }
+#endif
+ if (core_id == 0 && !remote_party)
+ { new_state(); /* cpu0 explores root */
+ if (verbose)
+ cpu_printf("done with 1st dfs, nstates %g (put %d states), read q\n",
+ nstates, nstates_put);
+ dfs_phase2 = 1;
+ }
+ Read_Queue(core_id); /* all cores */
+
+ if (verbose)
+ { cpu_printf("put %6d states into queue -- got %6d\n",
+ nstates_put, nstates_get);
+ }
+ if (proxy_pid != 0)
+ { rm_shared_segments();
+ }
+ done = 1;
+ wrapup();
+ exit(0);
+}
+
+#else
+int unpack_state(SM_frame *, int);
+#endif
+
+struct H_el *
+grab_shared(int n)
+{
+#ifndef SEP_STATE
+ char *rval = (char *) 0;
+
+ if (n == 0)
+ { printf("cpu%d: grab shared zero\n", core_id); fflush(stdout);
+ return (struct H_el *) rval;
+ } else if (n&(sizeof(void *)-1))
+ { n += sizeof(void *)-(n&(sizeof(void *)-1)); /* alignment */
+ }
+
+#ifdef SEP_HEAP
+ /* no locking */
+ if (my_heap != NULL && my_size > n)
+ { rval = my_heap;
+ my_heap += n;
+ my_size -= n;
+ goto done;
+ }
+#endif
+
+ if (!dc_shared)
+ { sudden_stop("pan: out of memory");
+ }
+
+ /* another lock is always already in effect when this is called */
+ /* but not always the same lock -- i.e., on different parts of the hashtable */
+ enter_critical(GLOBAL_LOCK); /* this must be independently mutex */
+#if defined(SEP_HEAP) && !defined(WIN32) && !defined(WIN64)
+ { static int noted = 0;
+ if (!noted)
+ { noted = 1;
+ printf("cpu%d: global heap has %ld bytes left, needed %d\n",
+ core_id, dc_shared?dc_shared->dc_size:0, n);
+ } }
+#endif
+#if 0
+ if (dc_shared->pattern != 1234567)
+ { leave_critical(GLOBAL_LOCK);
+ Uerror("overrun -- memory corruption");
+ }
+#endif
+ if (dc_shared->dc_size < n)
+ { if (verbose)
+ { printf("Next Pool %g Mb + %d\n", memcnt/(1048576.), n);
+ }
+ if (dc_shared->nxt == NULL
+ || dc_shared->nxt->dc_arena == NULL
+ || dc_shared->nxt->dc_size < n)
+ { printf("cpu%d: memcnt %g Mb + wanted %d bytes more\n",
+ core_id, memcnt / (1048576.), n);
+ leave_critical(GLOBAL_LOCK);
+ sudden_stop("out of memory -- aborting");
+ wrapup(); /* exits */
+ } else
+ { dc_shared = (sh_Allocater *) dc_shared->nxt;
+ } }
+
+ rval = (char *) dc_shared->dc_arena;
+ dc_shared->dc_arena += n;
+ dc_shared->dc_size -= (long) n;
+#if 0
+ if (VVERBOSE)
+ printf("cpu%d grab shared (%d bytes) -- %ld left\n",
+ core_id, n, dc_shared->dc_size);
+#endif
+ leave_critical(GLOBAL_LOCK);
+done:
+ memset(rval, 0, n);
+ memcnt += (double) n;
+
+ return (struct H_el *) rval;
+#else
+ return (struct H_el *) emalloc(n);
+#endif
+}
+
+SM_frame *
+Get_Full_Frame(int n)
+{ SM_frame *f;
+ double cnt_start = frame_wait;
+
+ f = &m_workq[n][prfull[n]];
+ while (f->m_vsize == 0) /* await full slot LOCK : full frame */
+ { iam_alive();
+#ifndef NGQ
+ #ifndef SAFETY
+ if (!a_cycles || core_id != 0)
+ #endif
+ if (*grcnt > 0) /* accessed outside lock, but safe even if wrong */
+ { enter_critical(GQ_RD); /* gq - read access */
+ if (*grcnt > 0) /* could have changed */
+ { f = &m_workq[NCORE][*grfull]; /* global q */
+ if (f->m_vsize == 0)
+ { /* writer is still filling the slot */
+ *gr_writemiss++;
+ f = &m_workq[n][prfull[n]]; /* reset */
+ } else
+ { *grfull = (*grfull+1) % (GN_FRAMES);
+ enter_critical(GQ_WR);
+ *grcnt = *grcnt - 1;
+ leave_critical(GQ_WR);
+ leave_critical(GQ_RD);
+ return f;
+ } }
+ leave_critical(GQ_RD);
+ }
+#endif
+ if (frame_wait++ - cnt_start > Delay)
+ { if (0)
+ { cpu_printf("timeout on q%d -- %u -- query %d\n",
+ n, f, query_in_progress);
+ }
+ return (SM_frame *) 0; /* timeout */
+ } }
+ iam_alive();
+ if (VVERBOSE) cpu_printf("got frame from q%d\n", n);
+ prfull[n] = (prfull[n] + 1) % (LN_FRAMES);
+ enter_critical(QLOCK(n));
+ prcnt[n]--; /* lock out increments */
+ leave_critical(QLOCK(n));
+ return f;
+}
+
+SM_frame *
+Get_Free_Frame(int n)
+{ SM_frame *f;
+ double cnt_start = free_wait;
+
+ if (VVERBOSE) { cpu_printf("get free frame from q%d\n", n); }
+
+ if (n == NCORE) /* global q */
+ { f = &(m_workq[n][lrfree]);
+ } else
+ { f = &(m_workq[n][prfree[n]]);
+ }
+ while (f->m_vsize != 0) /* await free slot LOCK : free slot */
+ { iam_alive();
+ if (free_wait++ - cnt_start > OneSecond)
+ { if (verbose)
+ { cpu_printf("timeout waiting for free slot q%d\n", n);
+ }
+ cnt_start = free_wait;
+ if (someone_crashed(1))
+ { printf("cpu%d: search terminated\n", core_id);
+ sudden_stop("get free frame");
+ pan_exit(1);
+ } } }
+ if (n != NCORE)
+ { prfree[n] = (prfree[n] + 1) % (LN_FRAMES);
+ enter_critical(QLOCK(n));
+ prcnt[n]++; /* lock out decrements */
+ if (prmax[n] < prcnt[n])
+ { prmax[n] = prcnt[n];
+ }
+ leave_critical(QLOCK(n));
+ }
+ return f;
+}
+#ifndef NGQ
+int
+GlobalQ_HasRoom(void)
+{ int rval = 0;
+
+ gq_tries++;
+ if (*grcnt < GN_FRAMES) /* there seems to be room */
+ { enter_critical(GQ_WR); /* gq write access */
+ if (*grcnt < GN_FRAMES)
+ { if (m_workq[NCORE][*grfree].m_vsize != 0)
+ { /* can happen if reader is slow emptying slot */
+ *gr_readmiss++;
+ goto out; /* dont wait: release lock and return */
+ }
+ lrfree = *grfree; /* Get_Free_Frame use lrfree in this mode */
+ *grfree = (*grfree + 1) % GN_FRAMES;
+ *grcnt = *grcnt + 1; /* count nr of slots filled -- no additional lock needed */
+ if (*grmax < *grcnt) *grmax = *grcnt;
+ leave_critical(GQ_WR); /* for short lock duration */
+ gq_hasroom++;
+ mem_put(NCORE); /* copy state into reserved slot */
+ rval = 1; /* successfull handoff */
+ } else
+ { gq_hasnoroom++;
+out: leave_critical(GQ_WR);
+ } }
+ return rval;
+}
+#endif
+
+int
+unpack_state(SM_frame *f, int from_q)
+{ int i, j;
+ static struct H_el D_State;
+
+ if (f->m_vsize > 0)
+ { boq = f->m_boq;
+ if (boq > 256)
+ { cpu_printf("saw control %d, expected state\n", boq);
+ return 0;
+ }
+ vsize = f->m_vsize;
+correct:
+ memcpy((uchar *) &now, (uchar *) f->m_now, vsize);
+ for (i = j = 0; i < VMAX; i++, j = (j+1)%8)
+ { Mask[i] = (f->m_Mask[i/8] & (1<<j)) ? 1 : 0;
+ }
+ if (now._nr_pr > 0)
+ { memcpy((uchar *) proc_offset, (uchar *) f->m_p_offset, now._nr_pr * sizeof(OFFT));
+ memcpy((uchar *) proc_skip, (uchar *) f->m_p_skip, now._nr_pr * sizeof(uchar));
+ }
+ if (now._nr_qs > 0)
+ { memcpy((uchar *) q_offset, (uchar *) f->m_q_offset, now._nr_qs * sizeof(OFFT));
+ memcpy((uchar *) q_skip, (uchar *) f->m_q_skip, now._nr_qs * sizeof(uchar));
+ }
+#ifndef NOVSZ
+ if (vsize != now._vsz)
+ { cpu_printf("vsize %d != now._vsz %d (type %d) %d\n",
+ vsize, now._vsz, f->m_boq, f->m_vsize);
+ vsize = now._vsz;
+ goto correct; /* rare event: a race */
+ }
+#endif
+ hmax = max(hmax, vsize);
+
+ if (f != &cur_Root)
+ { memcpy((uchar *) &cur_Root, (uchar *) f, sizeof(SM_frame));
+ }
+
+ if (((now._a_t) & 1) == 1) /* i.e., when starting nested DFS */
+ { A_depth = depthfound = 0;
+ memcpy((uchar *)&A_Root, (uchar *)&now, vsize);
+ }
+ nr_handoffs = f->nr_handoffs;
+ } else
+ { cpu_printf("pan: state empty\n");
+ }
+
+ depth = 0;
+ trpt = &trail[1];
+ trpt->tau = f->m_tau;
+ trpt->o_pm = f->m_o_pm;
+
+ (trpt-1)->ostate = &D_State; /* stub */
+ trpt->ostate = &D_State;
+
+#ifdef FULL_TRAIL
+ if (upto > 0)
+ { stack_last[core_id] = (Stack_Tree *) f->m_stack;
+ }
+ #if defined(VERBOSE)
+ if (stack_last[core_id])
+ { cpu_printf("%d: UNPACK -- SET m_stack %u (%d,%d)\n",
+ depth, stack_last[core_id], stack_last[core_id]->pr,
+ stack_last[core_id]->t_id);
+ }
+ #endif
+#endif
+
+ if (!trpt->o_t)
+ { static Trans D_Trans;
+ trpt->o_t = &D_Trans;
+ }
+
+ #ifdef VERI
+ if ((trpt->tau & 4) != 4)
+ { trpt->tau |= 4; /* the claim moves first */
+ cpu_printf("warning: trpt was not up to date\n");
+ }
+ #endif
+
+ for (i = 0; i < (int) now._nr_pr; i++)
+ { P0 *ptr = (P0 *) pptr(i);
+ #ifndef NP
+ if (accpstate[ptr->_t][ptr->_p])
+ { trpt->o_pm |= 2;
+ }
+ #else
+ if (progstate[ptr->_t][ptr->_p])
+ { trpt->o_pm |= 4;
+ }
+ #endif
+ }
+
+ #ifdef EVENT_TRACE
+ #ifndef NP
+ if (accpstate[EVENT_TRACE][now._event])
+ { trpt->o_pm |= 2;
+ }
+ #else
+ if (progstate[EVENT_TRACE][now._event])
+ { trpt->o_pm |= 4;
+ }
+ #endif
+ #endif
+
+ #if defined(C_States) && (HAS_TRACK==1)
+ /* restore state of tracked C objects */
+ c_revert((uchar *) &(now.c_state[0]));
+ #if (HAS_STACK==1)
+ c_unstack((uchar *) f->m_c_stack); /* unmatched tracked data */
+ #endif
+ #endif
+ return 1;
+}
+
+void
+write_root(void) /* for trail file */
+{ int fd;
+
+ if (iterative == 0 && Nr_Trails > 1)
+ sprintf(fnm, "%s%d.%s", TrailFile, Nr_Trails-1, sprefix);
+ else
+ sprintf(fnm, "%s.%s", TrailFile, sprefix);
+
+ if (cur_Root.m_vsize == 0)
+ { (void) unlink(fnm); /* remove possible old copy */
+ return; /* its the default initial state */
+ }
+
+ if ((fd = creat(fnm, TMODE)) < 0)
+ { char *q;
+ if ((q = strchr(TrailFile, '.')))
+ { *q = '\0'; /* strip .pml */
+ if (iterative == 0 && Nr_Trails-1 > 0)
+ sprintf(fnm, "%s%d.%s", TrailFile, Nr_Trails-1, sprefix);
+ else
+ sprintf(fnm, "%s.%s", TrailFile, sprefix);
+ *q = '.';
+ fd = creat(fnm, TMODE);
+ }
+ if (fd < 0)
+ { cpu_printf("pan: cannot create %s\n", fnm);
+ perror("cause");
+ return;
+ } }
+
+ if (write(fd, &cur_Root, sizeof(SM_frame)) != sizeof(SM_frame))
+ { cpu_printf("pan: error writing %s\n", fnm);
+ } else
+ { cpu_printf("pan: wrote %s\n", fnm);
+ }
+ close(fd);
+}
+
+void
+set_root(void)
+{ int fd;
+ char *q;
+ char MyFile[512];
+ char MySuffix[16];
+ char *ssuffix = "rst";
+ int try_core = 1;
+
+ strcpy(MyFile, TrailFile);
+try_again:
+ if (whichtrail > 0)
+ { sprintf(fnm, "%s%d.%s", MyFile, whichtrail, ssuffix);
+ fd = open(fnm, O_RDONLY, 0);
+ if (fd < 0 && (q = strchr(MyFile, '.')))
+ { *q = '\0'; /* strip .pml */
+ sprintf(fnm, "%s%d.%s", MyFile, whichtrail, ssuffix);
+ *q = '.';
+ fd = open(fnm, O_RDONLY, 0);
+ }
+ } else
+ { sprintf(fnm, "%s.%s", MyFile, ssuffix);
+ fd = open(fnm, O_RDONLY, 0);
+ if (fd < 0 && (q = strchr(MyFile, '.')))
+ { *q = '\0'; /* strip .pml */
+ sprintf(fnm, "%s.%s", MyFile, ssuffix);
+ *q = '.';
+ fd = open(fnm, O_RDONLY, 0);
+ } }
+
+ if (fd < 0)
+ { if (try_core < NCORE)
+ { ssuffix = MySuffix;
+ sprintf(ssuffix, "cpu%d_rst", try_core++);
+ goto try_again;
+ }
+ cpu_printf("no file '%s.rst' or '%s' (not an error)\n", MyFile, fnm);
+ } else
+ { if (read(fd, &cur_Root, sizeof(SM_frame)) != sizeof(SM_frame))
+ { cpu_printf("read error %s\n", fnm);
+ close(fd);
+ pan_exit(1);
+ }
+ close(fd);
+ (void) unpack_state(&cur_Root, -2);
+#ifdef SEP_STATE
+ cpu_printf("partial trail -- last few steps only\n");
+#endif
+ cpu_printf("restored root from '%s'\n", fnm);
+ printf("=====State:=====\n");
+ { int i, j; P0 *z;
+ for (i = 0; i < now._nr_pr; i++)
+ { z = (P0 *)pptr(i);
+ printf("proc %2d (%s) ", i, procname[z->_t]);
+ for (j = 0; src_all[j].src; j++)
+ if (src_all[j].tp == (int) z->_t)
+ { printf(" line %3d \"%s\" ",
+ src_all[j].src[z->_p], PanSource);
+ break;
+ }
+ printf("(state %d)\n", z->_p);
+ c_locals(i, z->_t);
+ }
+ c_globals();
+ }
+ printf("================\n");
+ }
+}
+
+#ifdef USE_DISK
+unsigned long dsk_written, dsk_drained;
+void mem_drain(void);
+#endif
+
+void
+m_clear_frame(SM_frame *f)
+{ int i, clr_sz = sizeof(SM_results);
+
+ for (i = 0; i <= _NP_; i++) /* all proctypes */
+ { clr_sz += NrStates[i]*sizeof(uchar);
+ }
+ memset(f, 0, clr_sz);
+ /* caution if sizeof(SM_results) > sizeof(SM_frame) */
+}
+
+#define TargetQ_Full(n) (m_workq[n][prfree[n]].m_vsize != 0)
+#define TargetQ_NotFull(n) (m_workq[n][prfree[n]].m_vsize == 0)
+
+int
+AllQueuesEmpty(void)
+{ int q;
+#ifndef NGQ
+ if (*grcnt != 0)
+ { return 0;
+ }
+#endif
+ for (q = 0; q < NCORE; q++)
+ { if (prcnt[q] != 0)
+ { return 0;
+ } }
+ return 1;
+}
+
+void
+Read_Queue(int q)
+{ SM_frame *f, *of;
+ int remember, target_q;
+ SM_results *r;
+ double patience = 0.0;
+
+ target_q = (q + 1) % NCORE;
+
+ for (;;)
+ { f = Get_Full_Frame(q);
+ if (!f) /* 1 second timeout -- and trigger for Query */
+ { if (someone_crashed(2))
+ { printf("cpu%d: search terminated [code %d]\n",
+ core_id, search_terminated?*search_terminated:-1);
+ sudden_stop("");
+ pan_exit(1);
+ }
+#ifdef TESTING
+ /* to profile with cc -pg and gprof pan.exe -- set handoff depth beyond maxdepth */
+ exit(0);
+#endif
+ remember = *grfree;
+ if (core_id == 0 /* root can initiate termination */
+ && remote_party == 0 /* and only the original root */
+ && query_in_progress == 0 /* unless its already in progress */
+ && AllQueuesEmpty())
+ { f = Get_Free_Frame(target_q);
+ query_in_progress = 1; /* only root process can do this */
+ if (!f) { Uerror("Fatal1: no free slot"); }
+ f->m_boq = QUERY; /* initiate Query */
+ if (verbose)
+ { cpu_printf("snd QUERY to q%d (%d) into slot %d\n",
+ target_q, nstates_get + 1, prfree[target_q]-1);
+ }
+ f->m_vsize = remember + 1;
+ /* number will not change unless we receive more states */
+ } else if (patience++ > OneHour) /* one hour watchdog timer */
+ { cpu_printf("timeout -- giving up\n");
+ sudden_stop("queue timeout");
+ pan_exit(1);
+ }
+ if (0) cpu_printf("timed out -- try again\n");
+ continue;
+ }
+ patience = 0.0; /* reset watchdog */
+
+ if (f->m_boq == QUERY)
+ { if (verbose)
+ { cpu_printf("got QUERY on q%d (%d <> %d) from slot %d\n",
+ q, f->m_vsize, nstates_put + 1, prfull[q]-1);
+ snapshot();
+ }
+ remember = f->m_vsize;
+ f->m_vsize = 0; /* release slot */
+
+ if (core_id == 0 && remote_party == 0) /* original root cpu0 */
+ { if (query_in_progress == 1 /* didn't send more states in the interim */
+ && *grfree + 1 == remember) /* no action on global queue meanwhile */
+ { if (verbose) cpu_printf("Termination detected\n");
+ if (TargetQ_Full(target_q))
+ { if (verbose)
+ cpu_printf("warning: target q is full\n");
+ }
+ f = Get_Free_Frame(target_q);
+ if (!f) { Uerror("Fatal2: no free slot"); }
+ m_clear_frame(f);
+ f->m_boq = QUIT; /* send final Quit, collect stats */
+ f->m_vsize = 111; /* anything non-zero will do */
+ if (verbose)
+ cpu_printf("put QUIT on q%d\n", target_q);
+ } else
+ { if (verbose) cpu_printf("Stale Query\n");
+#ifdef USE_DISK
+ mem_drain();
+#endif
+ }
+ query_in_progress = 0;
+ } else
+ { if (TargetQ_Full(target_q))
+ { if (verbose)
+ cpu_printf("warning: forward query - target q full\n");
+ }
+ f = Get_Free_Frame(target_q);
+ if (verbose)
+ cpu_printf("snd QUERY response to q%d (%d <> %d) in slot %d\n",
+ target_q, remember, *grfree + 1, prfree[target_q]-1);
+ if (!f) { Uerror("Fatal4: no free slot"); }
+
+ if (*grfree + 1 == remember) /* no action on global queue */
+ { f->m_boq = QUERY; /* forward query, to root */
+ f->m_vsize = remember;
+ } else
+ { f->m_boq = QUERY_F; /* no match -- busy */
+ f->m_vsize = 112; /* anything non-zero */
+#ifdef USE_DISK
+ if (dsk_written != dsk_drained)
+ { mem_drain();
+ }
+#endif
+ } }
+ continue;
+ }
+
+ if (f->m_boq == QUERY_F)
+ { if (verbose)
+ { cpu_printf("got QUERY_F on q%d from slot %d\n", q, prfull[q]-1);
+ }
+ f->m_vsize = 0; /* release slot */
+
+ if (core_id == 0 && remote_party == 0) /* original root cpu0 */
+ { if (verbose) cpu_printf("No Match on Query\n");
+ query_in_progress = 0;
+ } else
+ { if (TargetQ_Full(target_q))
+ { if (verbose) cpu_printf("warning: forwarding query_f, target queue full\n");
+ }
+ f = Get_Free_Frame(target_q);
+ if (verbose) cpu_printf("forward QUERY_F to q%d into slot %d\n",
+ target_q, prfree[target_q]-1);
+ if (!f) { Uerror("Fatal5: no free slot"); }
+ f->m_boq = QUERY_F; /* cannot terminate yet */
+ f->m_vsize = 113; /* anything non-zero */
+ }
+#ifdef USE_DISK
+ if (dsk_written != dsk_drained)
+ { mem_drain();
+ }
+#endif
+ continue;
+ }
+
+ if (f->m_boq == QUIT)
+ { if (0) cpu_printf("done -- local memcnt %g Mb\n", memcnt/(1048576.));
+ retrieve_info((SM_results *) f); /* collect and combine stats */
+ if (verbose)
+ { cpu_printf("received Quit\n");
+ snapshot();
+ }
+ f->m_vsize = 0; /* release incoming slot */
+ if (core_id != 0)
+ { f = Get_Free_Frame(target_q); /* new outgoing slot */
+ if (!f) { Uerror("Fatal6: no free slot"); }
+ m_clear_frame(f); /* start with zeroed stats */
+ record_info((SM_results *) f);
+ f->m_boq = QUIT; /* forward combined results */
+ f->m_vsize = 114; /* anything non-zero */
+ if (verbose>1)
+ cpu_printf("fwd Results to q%d\n", target_q);
+ }
+ break; /* successful termination */
+ }
+
+ /* else: 0<= boq <= 255, means STATE transfer */
+ if (unpack_state(f, q) != 0)
+ { nstates_get++;
+ f->m_vsize = 0; /* release slot */
+ if (VVERBOSE) cpu_printf("Got state\n");
+
+ if (search_terminated != NULL
+ && *search_terminated == 0)
+ { new_state(); /* explore successors */
+ memset((uchar *) &cur_Root, 0, sizeof(SM_frame)); /* avoid confusion */
+ } else
+ { pan_exit(0);
+ }
+ } else
+ { pan_exit(0);
+ } }
+ if (verbose) cpu_printf("done got %d put %d\n", nstates_get, nstates_put);
+ sleep_report();
+}
+
+void
+give_up(int unused_x)
+{
+ if (search_terminated != NULL)
+ { *search_terminated |= 32; /* give_up */
+ }
+ if (!writing_trail)
+ { was_interrupted = 1;
+ snapshot();
+ cpu_printf("Give Up\n");
+ sleep_report();
+ pan_exit(1);
+ } else /* we are already terminating */
+ { cpu_printf("SIGINT\n");
+ }
+}
+
+void
+check_overkill(void)
+{
+ vmax_seen = (vmax_seen + 7)/ 8;
+ vmax_seen *= 8; /* round up to a multiple of 8 */
+
+ if (core_id == 0
+ && !remote_party
+ && nstates_put > 0
+ && VMAX - vmax_seen > 8)
+ {
+#ifdef BITSTATE
+ printf("cpu0: max VMAX value seen in this run: ");
+#else
+ printf("cpu0: recommend recompiling with ");
+#endif
+ printf("-DVMAX=%d\n", vmax_seen);
+ }
+}
+
+void
+mem_put(int q) /* handoff state to other cpu, workq q */
+{ SM_frame *f;
+ int i, j;
+
+ if (vsize > VMAX)
+ { vsize = (vsize + 7)/8; vsize *= 8; /* round up */
+ printf("pan: recompile with -DVMAX=N with N >= %d\n", vsize);
+ Uerror("aborting");
+ }
+ if (now._nr_pr > PMAX)
+ { printf("pan: recompile with -DPMAX=N with N >= %d\n", now._nr_pr);
+ Uerror("aborting");
+ }
+ if (now._nr_qs > QMAX)
+ { printf("pan: recompile with -DQMAX=N with N >= %d\n", now._nr_qs);
+ Uerror("aborting");
+ }
+ if (vsize > vmax_seen) vmax_seen = vsize;
+ if (now._nr_pr > pmax_seen) pmax_seen = now._nr_pr;
+ if (now._nr_qs > qmax_seen) qmax_seen = now._nr_qs;
+
+ f = Get_Free_Frame(q); /* not called in likely deadlock states */
+ if (!f) { Uerror("Fatal3: no free slot"); }
+
+ if (VVERBOSE) cpu_printf("putting state into q%d\n", q);
+
+ memcpy((uchar *) f->m_now, (uchar *) &now, vsize);
+ memset((uchar *) f->m_Mask, 0, (VMAX+7)/8 * sizeof(char));
+ for (i = j = 0; i < VMAX; i++, j = (j+1)%8)
+ { if (Mask[i])
+ { f->m_Mask[i/8] |= (1<<j);
+ } }
+
+ if (now._nr_pr > 0)
+ { memcpy((uchar *) f->m_p_offset, (uchar *) proc_offset, now._nr_pr * sizeof(OFFT));
+ memcpy((uchar *) f->m_p_skip, (uchar *) proc_skip, now._nr_pr * sizeof(uchar));
+ }
+ if (now._nr_qs > 0)
+ { memcpy((uchar *) f->m_q_offset, (uchar *) q_offset, now._nr_qs * sizeof(OFFT));
+ memcpy((uchar *) f->m_q_skip, (uchar *) q_skip, now._nr_qs * sizeof(uchar));
+ }
+#if defined(C_States) && (HAS_TRACK==1) && (HAS_STACK==1)
+ c_stack((uchar *) f->m_c_stack); /* save unmatched tracked data */
+#endif
+#ifdef FULL_TRAIL
+ f->m_stack = stack_last[core_id];
+#endif
+ f->nr_handoffs = nr_handoffs+1;
+ f->m_tau = trpt->tau;
+ f->m_o_pm = trpt->o_pm;
+ f->m_boq = boq;
+ f->m_vsize = vsize; /* must come last - now the other cpu can see it */
+
+ if (query_in_progress == 1)
+ query_in_progress = 2; /* make sure we know, if a query makes the rounds */
+ nstates_put++;
+}
+
+#ifdef USE_DISK
+int Dsk_W_Nr, Dsk_R_Nr;
+int dsk_file = -1, dsk_read = -1;
+unsigned long dsk_written, dsk_drained;
+char dsk_name[512];
+
+#ifndef BFS_DISK
+#if defined(WIN32) || defined(WIN64)
+ #define RFLAGS (O_RDONLY|O_BINARY)
+ #define WFLAGS (O_CREAT|O_WRONLY|O_TRUNC|O_BINARY)
+#else
+ #define RFLAGS (O_RDONLY)
+ #define WFLAGS (O_CREAT|O_WRONLY|O_TRUNC)
+#endif
+#endif
+
+void
+dsk_stats(void)
+{ int i;
+
+ if (dsk_written > 0)
+ { cpu_printf("dsk_written %d states in %d files\ncpu%d: dsk_drained %6d states\n",
+ dsk_written, Dsk_W_Nr, core_id, dsk_drained);
+ close(dsk_read);
+ close(dsk_file);
+ for (i = 0; i < Dsk_W_Nr; i++)
+ { sprintf(dsk_name, "Q%.3d_%.3d.tmp", i, core_id);
+ unlink(dsk_name);
+ } }
+}
+
+void
+mem_drain(void)
+{ SM_frame *f, g;
+ int q = (core_id + 1) % NCORE; /* target q */
+ int sz;
+
+ if (dsk_read < 0
+ || dsk_written <= dsk_drained)
+ { return;
+ }
+
+ while (dsk_written > dsk_drained
+ && TargetQ_NotFull(q))
+ { f = Get_Free_Frame(q);
+ if (!f) { Uerror("Fatal: unhandled condition"); }
+
+ if ((dsk_drained+1)%MAX_DSK_FILE == 0) /* 100K states max per file */
+ { (void) close(dsk_read); /* close current read handle */
+ sprintf(dsk_name, "Q%.3d_%.3d.tmp", Dsk_R_Nr++, core_id);
+ (void) unlink(dsk_name); /* remove current file */
+ sprintf(dsk_name, "Q%.3d_%.3d.tmp", Dsk_R_Nr, core_id);
+ cpu_printf("reading %s\n", dsk_name);
+ dsk_read = open(dsk_name, RFLAGS); /* open next file */
+ if (dsk_read < 0)
+ { Uerror("could not open dsk file");
+ } }
+ if (read(dsk_read, &g, sizeof(SM_frame)) != sizeof(SM_frame))
+ { Uerror("bad dsk file read");
+ }
+ sz = g.m_vsize;
+ g.m_vsize = 0;
+ memcpy(f, &g, sizeof(SM_frame));
+ f->m_vsize = sz; /* last */
+
+ dsk_drained++;
+ }
+}
+
+void
+mem_file(void)
+{ SM_frame f;
+ int i, j, q = (core_id + 1) % NCORE; /* target q */
+
+ if (vsize > VMAX)
+ { printf("pan: recompile with -DVMAX=N with N >= %d\n", vsize);
+ Uerror("aborting");
+ }
+ if (now._nr_pr > PMAX)
+ { printf("pan: recompile with -DPMAX=N with N >= %d\n", now._nr_pr);
+ Uerror("aborting");
+ }
+ if (now._nr_qs > QMAX)
+ { printf("pan: recompile with -DQMAX=N with N >= %d\n", now._nr_qs);
+ Uerror("aborting");
+ }
+
+ if (VVERBOSE) cpu_printf("filing state for q%d\n", q);
+
+ memcpy((uchar *) f.m_now, (uchar *) &now, vsize);
+ memset((uchar *) f.m_Mask, 0, (VMAX+7)/8 * sizeof(char));
+ for (i = j = 0; i < VMAX; i++, j = (j+1)%8)
+ { if (Mask[i])
+ { f.m_Mask[i/8] |= (1<<j);
+ } }
+
+ if (now._nr_pr > 0)
+ { memcpy((uchar *)f.m_p_offset, (uchar *)proc_offset, now._nr_pr*sizeof(OFFT));
+ memcpy((uchar *)f.m_p_skip, (uchar *)proc_skip, now._nr_pr*sizeof(uchar));
+ }
+ if (now._nr_qs > 0)
+ { memcpy((uchar *) f.m_q_offset, (uchar *) q_offset, now._nr_qs*sizeof(OFFT));
+ memcpy((uchar *) f.m_q_skip, (uchar *) q_skip, now._nr_qs*sizeof(uchar));
+ }
+#if defined(C_States) && (HAS_TRACK==1) && (HAS_STACK==1)
+ c_stack((uchar *) f.m_c_stack); /* save unmatched tracked data */
+#endif
+#ifdef FULL_TRAIL
+ f.m_stack = stack_last[core_id];
+#endif
+ f.nr_handoffs = nr_handoffs+1;
+ f.m_tau = trpt->tau;
+ f.m_o_pm = trpt->o_pm;
+ f.m_boq = boq;
+ f.m_vsize = vsize;
+
+ if (query_in_progress == 1)
+ { query_in_progress = 2;
+ }
+ if (dsk_file < 0)
+ { sprintf(dsk_name, "Q%.3d_%.3d.tmp", Dsk_W_Nr, core_id);
+ dsk_file = open(dsk_name, WFLAGS, 0644);
+ dsk_read = open(dsk_name, RFLAGS);
+ if (dsk_file < 0 || dsk_read < 0)
+ { cpu_printf("File: <%s>\n", dsk_name);
+ Uerror("cannot open diskfile");
+ }
+ Dsk_W_Nr++; /* nr of next file to open */
+ cpu_printf("created temporary diskfile %s\n", dsk_name);
+ } else if ((dsk_written+1)%MAX_DSK_FILE == 0)
+ { close(dsk_file); /* close write handle */
+ sprintf(dsk_name, "Q%.3d_%.3d.tmp", Dsk_W_Nr++, core_id);
+ dsk_file = open(dsk_name, WFLAGS, 0644);
+ if (dsk_file < 0)
+ { cpu_printf("File: <%s>\n", dsk_name);
+ Uerror("aborting: cannot open new diskfile");
+ }
+ cpu_printf("created temporary diskfile %s\n", dsk_name);
+ }
+ if (write(dsk_file, &f, sizeof(SM_frame)) != sizeof(SM_frame))
+ { Uerror("aborting -- disk write failed (disk full?)");
+ }
+ nstates_put++;
+ dsk_written++;
+}
+#endif
+
+int
+mem_hand_off(void)
+{
+ if (search_terminated == NULL
+ || *search_terminated != 0) /* not a full crash check */
+ { pan_exit(0);
+ }
+ iam_alive(); /* on every transition of Down */
+#ifdef USE_DISK
+ mem_drain(); /* maybe call this also on every Up */
+#endif
+ if (depth > z_handoff /* above handoff limit */
+#ifndef SAFETY
+ && !a_cycles /* not in liveness mode */
+#endif
+#if SYNC
+ && boq == -1 /* not mid-rv */
+#endif
+#ifdef VERI
+ && (trpt->tau&4) /* claim moves first */
+ && !((trpt-1)->tau&128) /* not a stutter move */
+#endif
+ && !(trpt->tau&8)) /* not an atomic move */
+ { int q = (core_id + 1) % NCORE; /* circular handoff */
+ #ifdef GENEROUS
+ if (prcnt[q] < LN_FRAMES)
+ #else
+ if (TargetQ_NotFull(q)
+ && (dfs_phase2 == 0 || prcnt[core_id] > 0))
+ #endif
+ { mem_put(q);
+ return 1;
+ }
+ { int rval;
+ #ifndef NGQ
+ rval = GlobalQ_HasRoom();
+ #else
+ rval = 0;
+ #endif
+ #ifdef USE_DISK
+ if (rval == 0)
+ { void mem_file(void);
+ mem_file();
+ rval = 1;
+ }
+ #endif
+ return rval;
+ }
+ }
+ return 0; /* i.e., no handoff */
+}
+
+void
+mem_put_acc(void) /* liveness mode */
+{ int q = (core_id + 1) % NCORE;
+
+ if (search_terminated == NULL
+ || *search_terminated != 0)
+ { pan_exit(0);
+ }
+#ifdef USE_DISK
+ mem_drain();
+#endif
+ /* some tortured use of preprocessing: */
+#if !defined(NGQ) || defined(USE_DISK)
+ if (TargetQ_Full(q))
+ {
+#endif
+#ifndef NGQ
+ if (GlobalQ_HasRoom())
+ { return;
+ }
+#endif
+#ifdef USE_DISK
+ mem_file();
+ } else
+#else
+ #if !defined(NGQ) || defined(USE_DISK)
+ }
+ #endif
+#endif
+ { mem_put(q);
+ }
+}
+
+#if defined(WIN32) || defined(WIN64)
+void
+init_shm(void) /* initialize shared work-queues */
+{ char key[512];
+ int n, m;
+ int must_exit = 0;
+
+ if (core_id == 0 && verbose)
+ { printf("cpu0: step 3: allocate shared work-queues %g Mb\n",
+ ((double) NCORE * LWQ_SIZE + GWQ_SIZE) / (1048576.));
+ }
+ for (m = 0; m < NR_QS; m++) /* last q is global 1 */
+ { double qsize = (m == NCORE) ? GWQ_SIZE : LWQ_SIZE;
+ sprintf(key, "Global\\pan_%s_%.3d", PanSource, m);
+ if (core_id == 0)
+ { shmid[m] = CreateFileMapping(
+ INVALID_HANDLE_VALUE, /* use paging file */
+ NULL, /* default security */
+ PAGE_READWRITE, /* access permissions */
+ 0, /* high-order 4 bytes */
+ qsize, /* low-order bytes, size in bytes */
+ key); /* name */
+ } else /* worker nodes just open these segments */
+ { shmid[m] = OpenFileMapping(
+ FILE_MAP_ALL_ACCESS, /* read/write access */
+ FALSE, /* children do not inherit handle */
+ key);
+ }
+ if (shmid[m] == NULL)
+ { fprintf(stderr, "cpu%d: could not create or open shared queues\n",
+ core_id);
+ must_exit = 1;
+ break;
+ }
+ /* attach: */
+ shared_mem[m] = (char *) MapViewOfFile(shmid[m], FILE_MAP_ALL_ACCESS, 0, 0, 0);
+ if (shared_mem[m] == NULL)
+ { fprintf(stderr, "cpu%d: cannot attach shared q%d (%d Mb)\n",
+ core_id, m+1, (int) (qsize/(1048576.)));
+ must_exit = 1;
+ break;
+ }
+
+ memcnt += qsize;
+
+ m_workq[m] = (SM_frame *) shared_mem[m];
+ if (core_id == 0)
+ { int nframes = (m == NCORE) ? GN_FRAMES : LN_FRAMES;
+ for (n = 0; n < nframes; n++)
+ { m_workq[m][n].m_vsize = 0;
+ m_workq[m][n].m_boq = 0;
+ } } }
+
+ if (must_exit)
+ { fprintf(stderr, "pan: check './pan --' for usage details\n");
+ pan_exit(1); /* calls cleanup_shm */
+ }
+}
+
+static uchar *
+prep_shmid_S(size_t n) /* either sets SS or H_tab, WIN32/WIN64 */
+{ char *rval;
+#ifndef SEP_STATE
+ char key[512];
+
+ if (verbose && core_id == 0)
+ {
+ #ifdef BITSTATE
+ printf("cpu0: step 1: allocate shared bitstate %g Mb\n",
+ (double) n / (1048576.));
+ #else
+ printf("cpu0: step 1: allocate shared hastable %g Mb\n",
+ (double) n / (1048576.));
+ #endif
+ }
+ #ifdef MEMLIM
+ if (memcnt + (double) n > memlim)
+ { printf("cpu%d: S %8g + %d Kb exceeds memory limit of %8g Mb\n",
+ core_id, memcnt/1024., n/1024, memlim/(1048576.));
+ printf("cpu%d: insufficient memory -- aborting\n", core_id);
+ exit(1);
+ }
+ #endif
+
+ /* make key different from queues: */
+ sprintf(key, "Global\\pan_%s_%.3d", PanSource, NCORE+2); /* different from qs */
+
+ if (core_id == 0) /* root */
+ { shmid_S = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
+#ifdef WIN64
+ PAGE_READWRITE, (n>>32), (n & 0xffffffff), key);
+#else
+ PAGE_READWRITE, 0, n, key);
+#endif
+ memcnt += (double) n;
+ } else /* worker */
+ { shmid_S = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, key);
+ }
+ if (shmid_S == NULL)
+ {
+ #ifdef BITSTATE
+ fprintf(stderr, "cpu%d: cannot %s shared bitstate",
+ core_id, core_id?"open":"create");
+ #else
+ fprintf(stderr, "cpu%d: cannot %s shared hashtable",
+ core_id, core_id?"open":"create");
+ #endif
+ fprintf(stderr, "pan: check './pan --' for usage details\n");
+ pan_exit(1);
+ }
+
+ rval = (char *) MapViewOfFile(shmid_S, FILE_MAP_ALL_ACCESS, 0, 0, 0); /* attach */
+ if ((char *) rval == NULL)
+ { fprintf(stderr, "cpu%d: cannot attach shared bitstate or hashtable\n", core_id);
+ fprintf(stderr, "pan: check './pan --' for usage details\n");
+ pan_exit(1);
+ }
+#else
+ rval = (char *) emalloc(n);
+#endif
+ return (uchar *) rval;
+}
+
+static uchar *
+prep_state_mem(size_t n) /* WIN32/WIN64 sets memory arena for states */
+{ char *rval;
+ char key[512];
+ static int cnt = 3; /* start larger than earlier ftok calls */
+
+ if (verbose && core_id == 0)
+ { printf("cpu0: step 2+: pre-allocate memory arena %d of %g Mb\n",
+ cnt-3, (double) n / (1048576.));
+ }
+ #ifdef MEMLIM
+ if (memcnt + (double) n > memlim)
+ { printf("cpu%d: error: M %.0f + %.0f exceeds memory limit of %.0f Kb\n",
+ core_id, memcnt/1024.0, (double) n/1024.0, memlim/1024.0);
+ return NULL;
+ }
+ #endif
+
+ sprintf(key, "Global\\pan_%s_%.3d", PanSource, NCORE+cnt); cnt++;
+
+ if (core_id == 0)
+ { shmid_M = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
+#ifdef WIN64
+ PAGE_READWRITE, (n>>32), (n & 0xffffffff), key);
+#else
+ PAGE_READWRITE, 0, n, key);
+#endif
+ } else
+ { shmid_M = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, key);
+ }
+ if (shmid_M == NULL)
+ { printf("cpu%d: failed to get pool of shared memory nr %d of size %d\n",
+ core_id, cnt-3, n);
+ printf("pan: check './pan --' for usage details\n");
+ return NULL;
+ }
+ rval = (char *) MapViewOfFile(shmid_M, FILE_MAP_ALL_ACCESS, 0, 0, 0); /* attach */
+
+ if (rval == NULL)
+ { printf("cpu%d: failed to attach pool of shared memory nr %d of size %d\n",
+ core_id, cnt-3, n);
+ return NULL;
+ }
+ return (uchar *) rval;
+}
+
+void
+init_HT(unsigned long n) /* WIN32/WIN64 version */
+{ volatile char *x;
+ double get_mem;
+#ifndef SEP_STATE
+ char *dc_mem_start;
+#endif
+ if (verbose) printf("cpu%d: initialization for Windows\n", core_id);
+
+#ifdef SEP_STATE
+ #ifndef MEMLIM
+ if (verbose)
+ { printf("cpu0: steps 0,1: no -DMEMLIM set\n");
+ }
+ #else
+ if (verbose)
+ printf("cpu0: steps 0,1: -DMEMLIM=%d Mb - (hashtable %g Mb + workqueues %g Mb)\n",
+ MEMLIM, ((double)n/(1048576.)), ((double) NCORE * LWQ_SIZE + GWQ_SIZE)/(1048576.));
+#endif
+ get_mem = NCORE * sizeof(double) + (1 + CS_NR) * sizeof(void *)+ 4*sizeof(void *) + 2*sizeof(double);
+ /* NCORE * is_alive + search_terminated + CS_NR * sh_lock + 6 gr vars */
+ get_mem += 4 * NCORE * sizeof(void *);
+ #ifdef FULL_TRAIL
+ get_mem += (NCORE) * sizeof(Stack_Tree *);
+ /* NCORE * stack_last */
+ #endif
+ x = (volatile char *) prep_state_mem((size_t) get_mem);
+ shmid_X = (void *) x;
+ if (x == NULL)
+ { printf("cpu0: could not allocate shared memory, see ./pan --\n");
+ exit(1);
+ }
+ search_terminated = (volatile unsigned int *) x; /* comes first */
+ x += sizeof(void *); /* maintain alignment */
+
+ is_alive = (volatile double *) x;
+ x += NCORE * sizeof(double);
+
+ sh_lock = (volatile int *) x;
+ x += CS_NR * sizeof(void *); /* allow 1 word per entry */
+
+ grfree = (volatile int *) x;
+ x += sizeof(void *);
+ grfull = (volatile int *) x;
+ x += sizeof(void *);
+ grcnt = (volatile int *) x;
+ x += sizeof(void *);
+ grmax = (volatile int *) x;
+ x += sizeof(void *);
+ prfree = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prfull = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prcnt = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prmax = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ gr_readmiss = (volatile double *) x;
+ x += sizeof(double);
+ gr_writemiss = (volatile double *) x;
+ x += sizeof(double);
+
+ #ifdef FULL_TRAIL
+ stack_last = (volatile Stack_Tree **) x;
+ x += NCORE * sizeof(Stack_Tree *);
+ #endif
+
+ #ifndef BITSTATE
+ H_tab = (struct H_el **) emalloc(n);
+ #endif
+#else
+ #ifndef MEMLIM
+ #warning MEMLIM not set
+ #define MEMLIM (2048)
+ #endif
+
+ if (core_id == 0 && verbose)
+ printf("cpu0: step 0: -DMEMLIM=%d Mb - (hashtable %g Mb + workqueues %g Mb) = %g Mb for state storage\n",
+ MEMLIM, ((double)n/(1048576.)), ((double) NCORE * LWQ_SIZE + GWQ_SIZE)/(1048576.),
+ (memlim - memcnt - (double) n - ((double) NCORE * LWQ_SIZE + GWQ_SIZE))/(1048576.));
+ #ifndef BITSTATE
+ H_tab = (struct H_el **) prep_shmid_S((size_t) n); /* hash_table */
+ #endif
+ get_mem = memlim - memcnt - ((double) NCORE) * LWQ_SIZE - GWQ_SIZE;
+ if (get_mem <= 0)
+ { Uerror("internal error -- shared state memory");
+ }
+
+ if (core_id == 0 && verbose)
+ { printf("cpu0: step 2: shared state memory %g Mb\n",
+ get_mem/(1048576.));
+ }
+ x = dc_mem_start = (char *) prep_state_mem((size_t) get_mem); /* for states */
+ if (x == NULL)
+ { printf("cpu%d: insufficient memory -- aborting\n", core_id);
+ exit(1);
+ }
+
+ search_terminated = (volatile unsigned int *) x; /* comes first */
+ x += sizeof(void *); /* maintain alignment */
+
+ is_alive = (volatile double *) x;
+ x += NCORE * sizeof(double);
+
+ sh_lock = (volatile int *) x;
+ x += CS_NR * sizeof(int);
+
+ grfree = (volatile int *) x;
+ x += sizeof(void *);
+ grfull = (volatile int *) x;
+ x += sizeof(void *);
+ grcnt = (volatile int *) x;
+ x += sizeof(void *);
+ grmax = (volatile int *) x;
+ x += sizeof(void *);
+ prfree = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prfull = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prcnt = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ prmax = (volatile int *) x;
+ x += NCORE * sizeof(void *);
+ gr_readmiss = (volatile double *) x;
+ x += sizeof(double);
+ gr_writemiss = (volatile double *) x;
+ x += sizeof(double);
+
+ #ifdef FULL_TRAIL
+ stack_last = (volatile Stack_Tree **) x;
+ x += NCORE * sizeof(Stack_Tree *);
+ #endif
+ if (((long)x)&(sizeof(void *)-1)) /* word alignment */
+ { x += sizeof(void *)-(((long)x)&(sizeof(void *)-1)); /* 64-bit align */
+ }
+
+ #ifdef COLLAPSE
+ ncomps = (unsigned long *) x;
+ x += (256+2) * sizeof(unsigned long);
+ #endif
+
+ dc_shared = (sh_Allocater *) x; /* in shared memory */
+ x += sizeof(sh_Allocater);
+
+ if (core_id == 0) /* root only */
+ { dc_shared->dc_id = shmid_M;
+ dc_shared->dc_start = (void *) dc_mem_start;
+ dc_shared->dc_arena = x;
+ dc_shared->pattern = 1234567;
+ dc_shared->dc_size = (long) get_mem - (long) (x - dc_mem_start);
+ dc_shared->nxt = NULL;
+ }
+#endif
+}
+
+#if defined(WIN32) || defined(WIN64) || defined(__i386__) || defined(__x86_64__)
+extern BOOLEAN InterlockedBitTestAndSet(LONG volatile* Base, LONG Bit);
+int
+tas(volatile LONG *s)
+{ return InterlockedBitTestAndSet(s, 1);
+}
+#else
+ #error missing definition of test and set operation for this platform
+#endif
+
+void
+cleanup_shm(int val)
+{ int m;
+ static int nibis = 0;
+
+ if (nibis != 0)
+ { printf("cpu%d: Redundant call to cleanup_shm(%d)\n", core_id, val);
+ return;
+ } else
+ { nibis = 1;
+ }
+ if (search_terminated != NULL)
+ { *search_terminated |= 16; /* cleanup_shm */
+ }
+
+ for (m = 0; m < NR_QS; m++)
+ { if (shmid[m] != NULL)
+ { UnmapViewOfFile((char *) shared_mem[m]);
+ CloseHandle(shmid[m]);
+ } }
+#ifdef SEP_STATE
+ UnmapViewOfFile((void *) shmid_X);
+ CloseHandle((void *) shmid_M);
+#else
+ #ifdef BITSTATE
+ if (shmid_S != NULL)
+ { UnmapViewOfFile(SS);
+ CloseHandle(shmid_S);
+ }
+ #else
+ if (core_id == 0 && verbose)
+ { printf("cpu0: done, %ld Mb of shared state memory left\n",
+ dc_shared->dc_size / (long)(1048576));
+ }
+ if (shmid_S != NULL)
+ { UnmapViewOfFile(H_tab);
+ CloseHandle(shmid_S);
+ }
+ shmid_M = (void *) (dc_shared->dc_id);
+ UnmapViewOfFile((char *) dc_shared->dc_start);
+ CloseHandle(shmid_M);
+ #endif
+#endif
+ /* detached from shared memory - so cannot use cpu_printf */
+ if (verbose)
+ { printf("cpu%d: done -- got %d states from queue\n",
+ core_id, nstates_get);
+ }
+}
+
+void
+mem_get(void)
+{ SM_frame *f;
+ int is_parent;
+
+#if defined(MA) && !defined(SEP_STATE)
+ #error MA requires SEP_STATE in multi-core mode
+#endif
+#ifdef BFS
+ #error BFS is not supported in multi-core mode
+#endif
+#ifdef SC
+ #error SC is not supported in multi-core mode
+#endif
+ init_shm(); /* we are single threaded when this starts */
+ signal(SIGINT, give_up); /* windows control-c interrupt */
+
+ if (core_id == 0 && verbose)
+ { printf("cpu0: step 4: creating additional workers (proxy %d)\n",
+ proxy_pid);
+ }
+#if 0
+ if NCORE > 1 the child or the parent should fork N-1 more times
+ the parent is the only process with core_id == 0 and is_parent > 0
+ the others (workers) have is_parent = 0 and core_id = 1..NCORE-1
+#endif
+ if (core_id == 0) /* root starts up the workers */
+ { worker_pids[0] = (DWORD) getpid(); /* for completeness */
+ while (++core_id < NCORE) /* first worker sees core_id = 1 */
+ { char cmdline[64];
+ STARTUPINFO si = { sizeof(si) };
+ PROCESS_INFORMATION pi;
+
+ if (proxy_pid == core_id) /* always non-zero */
+ { sprintf(cmdline, "pan_proxy.exe -r %s-Q%d -Z%d",
+ o_cmdline, getpid(), core_id);
+ } else
+ { sprintf(cmdline, "pan.exe %s-Q%d -Z%d",
+ o_cmdline, getpid(), core_id);
+ }
+ if (verbose) printf("cpu%d: spawn %s\n", core_id, cmdline);
+
+ is_parent = CreateProcess(0, cmdline, 0, 0, FALSE, 0, 0, 0, &si, &pi);
+ if (is_parent == 0)
+ { Uerror("fork failed");
+ }
+ worker_pids[core_id] = pi.dwProcessId;
+ worker_handles[core_id] = pi.hProcess;
+ if (verbose)
+ { cpu_printf("created core %d, pid %d\n",
+ core_id, pi.dwProcessId);
+ }
+ if (proxy_pid == core_id) /* we just created the receive half */
+ { /* add proxy send, store pid in proxy_pid_snd */
+ sprintf(cmdline, "pan_proxy.exe -s %s-Q%d -Z%d -Y%d",
+ o_cmdline, getpid(), core_id, worker_pids[proxy_pid]);
+ if (verbose) printf("cpu%d: spawn %s\n", core_id, cmdline);
+ is_parent = CreateProcess(0, cmdline, 0,0, FALSE, 0,0,0, &si, &pi);
+ if (is_parent == 0)
+ { Uerror("fork failed");
+ }
+ proxy_pid_snd = pi.dwProcessId;
+ proxy_handle_snd = pi.hProcess;
+ if (verbose)
+ { cpu_printf("created core %d, pid %d (send proxy)\n",
+ core_id, pi.dwProcessId);
+ } } }
+ core_id = 0; /* reset core_id for root process */
+ } else /* worker */
+ { static char db0[16]; /* good for up to 10^6 cores */
+ static char db1[16];
+ tprefix = db0; sprefix = db1;
+ sprintf(tprefix, "cpu%d_trail", core_id); /* avoid conflicts on file access */
+ sprintf(sprefix, "cpu%d_rst", core_id);
+ memcnt = 0; /* count only additionally allocated memory */
+ }
+ if (verbose)
+ { cpu_printf("starting core_id %d -- pid %d\n", core_id, getpid());
+ }
+ if (core_id == 0 && !remote_party)
+ { new_state(); /* root starts the search */
+ if (verbose)
+ cpu_printf("done with 1st dfs, nstates %g (put %d states), start reading q\n",
+ nstates, nstates_put);
+ dfs_phase2 = 1;
+ }
+ Read_Queue(core_id); /* all cores */
+
+ if (verbose)
+ { cpu_printf("put %6d states into queue -- got %6d\n",
+ nstates_put, nstates_get);
+ }
+ done = 1;
+ wrapup();
+ exit(0);
+}
+#endif
+
+#ifdef BITSTATE
+void
+init_SS(unsigned long n)
+{
+ SS = (uchar *) prep_shmid_S((size_t) n);
+ init_HT(0L);
+}
+#endif
+
+#endif
+clock_t start_time;
+#if NCORE>1
+clock_t crash_stamp;
+#endif
+#if !defined(WIN32) && !defined(WIN64)
+struct tms start_tm;
+#endif
+
+void
+start_timer(void)
+{
+#if defined(WIN32) || defined(WIN64)
+ start_time = clock();
+#else
+ start_time = times(&start_tm);
+#endif
+}
+
+void
+stop_timer(void)
+{ clock_t stop_time;
+ double delta_time;
+#if !defined(WIN32) && !defined(WIN64)
+ struct tms stop_tm;
+ stop_time = times(&stop_tm);
+ delta_time = ((double) (stop_time - start_time)) / ((double) sysconf(_SC_CLK_TCK));
+#else
+ stop_time = clock();
+ delta_time = ((double) (stop_time - start_time)) / ((double) CLOCKS_PER_SEC);
+#endif
+ if (readtrail || delta_time < 0.00) return;
+#if NCORE>1
+ if (core_id == 0 && nstates > (double) 0)
+ { printf("\ncpu%d: elapsed time %.3g seconds (%g states visited)\n", core_id, delta_time, nstates);
+ if (delta_time > 0.01)
+ { printf("cpu%d: rate %g states/second\n", core_id, nstates/delta_time);
+ }
+ { void check_overkill(void);
+ check_overkill();
+ } }
+#else
+ printf("\npan: elapsed time %.3g seconds\n", delta_time);
+ if (delta_time > 0.01)
+ { printf("pan: rate %9.8g states/second\n", nstates/delta_time);
+ if (verbose)
+ { printf("pan: avg transition delay %.5g usec\n",
+ delta_time/(nstates+truncs));
+ } }
+#endif
+}
+
+#if NCORE>1
+#ifdef T_ALERT
+double t_alerts[17];
+
+void
+crash_report(void)
+{ int i;
+ printf("crash alert intervals:\n");
+ for (i = 0; i < 17; i++)
+ { printf("%d\t%g\n", i, t_alerts[i]);
+} }
+#endif
+
+void
+crash_reset(void)
+{ /* false alarm */
+ if (crash_stamp != (clock_t) 0)
+ {
+#ifdef T_ALERT
+ double delta_time;
+ int i;
+#if defined(WIN32) || defined(WIN64)
+ delta_time = ((double) (clock() - crash_stamp)) / ((double) CLOCKS_PER_SEC);
+#else
+ delta_time = ((double) (times(&start_tm) - crash_stamp)) / ((double) sysconf(_SC_CLK_TCK));
+#endif
+ for (i = 0; i < 16; i++)
+ { if (delta_time <= (i*30))
+ { t_alerts[i] = delta_time;
+ break;
+ } }
+ if (i == 16) t_alerts[i] = delta_time;
+#endif
+ if (verbose)
+ printf("cpu%d: crash alert off\n", core_id);
+ }
+ crash_stamp = (clock_t) 0;
+}
+
+int
+crash_test(double maxtime)
+{ double delta_time;
+ if (crash_stamp == (clock_t) 0)
+ { /* start timing */
+#if defined(WIN32) || defined(WIN64)
+ crash_stamp = clock();
+#else
+ crash_stamp = times(&start_tm);
+#endif
+ if (verbose)
+ { printf("cpu%d: crash detection\n", core_id);
+ }
+ return 0;
+ }
+#if defined(WIN32) || defined(WIN64)
+ delta_time = ((double) (clock() - crash_stamp)) / ((double) CLOCKS_PER_SEC);
+#else
+ delta_time = ((double) (times(&start_tm) - crash_stamp)) / ((double) sysconf(_SC_CLK_TCK));
+#endif
+ return (delta_time >= maxtime);
+}
+#endif
+
+void
+do_the_search(void)
+{ int i;
+ depth = mreached = 0;
+ trpt = &trail[0];
+#ifdef VERI
+ trpt->tau |= 4; /* the claim moves first */
+#endif
+ for (i = 0; i < (int) now._nr_pr; i++)
+ { P0 *ptr = (P0 *) pptr(i);
+#ifndef NP
+ if (!(trpt->o_pm&2)
+ && accpstate[ptr->_t][ptr->_p])
+ { trpt->o_pm |= 2;
+ }
+#else
+ if (!(trpt->o_pm&4)
+ && progstate[ptr->_t][ptr->_p])
+ { trpt->o_pm |= 4;
+ }
+#endif
+ }
+#ifdef EVENT_TRACE
+#ifndef NP
+ if (accpstate[EVENT_TRACE][now._event])
+ { trpt->o_pm |= 2;
+ }
+#else
+ if (progstate[EVENT_TRACE][now._event])
+ { trpt->o_pm |= 4;
+ }
+#endif
+#endif
+#ifndef NOCOMP
+ Mask[0] = Mask[1] = 1; /* _nr_pr, _nr_qs */
+ if (!a_cycles)
+ { i = &(now._a_t) - (uchar *) &now;
+ Mask[i] = 1; /* _a_t */
+ }
+#ifndef NOFAIR
+ if (!fairness)
+ { int j = 0;
+ i = &(now._cnt[0]) - (uchar *) &now;
+ while (j++ < NFAIR)
+ Mask[i++] = 1; /* _cnt[] */
+ }
+#endif
+#endif
+#ifndef NOFAIR
+ if (fairness
+ && (a_cycles && (trpt->o_pm&2)))
+ { now._a_t = 2; /* set the A-bit */
+ now._cnt[0] = now._nr_pr + 1;
+#ifdef VERBOSE
+ printf("%3d: fairness Rule 1, cnt=%d, _a_t=%d\n",
+ depth, now._cnt[now._a_t&1], now._a_t);
+#endif
+ }
+#endif
+ c_stack_start = (char *) &i; /* meant to be read-only */
+#if defined(HAS_CODE) && defined (C_INIT)
+ C_INIT; /* initialization of data that must precede fork() */
+ c_init_done++;
+#endif
+#if defined(C_States) && (HAS_TRACK==1)
+ /* capture initial state of tracked C objects */
+ c_update((uchar *) &(now.c_state[0]));
+#endif
+#ifdef HAS_CODE
+ if (readtrail) getrail(); /* no return */
+#endif
+ start_timer();
+#ifdef BFS
+ bfs();
+#else
+#if defined(C_States) && defined(HAS_STACK) && (HAS_TRACK==1)
+ /* initial state of tracked & unmatched objects */
+ c_stack((uchar *) &(svtack->c_stack[0]));
+#endif
+#ifdef RANDOMIZE
+ #if RANDOMIZE>0
+ srand(RANDOMIZE);
+ #else
+ srand(123);
+ #endif
+#endif
+#if NCORE>1
+ mem_get();
+#else
+ new_state(); /* start 1st DFS */
+#endif
+#endif
+}
+#ifdef INLINE_REV
+uchar
+do_reverse(Trans *t, short II, uchar M)
+{ uchar _m = M;
+ int tt = (int) ((P0 *)this)->_p;
+#include REVERSE_MOVES
+R999: return _m;
+}
+#endif
+#ifndef INLINE
+#ifdef EVENT_TRACE
+static char _tp = 'n'; static int _qid = 0;
+#endif
+uchar
+do_transit(Trans *t, short II)
+{ uchar _m = 0;
+ int tt = (int) ((P0 *)this)->_p;
+#ifdef M_LOSS
+ uchar delta_m = 0;
+#endif
+#ifdef EVENT_TRACE
+ short oboq = boq;
+ uchar ot = (uchar) ((P0 *)this)->_t;
+ if (ot == EVENT_TRACE) boq = -1;
+#define continue { boq = oboq; return 0; }
+#else
+#define continue return 0
+#ifdef SEPARATE
+ uchar ot = (uchar) ((P0 *)this)->_t;
+#endif
+#endif
+#include FORWARD_MOVES
+P999:
+#ifdef EVENT_TRACE
+ if (ot == EVENT_TRACE) boq = oboq;
+#endif
+ return _m;
+#undef continue
+}
+#ifdef EVENT_TRACE
+void
+require(char tp, int qid)
+{ Trans *t;
+ _tp = tp; _qid = qid;
+
+ if (now._event != endevent)
+ for (t = trans[EVENT_TRACE][now._event]; t; t = t->nxt)
+ { if (do_transit(t, EVENT_TRACE))
+ { now._event = t->st;
+ reached[EVENT_TRACE][t->st] = 1;
+#ifdef VERBOSE
+ printf(" event_trace move to -> %d\n", t->st);
+#endif
+#ifndef BFS
+#ifndef NP
+ if (accpstate[EVENT_TRACE][now._event])
+ (trpt+1)->o_pm |= 2;
+#else
+ if (progstate[EVENT_TRACE][now._event])
+ (trpt+1)->o_pm |= 4;
+#endif
+#endif
+#ifdef NEGATED_TRACE
+ if (now._event == endevent)
+ {
+#ifndef BFS
+ depth++; trpt++;
+#endif
+ uerror("event_trace error (all events matched)");
+#ifndef BFS
+ trpt--; depth--;
+#endif
+ break;
+ }
+#endif
+ for (t = t->nxt; t; t = t->nxt)
+ { if (do_transit(t, EVENT_TRACE))
+ Uerror("non-determinism in event-trace");
+ }
+ return;
+ }
+#ifdef VERBOSE
+ else
+ printf(" event_trace miss '%c' -- %d, %d, %d\n",
+ tp, qid, now._event, t->forw);
+#endif
+ }
+#ifdef NEGATED_TRACE
+ now._event = endevent; /* only 1st try will count -- fixed 4.2.6 */
+#else
+#ifndef BFS
+ depth++; trpt++;
+#endif
+ uerror("event_trace error (no matching event)");
+#ifndef BFS
+ trpt--; depth--;
+#endif
+#endif
+}
+#endif
+int
+enabled(int iam, int pid)
+{ Trans *t; uchar *othis = this;
+ int res = 0; int tt; uchar ot;
+#ifdef VERI
+ /* if (pid > 0) */ pid++;
+#endif
+ if (pid == iam)
+ Uerror("used: enabled(pid=thisproc)");
+ if (pid < 0 || pid >= (int) now._nr_pr)
+ return 0;
+ this = pptr(pid);
+ TstOnly = 1;
+ tt = (int) ((P0 *)this)->_p;
+ ot = (uchar) ((P0 *)this)->_t;
+ for (t = trans[ot][tt]; t; t = t->nxt)
+ if (do_transit(t, (short) pid))
+ { res = 1;
+ break;
+ }
+ TstOnly = 0;
+ this = othis;
+ return res;
+}
+#endif
+void
+snap_time(void)
+{ clock_t stop_time;
+ double delta_time;
+#if !defined(WIN32) && !defined(WIN64)
+ struct tms stop_tm;
+ stop_time = times(&stop_tm);
+ delta_time = ((double) (stop_time - start_time)) / ((double) sysconf(_SC_CLK_TCK));
+#else
+ stop_time = clock();
+ delta_time = ((double) (stop_time - start_time)) / ((double) CLOCKS_PER_SEC);
+#endif
+ if (delta_time > 0.01)
+ { printf("t= %6.3g ", delta_time);
+ printf("R= %7.0g", nstates/delta_time);
+ }
+ printf("\n");
+ if (quota > 0.1 && delta_time > quota)
+ { printf("Time limit of %6.3g minutes exceeded\n", quota/60.0);
+#if NCORE>1
+ fflush(stdout);
+ leave_critical(GLOBAL_LOCK);
+ sudden_stop("time-limit");
+ exit(1);
+#endif
+ wrapup();
+ }
+}
+void
+snapshot(void)
+{
+#if NCORE>1
+ enter_critical(GLOBAL_LOCK); /* snapshot */
+ printf("cpu%d: ", core_id);
+#endif
+ printf("Depth= %7ld States= %8.3g ",
+#if NCORE>1
+ (long) (nr_handoffs * z_handoff) +
+#endif
+ mreached, nstates);
+ printf("Transitions= %8.3g ", nstates+truncs);
+#ifdef MA
+ printf("Nodes= %7d ", nr_states);
+#endif
+ printf("Memory= %9.3f\t", memcnt/1048576.);
+ snap_time();
+ fflush(stdout);
+#if NCORE>1
+ leave_critical(GLOBAL_LOCK);
+#endif
+}
+#ifdef SC
+void
+stack2disk(void)
+{
+ if (!stackwrite
+ && (stackwrite = creat(stackfile, TMODE)) < 0)
+ Uerror("cannot create stackfile");
+
+ if (write(stackwrite, trail, DDD*sizeof(Trail))
+ != DDD*sizeof(Trail))
+ Uerror("stackfile write error -- disk is full?");
+
+ memmove(trail, &trail[DDD], (HHH-DDD+2)*sizeof(Trail));
+ memset(&trail[HHH-DDD+2], 0, (omaxdepth - HHH + DDD - 2)*sizeof(Trail));
+ CNT1++;
+}
+void
+disk2stack(void)
+{ long have;
+
+ CNT2++;
+ memmove(&trail[DDD], trail, (HHH-DDD+2)*sizeof(Trail));
+
+ if (!stackwrite
+ || lseek(stackwrite, -DDD* (off_t) sizeof(Trail), SEEK_CUR) == -1)
+ Uerror("disk2stack lseek error");
+
+ if (!stackread
+ && (stackread = open(stackfile, 0)) < 0)
+ Uerror("cannot open stackfile");
+
+ if (lseek(stackread, (CNT1-CNT2)*DDD* (off_t) sizeof(Trail), SEEK_SET) == -1)
+ Uerror("disk2stack lseek error");
+
+ have = read(stackread, trail, DDD*sizeof(Trail));
+ if (have != DDD*sizeof(Trail))
+ Uerror("stackfile read error");
+}
+#endif
+uchar *
+Pptr(int x)
+{ if (x < 0 || x >= MAXPROC || !proc_offset[x])
+ return noptr;
+ else
+ return (uchar *) pptr(x);
+}
+int qs_empty(void);
+/*
+ * new_state() is the main DFS search routine in the verifier
+ * it has a lot of code ifdef-ed together to support
+ * different search modes, which makes it quite unreadable.
+ * if you are studying the code, first use the C preprocessor
+ * to generate a specific version from the pan.c source,
+ * e.g. by saying:
+ * gcc -E -DNOREDUCE -DBITSTATE pan.c > ppan.c
+ * and then study the resulting file, rather than this one
+ */
+#if !defined(BFS) && (!defined(BITSTATE) || !defined(MA))
+
+#ifdef NSUCC
+int N_succ[512];
+void
+tally_succ(int cnt)
+{ if (cnt < 512) N_succ[cnt]++;
+ else printf("tally_succ: cnt %d exceeds range\n", cnt);
+}
+
+void
+dump_succ(void)
+{ int i; double sum = 0.0;
+ double w_avg = 0.0;
+ printf("Successor counts:\n");
+ for (i = 0; i < 512; i++)
+ { sum += (double) N_succ[i];
+ }
+ for (i = 0; i < 512; i++)
+ { if (N_succ[i] > 0)
+ { printf("%3d %10d (%.4g %% of total)\n",
+ i, N_succ[i], (100.0 * (double) N_succ[i])/sum);
+ w_avg += (double) i * (double) N_succ[i];
+ } }
+ if (sum > N_succ[0])
+ printf("mean %.4g (without 0: %.4g)\n", w_avg / sum, w_avg / (sum - (double) N_succ[0]));
+}
+#endif
+
+void
+new_state(void)
+{ Trans *t;
+ uchar _n, _m, ot;
+#ifdef RANDOMIZE
+ short ooi, eoi;
+#endif
+#ifdef M_LOSS
+ uchar delta_m = 0;
+#endif
+ short II, JJ = 0, kk;
+ int tt;
+#ifdef REVERSE
+ short From = BASE, To = now._nr_pr-1;
+#else
+ short From = now._nr_pr-1, To = BASE;
+#endif
+Down:
+#ifdef CHECK
+ cpu_printf("%d: Down - %s %saccepting [pids %d-%d]\n",
+ depth, (trpt->tau&4)?"claim":"program",
+ (trpt->o_pm&2)?"":"non-", From, To);
+#endif
+#ifdef SCHED
+ if (depth > 0)
+ { trpt->sched_limit = (trpt-1)->sched_limit;
+ } else
+ { trpt->sched_limit = 0;
+ }
+#endif
+#ifdef SC
+ if (depth > hiwater)
+ { stack2disk();
+ maxdepth += DDD;
+ hiwater += DDD;
+ trpt -= DDD;
+ if(verbose)
+ printf("zap %d: %d (maxdepth now %d)\n",
+ CNT1, hiwater, maxdepth);
+ }
+#endif
+ trpt->tau &= ~(16|32|64); /* make sure these are off */
+#if defined(FULLSTACK) && defined(MA)
+ trpt->proviso = 0;
+#endif
+#ifdef NSUCC
+ trpt->n_succ = 0;
+#endif
+#if NCORE>1
+ if (mem_hand_off())
+ {
+#if SYNC
+ (trpt+1)->o_n = 1; /* not a deadlock: as below */
+#endif
+#ifndef LOOPSTATE
+ (trpt-1)->tau |= 16; /* worstcase guess: as below */
+#endif
+#if NCORE>1 && defined(FULL_TRAIL)
+ if (upto > 0)
+ { Pop_Stack_Tree();
+ }
+#endif
+ goto Up;
+ }
+#endif
+ if (depth >= maxdepth)
+ { if (!warned)
+ { warned = 1;
+ printf("error: max search depth too small\n");
+ }
+ if (bounded)
+ { uerror("depth limit reached");
+ }
+ truncs++;
+#if SYNC
+ (trpt+1)->o_n = 1; /* not a deadlock */
+#endif
+#ifndef LOOPSTATE
+ (trpt-1)->tau |= 16; /* worstcase guess */
+#endif
+#if NCORE>1 && defined(FULL_TRAIL)
+ if (upto > 0)
+ { Pop_Stack_Tree();
+ }
+#endif
+ goto Up;
+ }
+AllOver:
+#if (defined(FULLSTACK) && !defined(MA)) || NCORE>1
+ /* if atomic or rv move, carry forward previous state */
+ trpt->ostate = (trpt-1)->ostate;
+#endif
+#ifdef VERI
+ if ((trpt->tau&4) || ((trpt-1)->tau&128))
+#endif
+ if (boq == -1) { /* if not mid-rv */
+#ifndef SAFETY
+ /* this check should now be redundant
+ * because the seed state also appears
+ * on the 1st dfs stack and would be
+ * matched in hstore below
+ */
+ if ((now._a_t&1) && depth > A_depth)
+ { if (!memcmp((char *)&A_Root,
+ (char *)&now, vsize))
+ {
+ depthfound = A_depth;
+#ifdef CHECK
+ printf("matches seed\n");
+#endif
+#ifdef NP
+ uerror("non-progress cycle");
+#else
+ uerror("acceptance cycle");
+#endif
+#if NCORE>1 && defined(FULL_TRAIL)
+ if (upto > 0)
+ { Pop_Stack_Tree();
+ }
+#endif
+ goto Up;
+ }
+#ifdef CHECK
+ printf("not seed\n");
+#endif
+ }
+#endif
+ if (!(trpt->tau&8)) /* if no atomic move */
+ {
+#ifdef BITSTATE
+#ifdef CNTRSTACK
+ II = bstore((char *)&now, vsize);
+ trpt->j6 = j1; trpt->j7 = j2;
+ JJ = LL[j1] && LL[j2];
+#else
+#ifdef FULLSTACK
+ JJ = onstack_now();
+#else
+#ifndef NOREDUCE
+ JJ = II; /* worstcase guess for p.o. */
+#endif
+#endif
+ II = bstore((char *)&now, vsize);
+#endif
+#else
+#ifdef MA
+ II = gstore((char *)&now, vsize, 0);
+#ifndef FULLSTACK
+ JJ = II;
+#else
+ JJ = (II == 2)?1:0;
+#endif
+#else
+ II = hstore((char *)&now, vsize);
+#ifdef FULLSTACK
+ JJ = (II == 2)?1:0;
+#endif
+#endif
+#endif
+ kk = (II == 1 || II == 2);
+#ifndef SAFETY
+#if NCORE==1 || defined (SEP_STATE)
+ if (II == 2 && ((trpt->o_pm&2) || ((trpt-1)->o_pm&2)))
+ #ifndef NOFAIR
+#if 0
+ if (!fairness || ((now._a_t&1) && now._cnt[1] == 1)) /* 5.1.4 */
+#else
+ if (a_cycles && !fairness) /* 5.1.6 -- example by Hirofumi Watanabe */
+#endif
+ #endif
+ {
+ II = 3; /* Schwoon & Esparza 2005, Gastin&Moro 2004 */
+#ifdef VERBOSE
+ printf("state match on dfs stack\n");
+#endif
+ goto same_case;
+ }
+#endif
+#if defined(FULLSTACK) && defined(BITSTATE)
+ if (!JJ && (now._a_t&1) && depth > A_depth)
+ { int oj1 = j1;
+ uchar o_a_t = now._a_t;
+ now._a_t &= ~(1|16|32);
+ if (onstack_now())
+ { II = 3;
+#ifdef VERBOSE
+ printf("state match on 1st dfs stack\n");
+#endif
+ }
+ now._a_t = o_a_t;
+ j1 = oj1;
+ }
+#endif
+ if (II == 3 && a_cycles && (now._a_t&1))
+ {
+#ifndef NOFAIR
+ if (fairness && now._cnt[1] > 1) /* was != 0 */
+ {
+#ifdef VERBOSE
+ printf(" fairness count non-zero\n");
+#endif
+ II = 0;
+ } else
+#endif
+ {
+#ifndef BITSTATE
+ nShadow--;
+#endif
+same_case: if (Lstate) depthfound = Lstate->D;
+#ifdef NP
+ uerror("non-progress cycle");
+#else
+ uerror("acceptance cycle");
+#endif
+#if NCORE>1 && defined(FULL_TRAIL)
+ if (upto > 0)
+ { Pop_Stack_Tree();
+ }
+#endif
+ goto Up;
+ }
+ }
+#endif
+#ifndef NOREDUCE
+#ifndef SAFETY
+#if NCORE>1 && !defined(SEP_STATE) && defined(V_PROVISO)
+ if (II != 0 && (!Lstate || Lstate->cpu_id < core_id))
+ { (trpt-1)->tau |= 16;
+ }
+#endif
+ if ((II && JJ) || (II == 3))
+ { /* marker for liveness proviso */
+#ifndef LOOPSTATE
+ (trpt-1)->tau |= 16;
+#endif
+ truncs2++;
+ }
+#else
+#if NCORE>1 && !defined(SEP_STATE) && defined(V_PROVISO)
+ if (!(II != 0 && (!Lstate || Lstate->cpu_id < core_id)))
+ { /* treat as stack state */
+ (trpt-1)->tau |= 16;
+ } else
+ { /* treat as non-stack state */
+ (trpt-1)->tau |= 64;
+ }
+#endif
+ if (!II || !JJ)
+ { /* successor outside stack */
+ (trpt-1)->tau |= 64;
+ }
+#endif
+#endif
+ if (II)
+ { truncs++;
+#if NCORE>1 && defined(FULL_TRAIL)
+ if (upto > 0)
+ { Pop_Stack_Tree();
+ if (depth == 0)
+ { return;
+ } }
+#endif
+ goto Up;
+ }
+ if (!kk)
+ { static long sdone = (long) 0; long ndone;
+ nstates++;
+#if defined(ZAPH) && defined(BITSTATE)
+ zstates += (double) hfns;
+#endif
+ ndone = (unsigned long) (nstates/((double) FREQ));
+ if (ndone != sdone)
+ { snapshot();
+ sdone = ndone;
+#if defined(AUTO_RESIZE) && !defined(BITSTATE) && !defined(MA)
+ if (nstates > ((double)(ONE_L<<(ssize+1))))
+ { void resize_hashtable(void);
+ resize_hashtable();
+ }
+#endif
+#if defined(ZAPH) && defined(BITSTATE)
+ if (zstates > ((double)(ONE_L<<(ssize-2))))
+ { /* more than half the bits set */
+ void zap_hashtable(void);
+ zap_hashtable();
+ zstates = 0;
+ }
+#endif
+ }
+#ifdef SVDUMP
+ if (vprefix > 0)
+ if (write(svfd, (uchar *) &now, vprefix) != vprefix)
+ { fprintf(efd, "writing %s.svd failed\n", PanSource);
+ wrapup();
+ }
+#endif
+#if defined(MA) && defined(W_XPT)
+ if ((unsigned long) nstates%W_XPT == 0)
+ { void w_xpoint(void);
+ w_xpoint();
+ }
+#endif
+ }
+#if defined(FULLSTACK) || defined(CNTRSTACK)
+ onstack_put();
+#ifdef DEBUG2
+#if defined(FULLSTACK) && !defined(MA)
+ printf("%d: putting %u (%d)\n", depth,
+ trpt->ostate,
+ (trpt->ostate)?trpt->ostate->tagged:0);
+#else
+ printf("%d: putting\n", depth);
+#endif
+#endif
+#else
+ #if NCORE>1
+ trpt->ostate = Lstate;
+ #endif
+#endif
+ } }
+ if (depth > mreached)
+ mreached = depth;
+#ifdef VERI
+ if (trpt->tau&4)
+#endif
+ trpt->tau &= ~(1|2); /* timeout and -request off */
+ _n = 0;
+#if SYNC
+ (trpt+1)->o_n = 0;
+#endif
+#ifdef VERI
+ if (now._nr_pr == 0) /* claim terminated */
+ uerror("end state in claim reached");
+ check_claim(((P0 *)pptr(0))->_p);
+Stutter:
+ if (trpt->tau&4) /* must make a claimmove */
+ {
+#ifndef NOFAIR
+ if ((now._a_t&2) /* A-bit set */
+ && now._cnt[now._a_t&1] == 1)
+ { now._a_t &= ~2;
+ now._cnt[now._a_t&1] = 0;
+ trpt->o_pm |= 16;
+#ifdef DEBUG
+ printf("%3d: fairness Rule 3.: _a_t = %d\n",
+ depth, now._a_t);
+#endif
+ }
+#endif
+ II = 0; /* never */
+ goto Veri0;
+ }
+#endif
+#ifndef NOREDUCE
+ /* Look for a process with only safe transitions */
+ /* (special rules apply in the 2nd dfs) */
+ if (boq == -1 && From != To
+
+#ifdef SAFETY
+ #if NCORE>1
+ && (depth < z_handoff)
+ #endif
+ )
+#else
+ #if NCORE>1
+ && ((a_cycles) || (!a_cycles && depth < z_handoff))
+ #endif
+ && (!(now._a_t&1)
+ || (a_cycles &&
+ #ifndef BITSTATE
+#ifdef MA
+#ifdef VERI
+ !((trpt-1)->proviso))
+#else
+ !(trpt->proviso))
+#endif
+#else
+#ifdef VERI
+ (trpt-1)->ostate &&
+ !(((char *)&((trpt-1)->ostate->state))[0] & 128))
+#else
+ !(((char *)&(trpt->ostate->state))[0] & 128))
+#endif
+#endif
+ #else
+#ifdef VERI
+ (trpt-1)->ostate &&
+ (trpt-1)->ostate->proviso == 0)
+#else
+ trpt->ostate->proviso == 0)
+#endif
+ #endif
+ ))
+#endif
+
+#ifdef REVERSE
+ for (II = From; II <= To; II++)
+#else
+ for (II = From; II >= To; II--)
+#endif
+ {
+Resume: /* pick up here if preselect fails */
+ this = pptr(II);
+ tt = (int) ((P0 *)this)->_p;
+ ot = (uchar) ((P0 *)this)->_t;
+ if (trans[ot][tt]->atom & 8)
+ { t = trans[ot][tt];
+ if (t->qu[0] != 0)
+ { Ccheck++;
+ if (!q_cond(II, t))
+ continue;
+ Cholds++;
+ }
+ From = To = II; /* the process preselected */
+#ifdef NIBIS
+ t->om = 0;
+#endif
+ trpt->tau |= 32; /* preselect marker */
+#ifdef DEBUG
+#ifdef NIBIS
+ printf("%3d: proc %d Pre", depth, II);
+ printf("Selected (om=%d, tau=%d)\n",
+ t->om, trpt->tau);
+#else
+ printf("%3d: proc %d PreSelected (tau=%d)\n",
+ depth, II, trpt->tau);
+#endif
+#endif
+ goto Again;
+ }
+ }
+ trpt->tau &= ~32;
+#endif
+#if !defined(NOREDUCE) || (defined(ETIM) && !defined(VERI))
+Again:
+#endif
+ /* The Main Expansion Loop over Processes */
+ trpt->o_pm &= ~(8|16|32|64); /* fairness-marks */
+#ifndef NOFAIR
+ if (fairness && boq == -1
+#ifdef VERI
+ && (!(trpt->tau&4) && !((trpt-1)->tau&128))
+#endif
+ && !(trpt->tau&8))
+ { /* A_bit = 1; Cnt = N in acc states with A_bit 0 */
+ if (!(now._a_t&2))
+ {
+ if (a_cycles && (trpt->o_pm&2))
+ { /* Accepting state */
+ now._a_t |= 2;
+ now._cnt[now._a_t&1] = now._nr_pr + 1;
+ trpt->o_pm |= 8;
+#ifdef DEBUG
+ printf("%3d: fairness Rule 1: cnt=%d, _a_t=%d\n",
+ depth, now._cnt[now._a_t&1], now._a_t);
+#endif
+ }
+ } else
+ { /* A_bit = 0 when Cnt 0 */
+ if (now._cnt[now._a_t&1] == 1)
+ { now._a_t &= ~2;
+ now._cnt[now._a_t&1] = 0;
+ trpt->o_pm |= 16;
+#ifdef DEBUG
+ printf("%3d: fairness Rule 3: _a_t = %d\n",
+ depth, now._a_t);
+#endif
+ } } }
+#endif
+
+#ifdef REVERSE
+ for (II = From; II <= To; II++)
+#else
+ for (II = From; II >= To; II--)
+#endif
+ {
+#if SYNC
+ /* no rendezvous with same proc */
+ if (boq != -1 && trpt->pr == II) continue;
+#endif
+#ifdef SCHED
+ /* limit max nr of interleavings */
+ if (From != To
+ && depth > 0
+ #ifdef VERI
+ && II != 0
+ #endif
+ && (trpt-1)->pr != II
+ && trpt->sched_limit >= sched_max)
+ { continue;
+ }
+#endif
+#ifdef VERI
+Veri0:
+#endif
+ this = pptr(II);
+ tt = (int) ((P0 *)this)->_p;
+ ot = (uchar) ((P0 *)this)->_t;
+#ifdef NIBIS
+ /* don't repeat a previous preselected expansion */
+ /* could hit this if reduction proviso was false */
+ t = trans[ot][tt];
+ if (!(trpt->tau&4)
+ && !(trpt->tau&1)
+ && !(trpt->tau&32)
+ && (t->atom & 8)
+ && boq == -1
+ && From != To)
+ { if (t->qu[0] == 0
+ || q_cond(II, t))
+ { _m = t->om;
+ if (_m>_n||(_n>3&&_m!=0)) _n=_m;
+ continue; /* did it before */
+ } }
+#endif
+ trpt->o_pm &= ~1; /* no move in this pid yet */
+#ifdef EVENT_TRACE
+ (trpt+1)->o_event = now._event;
+#endif
+ /* Fairness: Cnt++ when Cnt == II */
+#ifndef NOFAIR
+ trpt->o_pm &= ~64; /* didn't apply rule 2 */
+ if (fairness
+ && boq == -1
+ && !(trpt->o_pm&32)
+ && (now._a_t&2)
+ && now._cnt[now._a_t&1] == II+2)
+ { now._cnt[now._a_t&1] -= 1;
+#ifdef VERI
+ /* claim need not participate */
+ if (II == 1)
+ now._cnt[now._a_t&1] = 1;
+#endif
+#ifdef DEBUG
+ printf("%3d: proc %d fairness ", depth, II);
+ printf("Rule 2: --cnt to %d (%d)\n",
+ now._cnt[now._a_t&1], now._a_t);
+#endif
+ trpt->o_pm |= (32|64);
+ }
+#endif
+#ifdef HAS_PROVIDED
+ if (!provided(II, ot, tt, t)) continue;
+#endif
+ /* check all trans of proc II - escapes first */
+#ifdef HAS_UNLESS
+ trpt->e_state = 0;
+#endif
+ (trpt+1)->pr = (uchar) II;
+ (trpt+1)->st = tt;
+#ifdef RANDOMIZE
+ for (ooi = eoi = 0, t = trans[ot][tt]; t; t = t->nxt, ooi++)
+ { if (strcmp(t->tp, "else") == 0)
+ { eoi++;
+ break;
+ } }
+ if (eoi > 0)
+ { t = trans[ot][tt];
+ #ifdef VERBOSE
+ printf("randomizer: suppressed, saw else\n");
+ #endif
+ } else
+ { eoi = rand()%ooi;
+ #ifdef VERBOSE
+ printf("randomizer: skip %d in %d\n", eoi, ooi);
+ #endif
+ for (t = trans[ot][tt]; t; t = t->nxt)
+ if (eoi-- <= 0) break;
+ }
+domore:
+ for ( ; t && ooi > 0; t = t->nxt, ooi--)
+#else
+ for (t = trans[ot][tt]; t; t = t->nxt)
+#endif
+ {
+#ifdef HAS_UNLESS
+ /* exploring all transitions from
+ * a single escape state suffices
+ */
+ if (trpt->e_state > 0
+ && trpt->e_state != t->e_trans)
+ {
+#ifdef DEBUG
+ printf("skip 2nd escape %d (did %d before)\n",
+ t->e_trans, trpt->e_state);
+#endif
+ break;
+ }
+#endif
+ (trpt+1)->o_t = t;
+#ifdef INLINE
+#include FORWARD_MOVES
+P999: /* jumps here when move succeeds */
+#else
+ if (!(_m = do_transit(t, II))) continue;
+#endif
+#ifdef SCHED
+ if (depth > 0
+ #ifdef VERI
+ && II != 0
+ #endif
+ && (trpt-1)->pr != II)
+ { trpt->sched_limit = 1 + (trpt-1)->sched_limit;
+ }
+#endif
+ if (boq == -1)
+#ifdef CTL
+ /* for branching-time, can accept reduction only if */
+ /* the persistent set contains just 1 transition */
+ { if ((trpt->tau&32) && (trpt->o_pm&1))
+ trpt->tau |= 16;
+ trpt->o_pm |= 1; /* we moved */
+ }
+#else
+ trpt->o_pm |= 1; /* we moved */
+#endif
+#ifdef LOOPSTATE
+ if (loopstate[ot][tt])
+ {
+#ifdef VERBOSE
+ printf("exiting from loopstate:\n");
+#endif
+ trpt->tau |= 16;
+ cnt_loops++;
+ }
+#endif
+#ifdef PEG
+ peg[t->forw]++;
+#endif
+#if defined(VERBOSE) || defined(CHECK)
+#if defined(SVDUMP)
+ cpu_printf("%3d: proc %d exec %d \n", depth, II, t->t_id);
+#else
+ cpu_printf("%3d: proc %d exec %d, %d to %d, %s %s %s %saccepting [tau=%d]\n",
+ depth, II, t->forw, tt, t->st, t->tp,
+ (t->atom&2)?"atomic":"",
+ (boq != -1)?"rendez-vous":"",
+ (trpt->o_pm&2)?"":"non-", trpt->tau);
+#ifdef HAS_UNLESS
+ if (t->e_trans)
+ cpu_printf("\t(escape to state %d)\n", t->st);
+#endif
+#endif
+#ifdef RANDOMIZE
+ cpu_printf("\t(randomizer %d)\n", ooi);
+#endif
+#endif
+#ifdef HAS_LAST
+#ifdef VERI
+ if (II != 0)
+#endif
+ now._last = II - BASE;
+#endif
+#ifdef HAS_UNLESS
+ trpt->e_state = t->e_trans;
+#endif
+ depth++; trpt++;
+ trpt->pr = (uchar) II;
+ trpt->st = tt;
+ trpt->o_pm &= ~(2|4);
+ if (t->st > 0)
+ { ((P0 *)this)->_p = t->st;
+/* moved down reached[ot][t->st] = 1; */
+ }
+#ifndef SAFETY
+ if (a_cycles)
+ {
+#if (ACCEPT_LAB>0 && !defined(NP)) || (PROG_LAB>0 && defined(HAS_NP))
+ int ii;
+#endif
+#define P__Q ((P0 *)pptr(ii))
+#if ACCEPT_LAB>0
+#ifdef NP
+ /* state 1 of np_ claim is accepting */
+ if (((P0 *)pptr(0))->_p == 1)
+ trpt->o_pm |= 2;
+#else
+ for (ii = 0; ii < (int) now._nr_pr; ii++)
+ { if (accpstate[P__Q->_t][P__Q->_p])
+ { trpt->o_pm |= 2;
+ break;
+ } }
+#endif
+#endif
+#if defined(HAS_NP) && PROG_LAB>0
+ for (ii = 0; ii < (int) now._nr_pr; ii++)
+ { if (progstate[P__Q->_t][P__Q->_p])
+ { trpt->o_pm |= 4;
+ break;
+ } }
+#endif
+#undef P__Q
+ }
+#endif
+ trpt->o_t = t; trpt->o_n = _n;
+ trpt->o_ot = ot; trpt->o_tt = tt;
+ trpt->o_To = To; trpt->o_m = _m;
+ trpt->tau = 0;
+#ifdef RANDOMIZE
+ trpt->oo_i = ooi;
+#endif
+ if (boq != -1 || (t->atom&2))
+ { trpt->tau |= 8;
+#ifdef VERI
+ /* atomic sequence in claim */
+ if((trpt-1)->tau&4)
+ trpt->tau |= 4;
+ else
+ trpt->tau &= ~4;
+ } else
+ { if ((trpt-1)->tau&4)
+ trpt->tau &= ~4;
+ else
+ trpt->tau |= 4;
+ }
+ /* if claim allowed timeout, so */
+ /* does the next program-step: */
+ if (((trpt-1)->tau&1) && !(trpt->tau&4))
+ trpt->tau |= 1;
+#else
+ } else
+ trpt->tau &= ~8;
+#endif
+ if (boq == -1 && (t->atom&2))
+ { From = To = II; nlinks++;
+ } else
+#ifdef REVERSE
+ { From = BASE; To = now._nr_pr-1;
+#else
+ { From = now._nr_pr-1; To = BASE;
+#endif
+ }
+#if NCORE>1 && defined(FULL_TRAIL)
+ if (upto > 0)
+ { Push_Stack_Tree(II, t->t_id);
+ }
+#endif
+ goto Down; /* pseudo-recursion */
+Up:
+#ifdef CHECK
+ cpu_printf("%d: Up - %s\n", depth,
+ (trpt->tau&4)?"claim":"program");
+#endif
+#if NCORE>1
+ iam_alive();
+ #ifdef USE_DISK
+ mem_drain();
+ #endif
+#endif
+#if defined(MA) || NCORE>1
+ if (depth <= 0) return;
+ /* e.g., if first state is old, after a restart */
+#endif
+#ifdef SC
+ if (CNT1 > CNT2
+ && depth < hiwater - (HHH-DDD) + 2)
+ {
+ trpt += DDD;
+ disk2stack();
+ maxdepth -= DDD;
+ hiwater -= DDD;
+ if(verbose)
+ printf("unzap %d: %d\n", CNT2, hiwater);
+ }
+#endif
+#ifndef NOFAIR
+ if (trpt->o_pm&128) /* fairness alg */
+ { now._cnt[now._a_t&1] = trpt->bup.oval;
+ _n = 1; trpt->o_pm &= ~128;
+ depth--; trpt--;
+#if defined(VERBOSE) || defined(CHECK)
+ printf("%3d: reversed fairness default move\n", depth);
+#endif
+ goto Q999;
+ }
+#endif
+#ifdef HAS_LAST
+#ifdef VERI
+ { int d; Trail *trl;
+ now._last = 0;
+ for (d = 1; d < depth; d++)
+ { trl = getframe(depth-d); /* was (trpt-d) */
+ if (trl->pr != 0)
+ { now._last = trl->pr - BASE;
+ break;
+ } } }
+#else
+ now._last = (depth<1)?0:(trpt-1)->pr;
+#endif
+#endif
+#ifdef EVENT_TRACE
+ now._event = trpt->o_event;
+#endif
+#ifndef SAFETY
+ if ((now._a_t&1) && depth <= A_depth)
+ return; /* to checkcycles() */
+#endif
+ t = trpt->o_t; _n = trpt->o_n;
+ ot = trpt->o_ot; II = trpt->pr;
+ tt = trpt->o_tt; this = pptr(II);
+ To = trpt->o_To; _m = trpt->o_m;
+#ifdef RANDOMIZE
+ ooi = trpt->oo_i;
+#endif
+#ifdef INLINE_REV
+ _m = do_reverse(t, II, _m);
+#else
+#include REVERSE_MOVES
+R999: /* jumps here when done */
+#endif
+#ifdef VERBOSE
+ cpu_printf("%3d: proc %d reverses %d, %d to %d\n",
+ depth, II, t->forw, tt, t->st);
+ cpu_printf("\t%s [abit=%d,adepth=%d,tau=%d,%d]\n",
+ t->tp, now._a_t, A_depth, trpt->tau, (trpt-1)->tau);
+#endif
+#ifndef NOREDUCE
+ /* pass the proviso tags */
+ if ((trpt->tau&8) /* rv or atomic */
+ && (trpt->tau&16))
+ (trpt-1)->tau |= 16;
+#ifdef SAFETY
+ if ((trpt->tau&8) /* rv or atomic */
+ && (trpt->tau&64))
+ (trpt-1)->tau |= 64;
+#endif
+#endif
+ depth--; trpt--;
+
+#ifdef NSUCC
+ trpt->n_succ++;
+#endif
+#ifdef NIBIS
+ (trans[ot][tt])->om = _m; /* head of list */
+#endif
+ /* i.e., not set if rv fails */
+ if (_m)
+ {
+#if defined(VERI) && !defined(NP)
+ if (II == 0 && verbose && !reached[ot][t->st])
+ {
+ printf("depth %d: Claim reached state %d (line %d)\n",
+ depth, t->st, src_claim [t->st]);
+ fflush(stdout);
+ }
+#endif
+ reached[ot][t->st] = 1;
+ reached[ot][tt] = 1;
+ }
+#ifdef HAS_UNLESS
+ else trpt->e_state = 0; /* undo */
+#endif
+ if (_m>_n||(_n>3&&_m!=0)) _n=_m;
+ ((P0 *)this)->_p = tt;
+ } /* all options */
+#ifdef RANDOMIZE
+ if (!t && ooi > 0)
+ { t = trans[ot][tt];
+ #ifdef VERBOSE
+ printf("randomizer: continue for %d more\n", ooi);
+ #endif
+ goto domore;
+ }
+ #ifdef VERBOSE
+ else
+ printf("randomizer: done\n");
+ #endif
+#endif
+#ifndef NOFAIR
+ /* Fairness: undo Rule 2 */
+ if ((trpt->o_pm&32)
+ && (trpt->o_pm&64))
+ { if (trpt->o_pm&1)
+ {
+#ifdef VERI
+ if (now._cnt[now._a_t&1] == 1)
+ now._cnt[now._a_t&1] = 2;
+#endif
+ now._cnt[now._a_t&1] += 1;
+#ifdef VERBOSE
+ printf("%3d: proc %d fairness ", depth, II);
+ printf("undo Rule 2, cnt=%d, _a_t=%d\n",
+ now._cnt[now._a_t&1], now._a_t);
+#endif
+ trpt->o_pm &= ~(32|64);
+ } else
+ { if (_n > 0)
+ {
+ trpt->o_pm &= ~64;
+#ifdef REVERSE
+ II = From-1;
+#else
+ II = From+1;
+#endif
+ } } }
+#endif
+#ifdef VERI
+ if (II == 0) break; /* never claim */
+#endif
+ } /* all processes */
+#ifdef NSUCC
+ tally_succ(trpt->n_succ);
+#endif
+#ifdef SCHED
+ if (_n == 0 /* no process could move */
+ #ifdef VERI
+ && II != 0
+ #endif
+ && depth > 0
+ && trpt->sched_limit >= sched_max)
+ { _n = 1; /* not a deadlock */
+ }
+#endif
+#ifndef NOFAIR
+ /* Fairness: undo Rule 2 */
+ if (trpt->o_pm&32) /* remains if proc blocked */
+ {
+#ifdef VERI
+ if (now._cnt[now._a_t&1] == 1)
+ now._cnt[now._a_t&1] = 2;
+#endif
+ now._cnt[now._a_t&1] += 1;
+#ifdef VERBOSE
+ printf("%3d: proc -- fairness ", depth);
+ printf("undo Rule 2, cnt=%d, _a_t=%d\n",
+ now._cnt[now._a_t&1], now._a_t);
+#endif
+ trpt->o_pm &= ~32;
+ }
+#ifndef NP
+ if (fairness
+ && _n == 0 /* nobody moved */
+#ifdef VERI
+ && !(trpt->tau&4) /* in program move */
+#endif
+ && !(trpt->tau&8) /* not an atomic one */
+#ifdef OTIM
+ && ((trpt->tau&1) || endstate())
+#else
+#ifdef ETIM
+ && (trpt->tau&1) /* already tried timeout */
+#endif
+#endif
+#ifndef NOREDUCE
+ /* see below */
+ && !((trpt->tau&32) && (_n == 0 || (trpt->tau&16)))
+#endif
+ && now._cnt[now._a_t&1] > 0) /* needed more procs */
+ { depth++; trpt++;
+ trpt->o_pm |= 128 | ((trpt-1)->o_pm&(2|4));
+ trpt->bup.oval = now._cnt[now._a_t&1];
+ now._cnt[now._a_t&1] = 1;
+#ifdef VERI
+ trpt->tau = 4;
+#else
+ trpt->tau = 0;
+#endif
+#ifdef REVERSE
+ From = BASE; To = now._nr_pr-1;
+#else
+ From = now._nr_pr-1; To = BASE;
+#endif
+#if defined(VERBOSE) || defined(CHECK)
+ printf("%3d: fairness default move ", depth);
+ printf("(all procs block)\n");
+#endif
+ goto Down;
+ }
+#endif
+Q999: /* returns here with _n>0 when done */;
+ if (trpt->o_pm&8)
+ { now._a_t &= ~2;
+ now._cnt[now._a_t&1] = 0;
+ trpt->o_pm &= ~8;
+#ifdef VERBOSE
+ printf("%3d: fairness undo Rule 1, _a_t=%d\n",
+ depth, now._a_t);
+#endif
+ }
+ if (trpt->o_pm&16)
+ { now._a_t |= 2;
+ now._cnt[now._a_t&1] = 1;
+ trpt->o_pm &= ~16;
+#ifdef VERBOSE
+ printf("%3d: fairness undo Rule 3, _a_t=%d\n",
+ depth, now._a_t);
+#endif
+ }
+#endif
+#ifndef NOREDUCE
+#ifdef SAFETY
+#ifdef LOOPSTATE
+ /* at least one move that was preselected at this */
+ /* level, blocked or was a loop control flow point */
+ if ((trpt->tau&32) && (_n == 0 || (trpt->tau&16)))
+#else
+ /* preselected move - no successors outside stack */
+ if ((trpt->tau&32) && !(trpt->tau&64))
+#endif
+#ifdef REVERSE
+ { From = BASE; To = now._nr_pr-1;
+#else
+ { From = now._nr_pr-1; To = BASE;
+#endif
+#ifdef DEBUG
+ printf("%3d: proc %d UnSelected (_n=%d, tau=%d)\n",
+ depth, II+1, _n, trpt->tau);
+#endif
+ _n = 0; trpt->tau &= ~(16|32|64);
+#ifdef REVERSE
+ if (II <= To) /* II already decremented */
+#else
+ if (II >= BASE) /* II already decremented */
+#endif
+ goto Resume;
+ else
+ goto Again;
+ }
+#else
+ /* at least one move that was preselected at this */
+ /* level, blocked or truncated at the next level */
+/* implied: #ifdef FULLSTACK */
+ if ((trpt->tau&32) && (_n == 0 || (trpt->tau&16)))
+ {
+#ifdef DEBUG
+ printf("%3d: proc %d UnSelected (_n=%d, tau=%d)\n",
+ depth, II+1, (int) _n, trpt->tau);
+#endif
+ if (a_cycles && (trpt->tau&16))
+ { if (!(now._a_t&1))
+ {
+#ifdef DEBUG
+ printf("%3d: setting proviso bit\n", depth);
+#endif
+#ifndef BITSTATE
+#ifdef MA
+#ifdef VERI
+ (trpt-1)->proviso = 1;
+#else
+ trpt->proviso = 1;
+#endif
+#else
+#ifdef VERI
+ if ((trpt-1)->ostate)
+ ((char *)&((trpt-1)->ostate->state))[0] |= 128;
+#else
+ ((char *)&(trpt->ostate->state))[0] |= 128;
+#endif
+#endif
+#else
+#ifdef VERI
+ if ((trpt-1)->ostate)
+ (trpt-1)->ostate->proviso = 1;
+#else
+ trpt->ostate->proviso = 1;
+#endif
+#endif
+#ifdef REVERSE
+ From = BASE; To = now._nr_pr-1;
+#else
+ From = now._nr_pr-1; To = BASE;
+#endif
+ _n = 0; trpt->tau &= ~(16|32|64);
+ goto Again; /* do full search */
+ } /* else accept reduction */
+ } else
+#ifdef REVERSE
+ { From = BASE; To = now._nr_pr-1;
+#else
+ { From = now._nr_pr-1; To = BASE;
+#endif
+ _n = 0; trpt->tau &= ~(16|32|64);
+#ifdef REVERSE
+ if (II <= To) /* already decremented */
+#else
+ if (II >= BASE) /* already decremented */
+#endif
+ goto Resume;
+ else
+ goto Again;
+ } }
+/* #endif */
+#endif
+#endif
+ if (_n == 0 || ((trpt->tau&4) && (trpt->tau&2)))
+ {
+#ifdef DEBUG
+ cpu_printf("%3d: no move [II=%d, tau=%d, boq=%d]\n",
+ depth, II, trpt->tau, boq);
+#endif
+#if SYNC
+ /* ok if a rendez-vous fails: */
+ if (boq != -1) goto Done;
+#endif
+ /* ok if no procs or we're at maxdepth */
+ if ((now._nr_pr == 0 && (!strict || qs_empty()))
+#ifdef OTIM
+ || endstate()
+#endif
+ || depth >= maxdepth-1) goto Done;
+ if ((trpt->tau&8) && !(trpt->tau&4))
+ { trpt->tau &= ~(1|8);
+ /* 1=timeout, 8=atomic */
+#ifdef REVERSE
+ From = BASE; To = now._nr_pr-1;
+#else
+ From = now._nr_pr-1; To = BASE;
+#endif
+#ifdef DEBUG
+ cpu_printf("%3d: atomic step proc %d unexecutable\n", depth, II+1);
+#endif
+#ifdef VERI
+ trpt->tau |= 4; /* switch to claim */
+#endif
+ goto AllOver;
+ }
+#ifdef ETIM
+ if (!(trpt->tau&1)) /* didn't try timeout yet */
+ {
+#ifdef VERI
+ if (trpt->tau&4)
+ {
+#ifndef NTIM
+ if (trpt->tau&2) /* requested */
+#endif
+ { trpt->tau |= 1;
+ trpt->tau &= ~2;
+#ifdef DEBUG
+ cpu_printf("%d: timeout\n", depth);
+#endif
+ goto Stutter;
+ } }
+ else
+ { /* only claim can enable timeout */
+ if ((trpt->tau&8)
+ && !((trpt-1)->tau&4))
+/* blocks inside an atomic */ goto BreakOut;
+#ifdef DEBUG
+ cpu_printf("%d: req timeout\n",
+ depth);
+#endif
+ (trpt-1)->tau |= 2; /* request */
+#if NCORE>1 && defined(FULL_TRAIL)
+ if (upto > 0)
+ { Pop_Stack_Tree();
+ }
+#endif
+ goto Up;
+ }
+#else
+#ifdef DEBUG
+ cpu_printf("%d: timeout\n", depth);
+#endif
+ trpt->tau |= 1;
+ goto Again;
+#endif
+ }
+#endif
+#ifdef VERI
+BreakOut:
+#ifndef NOSTUTTER
+ if (!(trpt->tau&4))
+ { trpt->tau |= 4; /* claim stuttering */
+ trpt->tau |= 128; /* stutter mark */
+#ifdef DEBUG
+ cpu_printf("%d: claim stutter\n", depth);
+#endif
+ goto Stutter;
+ }
+#else
+ ;
+#endif
+#else
+ if (!noends && !a_cycles && !endstate())
+ { depth--; trpt--; /* new 4.2.3 */
+ uerror("invalid end state");
+ depth++; trpt++;
+ }
+#ifndef NOSTUTTER
+ else if (a_cycles && (trpt->o_pm&2)) /* new 4.2.4 */
+ { depth--; trpt--;
+ uerror("accept stutter");
+ depth++; trpt++;
+ }
+#endif
+#endif
+ }
+Done:
+ if (!(trpt->tau&8)) /* not in atomic seqs */
+ {
+#ifndef SAFETY
+ if (_n != 0
+#ifdef VERI
+ /* --after-- a program-step, i.e., */
+ /* after backtracking a claim-step */
+ && (trpt->tau&4)
+ /* with at least one running process */
+ /* unless in a stuttered accept state */
+ && ((now._nr_pr > 1) || (trpt->o_pm&2))
+#endif
+ && !(now._a_t&1))
+ {
+#ifndef NOFAIR
+ if (fairness)
+ {
+#ifdef VERBOSE
+ cpu_printf("Consider check %d %d...\n",
+ now._a_t, now._cnt[0]);
+#endif
+ if ((now._a_t&2) /* A-bit */
+ && (now._cnt[0] == 1))
+ checkcycles();
+ } else
+#endif
+ if (a_cycles && (trpt->o_pm&2))
+ checkcycles();
+ }
+#endif
+#ifndef MA
+#if defined(FULLSTACK) || defined(CNTRSTACK)
+#ifdef VERI
+ if (boq == -1
+ && (((trpt->tau&4) && !(trpt->tau&128))
+ || ( (trpt-1)->tau&128)))
+#else
+ if (boq == -1)
+#endif
+ {
+#ifdef DEBUG2
+#if defined(FULLSTACK)
+ printf("%d: zapping %u (%d)\n",
+ depth, trpt->ostate,
+ (trpt->ostate)?trpt->ostate->tagged:0);
+#endif
+#endif
+ onstack_zap();
+ }
+#endif
+#else
+#ifdef VERI
+ if (boq == -1
+ && (((trpt->tau&4) && !(trpt->tau&128))
+ || ( (trpt-1)->tau&128)))
+#else
+ if (boq == -1)
+#endif
+ {
+#ifdef DEBUG
+ printf("%d: zapping\n", depth);
+#endif
+ onstack_zap();
+#ifndef NOREDUCE
+ if (trpt->proviso)
+ gstore((char *) &now, vsize, 1);
+#endif
+ }
+#endif
+ }
+ if (depth > 0)
+ {
+#if NCORE>1 && defined(FULL_TRAIL)
+ if (upto > 0)
+ { Pop_Stack_Tree();
+ }
+#endif
+ goto Up;
+ }
+}
+
+#else
+void new_state(void) { /* place holder */ }
+#endif
+
+void
+assert(int a, char *s, int ii, int tt, Trans *t)
+{
+ if (!a && !noasserts)
+ { char bad[1024];
+ strcpy(bad, "assertion violated ");
+ if (strlen(s) > 1000)
+ { strncpy(&bad[19], (const char *) s, 1000);
+ bad[1019] = '\0';
+ } else
+ strcpy(&bad[19], s);
+ uerror(bad);
+ }
+}
+#ifndef NOBOUNDCHECK
+int
+Boundcheck(int x, int y, int a1, int a2, Trans *a3)
+{
+ assert((x >= 0 && x < y), "- invalid array index",
+ a1, a2, a3);
+ return x;
+}
+#endif
+void
+wrap_stats(void)
+{
+ if (nShadow>0)
+ printf("%9.8g states, stored (%g visited)\n",
+ nstates - nShadow, nstates);
+ else
+ printf("%9.8g states, stored\n", nstates);
+#ifdef BFS
+#if SYNC
+ printf(" %8g nominal states (- rv and atomic)\n", nstates-midrv-nlinks+revrv);
+ printf(" %8g rvs succeeded\n", midrv-failedrv);
+#else
+ printf(" %8g nominal states (stored-atomic)\n", nstates-nlinks);
+#endif
+#ifdef DEBUG
+ printf(" %8g midrv\n", midrv);
+ printf(" %8g failedrv\n", failedrv);
+ printf(" %8g revrv\n", revrv);
+#endif
+#endif
+ printf("%9.8g states, matched\n", truncs);
+#ifdef CHECK
+ printf("%9.8g matches within stack\n",truncs2);
+#endif
+ if (nShadow>0)
+ printf("%9.8g transitions (= visited+matched)\n",
+ nstates+truncs);
+ else
+ printf("%9.8g transitions (= stored+matched)\n",
+ nstates+truncs);
+ printf("%9.8g atomic steps\n", nlinks);
+ if (nlost) printf("%g lost messages\n", (double) nlost);
+
+#ifndef BITSTATE
+ printf("hash conflicts: %9.8g (resolved)\n", hcmp);
+ #ifndef AUTO_RESIZE
+ if (hcmp > (double) (1<<ssize))
+ { printf("hint: increase hashtable-size (-w) to reduce runtime\n");
+ } /* in multi-core: also reduces lock delays on access to hashtable */
+ #endif
+#else
+#ifdef CHECK
+ printf("%8g states allocated for dfs stack\n", ngrabs);
+#endif
+ if (udmem)
+ printf("\nhash factor: %4g (best if > 100.)\n\n",
+ (double)(((double) udmem) * 8.0) / (double) nstates);
+ else
+ printf("\nhash factor: %4g (best if > 100.)\n\n",
+ (double)(1<<(ssize-8)) / (double) nstates * 256.0);
+ printf("bits set per state: %u (-k%u)\n", hfns, hfns);
+ #if 0
+ if (udmem)
+ { printf("total bits available: %8g (-M%ld)\n",
+ ((double) udmem) * 8.0, udmem/(1024L*1024L));
+ } else
+ printf("total bits available: %8g (-w%d)\n",
+ ((double) (ONE_L << (ssize-4)) * 16.0), ssize);
+ #endif
+#endif
+#ifdef BFS_DISK
+ printf("bfs disk reads: %ld writes %ld -- diff %ld\n",
+ bfs_dsk_reads, bfs_dsk_writes, bfs_dsk_writes-bfs_dsk_reads);
+ if (bfs_dsk_read >= 0) (void) close(bfs_dsk_read);
+ if (bfs_dsk_write >= 0) (void) close(bfs_dsk_write);
+ (void) unlink("pan_bfs_dsk.tmp");
+#endif
+}
+
+void
+wrapup(void)
+{
+#if defined(BITSTATE) || !defined(NOCOMP)
+ double nr1, nr2, nr3 = 0.0, nr4, nr5 = 0.0;
+ #if !defined(MA) && (defined(MEMCNT) || defined(MEMLIM))
+ int mverbose = 1;
+ #else
+ int mverbose = verbose;
+ #endif
+#endif
+#if NCORE>1
+ if (verbose) cpu_printf("wrapup -- %d error(s)\n", errors);
+ if (core_id != 0)
+ {
+#ifdef USE_DISK
+ void dsk_stats(void);
+ dsk_stats();
+#endif
+ if (search_terminated != NULL)
+ { *search_terminated |= 2; /* wrapup */
+ }
+ exit(0); /* normal termination, not an error */
+ }
+#endif
+#if !defined(WIN32) && !defined(WIN64)
+ signal(SIGINT, SIG_DFL);
+#endif
+ printf("\n(%s)\n", SpinVersion);
+ if (!done) printf("Warning: Search not completed\n");
+#ifdef SC
+ (void) unlink((const char *)stackfile);
+#endif
+#if NCORE>1
+ if (a_cycles)
+ { printf(" + Multi-Core (NCORE=%d)\n", NCORE);
+ } else
+ { printf(" + Multi-Core (NCORE=%d -z%d)\n", NCORE, z_handoff);
+ }
+#endif
+#ifdef BFS
+ printf(" + Using Breadth-First Search\n");
+#endif
+#ifndef NOREDUCE
+ printf(" + Partial Order Reduction\n");
+#endif
+#ifdef REVERSE
+ printf(" + Reverse Depth-First Search Order\n");
+#endif
+#ifdef T_REVERSE
+ printf(" + Reverse Transition Ordering\n");
+#endif
+#ifdef RANDOMIZE
+ printf(" + Randomized Transition Ordering\n");
+#endif
+#ifdef SCHED
+ printf(" + Scheduling Restriction (-DSCHED=%d)\n", sched_max);
+#endif
+#ifdef COLLAPSE
+ printf(" + Compression\n");
+#endif
+#ifdef MA
+ printf(" + Graph Encoding (-DMA=%d)\n", MA);
+ #ifdef R_XPT
+ printf(" Restarted from checkpoint %s.xpt\n", PanSource);
+ #endif
+#endif
+#ifdef CHECK
+ #ifdef FULLSTACK
+ printf(" + FullStack Matching\n");
+ #endif
+ #ifdef CNTRSTACK
+ printf(" + CntrStack Matching\n");
+ #endif
+#endif
+#ifdef BITSTATE
+ printf("\nBit statespace search for:\n");
+#else
+#ifdef HC
+ printf("\nHash-Compact %d search for:\n", HC);
+#else
+ printf("\nFull statespace search for:\n");
+#endif
+#endif
+#ifdef EVENT_TRACE
+#ifdef NEGATED_TRACE
+ printf(" notrace assertion +\n");
+#else
+ printf(" trace assertion +\n");
+#endif
+#endif
+#ifdef VERI
+ printf(" never claim +\n");
+ printf(" assertion violations ");
+ if (noasserts)
+ printf("- (disabled by -A flag)\n");
+ else
+ printf("+ (if within scope of claim)\n");
+#else
+#ifdef NOCLAIM
+ printf(" never claim - (not selected)\n");
+#else
+ printf(" never claim - (none specified)\n");
+#endif
+ printf(" assertion violations ");
+ if (noasserts)
+ printf("- (disabled by -A flag)\n");
+ else
+ printf("+\n");
+#endif
+#ifndef SAFETY
+#ifdef NP
+ printf(" non-progress cycles ");
+#else
+ printf(" acceptance cycles ");
+#endif
+ if (a_cycles)
+ printf("+ (fairness %sabled)\n",
+ fairness?"en":"dis");
+ else printf("- (not selected)\n");
+#else
+ printf(" cycle checks - (disabled by -DSAFETY)\n");
+#endif
+#ifdef VERI
+ printf(" invalid end states - ");
+ printf("(disabled by ");
+ if (noends)
+ printf("-E flag)\n\n");
+ else
+ printf("never claim)\n\n");
+#else
+ printf(" invalid end states ");
+ if (noends)
+ printf("- (disabled by -E flag)\n\n");
+ else
+ printf("+\n\n");
+#endif
+ printf("State-vector %d byte, depth reached %ld", hmax,
+#if NCORE>1
+ (nr_handoffs * z_handoff) +
+#endif
+ mreached);
+ printf(", errors: %d\n", errors);
+ fflush(stdout);
+#ifdef MA
+ if (done)
+ { extern void dfa_stats(void);
+ if (maxgs+a_cycles+2 < MA)
+ printf("MA stats: -DMA=%d is sufficient\n",
+ maxgs+a_cycles+2);
+ dfa_stats();
+ }
+#endif
+ wrap_stats();
+#ifdef CHECK
+ printf("stackframes: %d/%d\n\n", smax, svmax);
+ printf("stats: fa %d, fh %d, zh %d, zn %d - ",
+ Fa, Fh, Zh, Zn);
+ printf("check %d holds %d\n", Ccheck, Cholds);
+ printf("stack stats: puts %d, probes %d, zaps %d\n",
+ PUT, PROBE, ZAPS);
+#else
+ printf("\n");
+#endif
+
+#if defined(BITSTATE) || !defined(NOCOMP)
+ nr1 = (nstates-nShadow)*
+ (double)(hmax+sizeof(struct H_el)-sizeof(unsigned));
+#ifdef BFS
+ nr2 = 0.0;
+#else
+ nr2 = (double) ((maxdepth+3)*sizeof(Trail));
+#endif
+#ifndef BITSTATE
+#if !defined(MA) || defined(COLLAPSE)
+ nr3 = (double) (ONE_L<<ssize)*sizeof(struct H_el *);
+#endif
+#else
+ if (udmem)
+ nr3 = (double) (udmem);
+ else
+ nr3 = (double) (ONE_L<<(ssize-3));
+#ifdef CNTRSTACK
+ nr5 = (double) (ONE_L<<(ssize-3));
+#endif
+#ifdef FULLSTACK
+ nr5 = (double) (maxdepth*sizeof(struct H_el *));
+#endif
+#endif
+ nr4 = (double) (svmax * (sizeof(Svtack) + hmax))
+ + (double) (smax * (sizeof(Stack) + Maxbody));
+#ifndef MA
+ if (mverbose || memcnt < nr1+nr2+nr3+nr4+nr5)
+#endif
+ { double remainder = memcnt;
+ double tmp_nr = memcnt-nr3-nr4-(nr2-fragment)-nr5;
+#if NCORE>1 && !defined(SEP_STATE)
+ tmp_nr -= ((double) NCORE * LWQ_SIZE) + GWQ_SIZE;
+#endif
+ if (tmp_nr < 0.0) tmp_nr = 0.;
+ printf("Stats on memory usage (in Megabytes):\n");
+ printf("%9.3f equivalent memory usage for states",
+ nr1/1048576.); /* 1024*1024=1048576 */
+ printf(" (stored*(State-vector + overhead))\n");
+ #if NCORE>1 && !defined(WIN32) && !defined(WIN64)
+ printf("%9.3f shared memory reserved for state storage\n",
+ mem_reserved/1048576.);
+ #ifdef SEP_HEAP
+ printf(" in %d local heaps of %7.3f MB each\n",
+ NCORE, mem_reserved/(NCORE*1048576.));
+ #endif
+ printf("\n");
+ #endif
+#ifdef BITSTATE
+ if (udmem)
+ printf("%9.3f memory used for hash array (-M%ld)\n",
+ nr3/1048576., udmem/(1024L*1024L));
+ else
+ printf("%9.3f memory used for hash array (-w%d)\n",
+ nr3/1048576., ssize);
+ if (nr5 > 0.0)
+ printf("%9.3f memory used for bit stack\n",
+ nr5/1048576.);
+ remainder = remainder - nr3 - nr5;
+#else
+ printf("%9.3f actual memory usage for states",
+ tmp_nr/1048576.);
+ remainder -= tmp_nr;
+ printf(" (");
+ if (tmp_nr > 0.)
+ { if (tmp_nr > nr1) printf("unsuccessful ");
+ printf("compression: %.2f%%)\n",
+ (100.0*tmp_nr)/nr1);
+ } else
+ printf("less than 1k)\n");
+#ifndef MA
+ if (tmp_nr > 0.)
+ { printf(" state-vector as stored = %.0f byte",
+ (tmp_nr)/(nstates-nShadow) -
+ (double) (sizeof(struct H_el) - sizeof(unsigned)));
+ printf(" + %ld byte overhead\n",
+ (long int) sizeof(struct H_el)-sizeof(unsigned));
+ }
+#endif
+#if !defined(MA) || defined(COLLAPSE)
+ printf("%9.3f memory used for hash table (-w%d)\n",
+ nr3/1048576., ssize);
+ remainder -= nr3;
+#endif
+#endif
+#ifndef BFS
+ printf("%9.3f memory used for DFS stack (-m%ld)\n",
+ nr2/1048576., maxdepth);
+ remainder -= nr2;
+#endif
+#if NCORE>1
+ remainder -= ((double) NCORE * LWQ_SIZE) + GWQ_SIZE;
+ printf("%9.3f shared memory used for work-queues\n",
+ (GWQ_SIZE + (double) NCORE * LWQ_SIZE) /1048576.);
+ printf(" in %d queues of %7.3f MB each",
+ NCORE, (double) LWQ_SIZE /1048576.);
+ #ifndef NGQ
+ printf(" + a global q of %7.3f MB\n",
+ (double) GWQ_SIZE / 1048576.);
+ #else
+ printf("\n");
+ #endif
+ #endif
+ if (remainder - fragment > 1048576.)
+ printf("%9.3f other (proc and chan stacks)\n",
+ (remainder-fragment)/1048576.);
+ if (fragment > 1048576.)
+ printf("%9.3f memory lost to fragmentation\n",
+ fragment/1048576.);
+ printf("%9.3f total actual memory usage\n\n",
+ memcnt/1048576.);
+ }
+#ifndef MA
+ else
+#endif
+#endif
+#ifndef MA
+ printf("%9.3f memory usage (Mbyte)\n\n",
+ memcnt/1048576.);
+#endif
+#ifdef COLLAPSE
+ printf("nr of templates: [ globals chans procs ]\n");
+ printf("collapse counts: [ ");
+ { int i; for (i = 0; i < 256+2; i++)
+ if (ncomps[i] != 0)
+ printf("%d ", ncomps[i]);
+ printf("]\n");
+ }
+#endif
+ if ((done || verbose) && !no_rck) do_reach();
+#ifdef PEG
+ { int i;
+ printf("\nPeg Counts (transitions executed):\n");
+ for (i = 1; i < NTRANS; i++)
+ { if (peg[i]) putpeg(i, peg[i]);
+ } }
+#endif
+#ifdef VAR_RANGES
+ dumpranges();
+#endif
+#ifdef SVDUMP
+ if (vprefix > 0) close(svfd);
+#endif
+#ifdef LOOPSTATE
+ printf("%g loopstates hit\n", cnt_loops);
+#endif
+#ifdef NSUCC
+ dump_succ();
+#endif
+#if NCORE>1 && defined(T_ALERT)
+ crash_report();
+#endif
+ pan_exit(0);
+}
+
+void
+stopped(int arg)
+{ printf("Interrupted\n");
+#if NCORE>1
+ was_interrupted = 1;
+#endif
+ wrapup();
+ pan_exit(0);
+}
+
+#ifdef SFH
+/*
+ * super fast hash, based on Paul Hsieh's function
+ * http://www.azillionmonkeys.com/qed/hash.html
+ */
+#include <stdint.h>
+ #undef get16bits
+ #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
+ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+ #define get16bits(d) (*((const uint16_t *) (d)))
+ #endif
+
+ #ifndef get16bits
+ #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+ +(uint32_t)(((const uint8_t *)(d))[0]) )
+ #endif
+
+void
+d_sfh(const char *s, int len)
+{ uint32_t h = len, tmp;
+ int rem;
+
+ rem = len & 3;
+ len >>= 2;
+
+ for ( ; len > 0; len--)
+ { h += get16bits(s);
+ tmp = (get16bits(s+2) << 11) ^ h;
+ h = (h << 16) ^ tmp;
+ s += 2*sizeof(uint16_t);
+ h += h >> 11;
+ }
+ switch (rem) {
+ case 3: h += get16bits(s);
+ h ^= h << 16;
+ h ^= s[sizeof(uint16_t)] << 18;
+ h += h >> 11;
+ break;
+ case 2: h += get16bits(s);
+ h ^= h << 11;
+ h += h >> 17;
+ break;
+ case 1: h += *s;
+ h ^= h << 10;
+ h += h >> 1;
+ break;
+ }
+ h ^= h << 3;
+ h += h >> 5;
+ h ^= h << 4;
+ h += h >> 17;
+ h ^= h << 25;
+ h += h >> 6;
+
+ K1 = h;
+}
+#endif
+
+#include <stdint.h>
+#if defined(HASH64) || defined(WIN64)
+/* 64-bit Jenkins hash, 1997
+ * http://burtleburtle.net/bob/c/lookup8.c
+ */
+#define mix(a,b,c) \
+{ a -= b; a -= c; a ^= (c>>43); \
+ b -= c; b -= a; b ^= (a<<9); \
+ c -= a; c -= b; c ^= (b>>8); \
+ a -= b; a -= c; a ^= (c>>38); \
+ b -= c; b -= a; b ^= (a<<23); \
+ c -= a; c -= b; c ^= (b>>5); \
+ a -= b; a -= c; a ^= (c>>35); \
+ b -= c; b -= a; b ^= (a<<49); \
+ c -= a; c -= b; c ^= (b>>11); \
+ a -= b; a -= c; a ^= (c>>12); \
+ b -= c; b -= a; b ^= (a<<18); \
+ c -= a; c -= b; c ^= (b>>22); \
+}
+#else
+/* 32-bit Jenkins hash, 2006
+ * http://burtleburtle.net/bob/c/lookup3.c
+ */
+#define rot(x,k) (((x)<<(k))|((x)>>(32-(k))))
+
+#define mix(a,b,c) \
+{ a -= c; a ^= rot(c, 4); c += b; \
+ b -= a; b ^= rot(a, 6); a += c; \
+ c -= b; c ^= rot(b, 8); b += a; \
+ a -= c; a ^= rot(c,16); c += b; \
+ b -= a; b ^= rot(a,19); a += c; \
+ c -= b; c ^= rot(b, 4); b += a; \
+}
+
+#define final(a,b,c) \
+{ c ^= b; c -= rot(b,14); \
+ a ^= c; a -= rot(c,11); \
+ b ^= a; b -= rot(a,25); \
+ c ^= b; c -= rot(b,16); \
+ a ^= c; a -= rot(c,4); \
+ b ^= a; b -= rot(a,14); \
+ c ^= b; c -= rot(b,24); \
+}
+#endif
+
+void
+d_hash(uchar *kb, int nbytes)
+{ uint8_t *bp;
+#if defined(HASH64) || defined(WIN64)
+ uint64_t a = 0, b, c, n;
+ uint64_t *k = (uint64_t *) kb;
+#else
+ uint32_t a, b, c, n;
+ uint32_t *k = (uint32_t *) kb;
+#endif
+ /* extend to multiple of words, if needed */
+ n = nbytes/WS; /* nr of words */
+ a = nbytes - (n*WS);
+ if (a > 0)
+ { n++;
+ bp = kb + nbytes;
+ switch (a) {
+ case 3: *bp++ = 0; /* fall thru */
+ case 2: *bp++ = 0; /* fall thru */
+ case 1: *bp = 0;
+ case 0: break;
+ } }
+#if defined(HASH64) || defined(WIN64)
+ b = HASH_CONST[HASH_NR];
+ c = 0x9e3779b97f4a7c13LL; /* arbitrary value */
+ while (n >= 3)
+ { a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ n -= 3;
+ k += 3;
+ }
+ c += (((uint64_t) nbytes)<<3);
+ switch (n) {
+ case 2: b += k[1];
+ case 1: a += k[0];
+ case 0: break;
+ }
+ mix(a,b,c);
+#else
+ a = c = 0xdeadbeef + (n<<2);
+ b = HASH_CONST[HASH_NR];
+ while (n > 3)
+ { a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ n -= 3;
+ k += 3;
+ }
+ switch (n) {
+ case 3: c += k[2];
+ case 2: b += k[1];
+ case 1: a += k[0];
+ case 0: break;
+ }
+ final(a,b,c);
+#endif
+ j1 = c&nmask; j3 = a&7; /* 1st bit */
+ j2 = b&nmask; j4 = (a>>3)&7; /* 2nd bit */
+ K1 = c; K2 = b;
+}
+
+void
+s_hash(uchar *cp, int om)
+{
+#if defined(SFH)
+ d_sfh((const char *) cp, om); /* sets K1 */
+#else
+ d_hash(cp, om); /* sets K1 etc */
+#endif
+#ifdef BITSTATE
+ if (S_Tab == H_tab)
+ j1 = K1 % omaxdepth;
+ else
+#endif
+ if (ssize < 8*WS)
+ j1 = K1&mask;
+ else
+ j1 = K1;
+}
+#ifndef RANDSTOR
+int *prerand;
+void
+inirand(void)
+{ int i;
+ srand(123); /* fixed startpoint */
+ prerand = (int *) emalloc((omaxdepth+3)*sizeof(int));
+ for (i = 0; i < omaxdepth+3; i++)
+ prerand[i] = rand();
+}
+int
+pan_rand(void)
+{ if (!prerand) inirand();
+ return prerand[depth];
+}
+#endif
+
+void
+set_masks(void) /* 4.2.5 */
+{
+ if (WS == 4 && ssize >= 32)
+ { mask = 0xffffffff;
+#ifdef BITSTATE
+ switch (ssize) {
+ case 34: nmask = (mask>>1); break;
+ case 33: nmask = (mask>>2); break;
+ default: nmask = (mask>>3); break;
+ }
+#else
+ nmask = mask;
+#endif
+ } else if (WS == 8)
+ { mask = ((ONE_L<<ssize)-1); /* hash init */
+#ifdef BITSTATE
+ nmask = mask>>3;
+#else
+ nmask = mask;
+#endif
+ } else if (WS != 4)
+ { fprintf(stderr, "pan: wordsize %ld not supported\n", (long int) WS);
+ exit(1);
+ } else /* WS == 4 and ssize < 32 */
+ { mask = ((ONE_L<<ssize)-1); /* hash init */
+ nmask = (mask>>3);
+ }
+}
+
+static long reclaim_size;
+static char *reclaim_mem;
+#if defined(AUTO_RESIZE) && !defined(BITSTATE) && !defined(MA)
+#if NCORE>1
+ #error cannot combine AUTO_RESIZE with NCORE>1 yet
+#endif
+static struct H_el **N_tab;
+void
+reverse_capture(struct H_el *p)
+{ if (!p) return;
+ reverse_capture(p->nxt);
+ /* last element of list moves first */
+ /* to preserve list-order */
+ j2 = p->m_K1;
+ if (ssize < 8*WS) /* probably always true */
+ { j2 &= mask;
+ }
+ p->nxt = N_tab[j2];
+ N_tab[j2] = p;
+}
+void
+resize_hashtable(void)
+{
+ if (WS == 4 && ssize >= 27 - 1)
+ { return; /* canot increase further */
+ }
+
+ ssize += 2; /* 4x size */
+
+ printf("pan: resizing hashtable to -w%d.. ", ssize);
+
+ N_tab = (struct H_el **)
+ emalloc((ONE_L<<ssize)*sizeof(struct H_el *));
+
+ set_masks(); /* they changed */
+
+ for (j1 = 0; j1 < (ONE_L << (ssize - 2)); j1++)
+ { reverse_capture(H_tab[j1]);
+ }
+ reclaim_mem = (char *) H_tab;
+ reclaim_size = (ONE_L << (ssize - 2));
+ H_tab = N_tab;
+
+ printf(" done\n");
+}
+#endif
+#if defined(ZAPH) && defined(BITSTATE)
+void
+zap_hashtable(void)
+{ cpu_printf("pan: resetting hashtable\n");
+ if (udmem)
+ { memset(SS, 0, udmem);
+ } else
+ { memset(SS, 0, ONE_L<<(ssize-3));
+ }
+}
+#endif
+
+int
+main(int argc, char *argv[])
+{ void to_compile(void);
+
+ efd = stderr; /* default */
+#ifdef BITSTATE
+ bstore = bstore_reg; /* default */
+#endif
+#if NCORE>1
+ { int i, j;
+ strcpy(o_cmdline, "");
+ for (j = 1; j < argc; j++)
+ { strcat(o_cmdline, argv[j]);
+ strcat(o_cmdline, " ");
+ }
+ /* printf("Command Line: %s\n", o_cmdline); */
+ if (strlen(o_cmdline) >= sizeof(o_cmdline))
+ { Uerror("option list too long");
+ } }
+#endif
+ while (argc > 1 && argv[1][0] == '-')
+ { switch (argv[1][1]) {
+#ifndef SAFETY
+#ifdef NP
+ case 'a': fprintf(efd, "error: -a disabled");
+ usage(efd); break;
+#else
+ case 'a': a_cycles = 1; break;
+#endif
+#endif
+ case 'A': noasserts = 1; break;
+ case 'b': bounded = 1; break;
+#ifdef HAS_CODE
+ case 'C': coltrace = 1; goto samething;
+#endif
+ case 'c': upto = atoi(&argv[1][2]); break;
+ case 'd': state_tables++; break;
+ case 'e': every_error = 1; Nr_Trails = 1; break;
+ case 'E': noends = 1; break;
+#ifdef SC
+ case 'F': if (strlen(argv[1]) > 2)
+ stackfile = &argv[1][2];
+ break;
+#endif
+#if !defined(SAFETY) && !defined(NOFAIR)
+ case 'f': fairness = 1; break;
+#endif
+#ifdef HAS_CODE
+ case 'g': gui = 1; goto samething;
+#endif
+ case 'h': if (!argv[1][2]) usage(efd); else
+ HASH_NR = atoi(&argv[1][2])%33; break;
+ case 'I': iterative = 2; every_error = 1; break;
+ case 'i': iterative = 1; every_error = 1; break;
+ case 'J': like_java = 1; break; /* Klaus Havelund */
+#ifdef BITSTATE
+ case 'k': hfns = atoi(&argv[1][2]); break;
+#endif
+#ifdef SCHED
+ case 'L': sched_max = atoi(&argv[1][2]); break;
+#endif
+#ifndef SAFETY
+#ifdef NP
+ case 'l': a_cycles = 1; break;
+#else
+ case 'l': fprintf(efd, "error: -l disabled");
+ usage(efd); break;
+#endif
+#endif
+#ifdef BITSTATE
+ case 'M': udmem = atoi(&argv[1][2]); break;
+ case 'G': udmem = atoi(&argv[1][2]); udmem *= 1024; break;
+#else
+ case 'M': case 'G':
+ fprintf(stderr, "-M and -G affect only -DBITSTATE\n");
+ break;
+#endif
+ case 'm': maxdepth = atoi(&argv[1][2]); break;
+ case 'n': no_rck = 1; break;
+ case 'P': readtrail = 1; onlyproc = atoi(&argv[1][2]);
+ if (argv[2][0] != '-') /* check next arg */
+ { trailfilename = argv[2];
+ argc--; argv++; /* skip next arg */
+ }
+ break;
+#ifdef SVDUMP
+ case 'p': vprefix = atoi(&argv[1][2]); break;
+#endif
+#if NCORE==1
+ case 'Q': quota = (double) 60.0 * (double) atoi(&argv[1][2]); break;
+#endif
+ case 'q': strict = 1; break;
+ case 'R': Nrun = atoi(&argv[1][2]); break;
+#ifdef HAS_CODE
+ case 'r':
+samething: readtrail = 1;
+ if (isdigit(argv[1][2]))
+ whichtrail = atoi(&argv[1][2]);
+ else if (argc > 2 && argv[2][0] != '-') /* check next arg */
+ { trailfilename = argv[2];
+ argc--; argv++; /* skip next arg */
+ }
+ break;
+ case 'S': silent = 1; goto samething;
+#endif
+#ifdef BITSTATE
+ case 's': hfns = 1; break;
+#endif
+ case 'T': TMODE = 0444; break;
+ case 't': if (argv[1][2]) tprefix = &argv[1][2]; break;
+ case 'V': start_timer(); printf("Generated by %s\n", SpinVersion);
+ to_compile(); pan_exit(2); break;
+ case 'v': verbose++; break;
+ case 'w': ssize = atoi(&argv[1][2]); break;
+ case 'Y': signoff = 1; break;
+ case 'X': efd = stdout; break;
+ case 'x': exclusive = 1; break;
+#if NCORE>1
+ /* -B ip is passthru to proxy of remote ip address: */
+ case 'B': argc--; argv++; break;
+ case 'Q': worker_pids[0] = atoi(&argv[1][2]); break;
+ /* -Un means that the nth worker should be instantiated as a proxy */
+ case 'U': proxy_pid = atoi(&argv[1][2]); break;
+ /* -W means that this copy is started by a cluster-server as a remote */
+ /* this flag is passed to ./pan_proxy, which interprets it */
+ case 'W': remote_party++; break;
+ case 'Z': core_id = atoi(&argv[1][2]);
+ if (verbose)
+ { printf("cpu%d: pid %d parent %d\n",
+ core_id, getpid(), worker_pids[0]);
+ }
+ break;
+ case 'z': z_handoff = atoi(&argv[1][2]); break;
+#else
+ case 'z': break; /* ignored for single-core */
+#endif
+ default : fprintf(efd, "saw option -%c\n", argv[1][1]); usage(efd); break;
+ }
+ argc--; argv++;
+ }
+ if (iterative && TMODE != 0666)
+ { TMODE = 0666;
+ fprintf(efd, "warning: -T ignored when -i or -I is used\n");
+ }
+#if defined(HASH32) && !defined(SFH)
+ if (WS > 4)
+ { fprintf(efd, "strong warning: compiling -DHASH32 on a 64-bit machine\n");
+ fprintf(efd, " without -DSFH can slow down performance a lot\n");
+ }
+#endif
+#if defined(WIN32) || defined(WIN64)
+ if (TMODE == 0666)
+ TMODE = _S_IWRITE | _S_IREAD;
+ else
+ TMODE = _S_IREAD;
+#endif
+#if NCORE>1
+ store_proxy_pid = proxy_pid; /* for checks in mem_file() and someone_crashed() */
+ if (core_id != 0) { proxy_pid = 0; }
+ #ifndef SEP_STATE
+ if (core_id == 0 && a_cycles)
+ { fprintf(efd, "hint: this search may be more efficient ");
+ fprintf(efd, "if pan.c is compiled -DSEP_STATE\n");
+ }
+ #endif
+ if (z_handoff < 0)
+ { z_handoff = 20; /* conservative default - for non-liveness checks */
+ }
+#if defined(NGQ) || defined(LWQ_FIXED)
+ LWQ_SIZE = (double) (128.*1048576.);
+#else
+ LWQ_SIZE = (double) ( z_handoff + 2.) * (double) sizeof(SM_frame);
+#endif
+ #if NCORE>2
+ if (a_cycles)
+ { fprintf(efd, "warning: the intended nr of cores to be used in liveness mode is 2\n");
+ #ifndef SEP_STATE
+ fprintf(efd, "warning: without -DSEP_STATE there is no guarantee that all liveness violations are found\n");
+ #endif
+ }
+ #endif
+ #ifdef HAS_HIDDEN
+ #error cannot use hidden variables when compiling multi-core
+ #endif
+#endif
+#ifdef BITSTATE
+ if (hfns <= 0)
+ { hfns = 1;
+ fprintf(efd, "warning: using -k%d as minimal usable value\n", hfns);
+ }
+#endif
+ omaxdepth = maxdepth;
+#ifdef BITSTATE
+ if (WS == 4 && ssize > 34)
+ { ssize = 34;
+ fprintf(efd, "warning: using -w%d as max usable value\n", ssize);
+/*
+ * -w35 would not work: 35-3 = 32 but 1^31 is the largest
+ * power of 2 that can be represented in an unsigned long
+ */
+ }
+#else
+ if (WS == 4 && ssize > 27)
+ { ssize = 27;
+ fprintf(efd, "warning: using -w%d as max usable value\n", ssize);
+/*
+ * for emalloc, the lookup table size multiplies by 4 for the pointers
+ * the largest power of 2 that can be represented in a ulong is 1^31
+ * hence the largest number of lookup table slots is 31-4 = 27
+ */
+ }
+#endif
+#ifdef SC
+ hiwater = HHH = maxdepth-10;
+ DDD = HHH/2;
+ if (!stackfile)
+ { stackfile = (char *) emalloc(strlen(PanSource)+4+1);
+ sprintf(stackfile, "%s._s_", PanSource);
+ }
+ if (iterative)
+ { fprintf(efd, "error: cannot use -i or -I with -DSC\n");
+ pan_exit(1);
+ }
+#endif
+#if (defined(R_XPT) || defined(W_XPT)) && !defined(MA)
+ #warning -DR_XPT and -DW_XPT assume -DMA (ignored)
+#endif
+ if (iterative && a_cycles)
+ fprintf(efd, "warning: -i or -I work for safety properties only\n");
+#ifdef BFS
+ #ifdef SC
+ #error -DBFS not compatible with -DSC
+ #endif
+ #ifdef HAS_LAST
+ #error -DBFS not compatible with _last
+ #endif
+ #ifdef HAS_STACK
+ #error cannot use c_track UnMatched with BFS
+ #endif
+ #ifdef REACH
+ #warning -DREACH is redundant when -DBFS is used
+ #endif
+#endif
+#if defined(MERGED) && defined(PEG)
+ #error to use -DPEG use: spin -o3 -a
+#endif
+#ifdef HC
+ #ifdef SFH
+ #error cannot combine -DHC and -DSFH
+ /* use of NOCOMP is the real reason */
+ #else
+ #ifdef NOCOMP
+ #error cannot combine -DHC and -DNOCOMP
+ #endif
+ #endif
+ #ifdef BITSTATE
+ #error cannot combine -DHC and -DBITSTATE
+ #endif
+#endif
+#if defined(SAFETY) && defined(NP)
+ #error cannot combine -DNP and -DBFS or -DSAFETY
+#endif
+#ifdef MA
+ #ifdef BITSTATE
+ #error cannot combine -DMA and -DBITSTATE
+ #endif
+ #if MA <= 0
+ #error usage: -DMA=N with N > 0 and N < VECTORSZ
+ #endif
+#endif
+#ifdef COLLAPSE
+ #ifdef BITSTATE
+ #error cannot combine -DBITSTATE and -DCOLLAPSE
+ #endif
+ #ifdef SFH
+ #error cannot combine -DCOLLAPSE and -DSFH
+ /* use of NOCOMP is the real reason */
+ #else
+ #ifdef NOCOMP
+ #error cannot combine -DCOLLAPSE and -DNOCOMP
+ #endif
+ #endif
+#endif
+ if (maxdepth <= 0 || ssize <= 1) usage(efd);
+#if SYNC>0 && !defined(NOREDUCE)
+ if (a_cycles && fairness)
+ { fprintf(efd, "error: p.o. reduction not compatible with ");
+ fprintf(efd, "fairness (-f) in models\n");
+ fprintf(efd, " with rendezvous operations: ");
+ fprintf(efd, "recompile with -DNOREDUCE\n");
+ pan_exit(1);
+ }
+#endif
+#if defined(REM_VARS) && !defined(NOREDUCE)
+ #warning p.o. reduction not compatible with remote varrefs (use -DNOREDUCE)
+#endif
+#if defined(NOCOMP) && !defined(BITSTATE)
+ if (a_cycles)
+ { fprintf(efd, "error: use of -DNOCOMP voids -l and -a\n");
+ pan_exit(1);
+ }
+#endif
+#ifdef MEMLIM
+ memlim = ((double) MEMLIM) * (double) (1<<20); /* size in Mbyte */
+#endif
+#ifndef BITSTATE
+ if (Nrun > 1) HASH_NR = Nrun - 1;
+#endif
+ if (Nrun < 1 || Nrun > 32)
+ { fprintf(efd, "error: invalid arg for -R\n");
+ usage(efd);
+ }
+#ifndef SAFETY
+ if (fairness && !a_cycles)
+ { fprintf(efd, "error: -f requires -a or -l\n");
+ usage(efd);
+ }
+ #if ACCEPT_LAB==0
+ if (a_cycles)
+ { fprintf(efd, "error: no accept labels defined ");
+ fprintf(efd, "in model (for option -a)\n");
+ usage(efd);
+ }
+ #endif
+#endif
+#ifndef NOREDUCE
+ #ifdef HAS_ENABLED
+ #error use of enabled() requires -DNOREDUCE
+ #endif
+ #ifdef HAS_PCVALUE
+ #error use of pcvalue() requires -DNOREDUCE
+ #endif
+ #ifdef HAS_BADELSE
+ #error use of 'else' combined with i/o stmnts requires -DNOREDUCE
+ #endif
+ #ifdef HAS_LAST
+ #error use of _last requires -DNOREDUCE
+ #endif
+#endif
+#if SYNC>0 && !defined(NOREDUCE)
+ #ifdef HAS_UNLESS
+ fprintf(efd, "warning: use of a rendezvous stmnts in the escape\n");
+ fprintf(efd, " of an unless clause, if present, could make p.o. reduction\n");
+ fprintf(efd, " invalid (use -DNOREDUCE to avoid this)\n");
+ #ifdef BFS
+ fprintf(efd, " (this type of rv is also not compatible with -DBFS)\n");
+ #endif
+ #endif
+#endif
+#if SYNC>0 && defined(BFS)
+ #warning use of rendezvous with BFS does not preserve all invalid endstates
+#endif
+#if !defined(REACH) && !defined(BITSTATE)
+ if (iterative != 0 && a_cycles == 0)
+ { fprintf(efd, "warning: -i and -I need -DREACH to work accurately\n");
+ }
+#endif
+#if defined(BITSTATE) && defined(REACH)
+ #warning -DREACH is voided by -DBITSTATE
+#endif
+#if defined(MA) && defined(REACH)
+ #warning -DREACH is voided by -DMA
+#endif
+#if defined(FULLSTACK) && defined(CNTRSTACK)
+ #error cannot combine -DFULLSTACK and -DCNTRSTACK
+#endif
+#if defined(VERI)
+ #if ACCEPT_LAB>0
+ #ifndef BFS
+ if (!a_cycles
+ #ifdef HAS_CODE
+ && !readtrail
+ #endif
+ #if NCORE>1
+ && core_id == 0
+ #endif
+ && !state_tables)
+ { fprintf(efd, "warning: never claim + accept labels ");
+ fprintf(efd, "requires -a flag to fully verify\n");
+ }
+ #else
+ if (!state_tables
+ #ifdef HAS_CODE
+ && !readtrail
+ #endif
+ )
+ { fprintf(efd, "warning: verification in BFS mode ");
+ fprintf(efd, "is restricted to safety properties\n");
+ }
+ #endif
+ #endif
+#endif
+#ifndef SAFETY
+ if (!a_cycles
+ #ifdef HAS_CODE
+ && !readtrail
+ #endif
+ #if NCORE>1
+ && core_id == 0
+ #endif
+ && !state_tables)
+ { fprintf(efd, "hint: this search is more efficient ");
+ fprintf(efd, "if pan.c is compiled -DSAFETY\n");
+ }
+ #ifndef NOCOMP
+ if (!a_cycles)
+ { S_A = 0;
+ } else
+ { if (!fairness)
+ { S_A = 1; /* _a_t */
+ #ifndef NOFAIR
+ } else /* _a_t and _cnt[NFAIR] */
+ { S_A = (&(now._cnt[0]) - (uchar *) &now) + NFAIR - 2;
+ /* -2 because first two uchars in now are masked */
+ #endif
+ } }
+ #endif
+#endif
+ signal(SIGINT, stopped);
+ set_masks();
+#ifdef BFS
+ trail = (Trail *) emalloc(6*sizeof(Trail));
+ trail += 3;
+#else
+ trail = (Trail *) emalloc((maxdepth+3)*sizeof(Trail));
+ trail++; /* protect trpt-1 refs at depth 0 */
+#endif
+#ifdef SVDUMP
+ if (vprefix > 0)
+ { char nm[64];
+ sprintf(nm, "%s.svd", PanSource);
+ if ((svfd = creat(nm, TMODE)) < 0)
+ { fprintf(efd, "couldn't create %s\n", nm);
+ vprefix = 0;
+ } }
+#endif
+#ifdef RANDSTOR
+ srand(123);
+#endif
+#if SYNC>0 && ASYNC==0
+ set_recvs();
+#endif
+ run();
+ done = 1;
+ wrapup();
+ return 0;
+}
+
+void
+usage(FILE *fd)
+{
+ fprintf(fd, "%s\n", SpinVersion);
+ fprintf(fd, "Valid Options are:\n");
+#ifndef SAFETY
+#ifdef NP
+ fprintf(fd, " -a -> is disabled by -DNP ");
+ fprintf(fd, "(-DNP compiles for -l only)\n");
+#else
+ fprintf(fd, " -a find acceptance cycles\n");
+#endif
+#else
+ fprintf(fd, " -a,-l,-f -> are disabled by -DSAFETY\n");
+#endif
+ fprintf(fd, " -A ignore assert() violations\n");
+ fprintf(fd, " -b consider it an error to exceed the depth-limit\n");
+ fprintf(fd, " -cN stop at Nth error ");
+ fprintf(fd, "(defaults to -c1)\n");
+ fprintf(fd, " -d print state tables and stop\n");
+ fprintf(fd, " -e create trails for all errors\n");
+ fprintf(fd, " -E ignore invalid end states\n");
+#ifdef SC
+ fprintf(fd, " -Ffile use 'file' to store disk-stack\n");
+#endif
+#ifndef NOFAIR
+ fprintf(fd, " -f add weak fairness (to -a or -l)\n");
+#endif
+ fprintf(fd, " -hN use different hash-seed N:1..32\n");
+ fprintf(fd, " -i search for shortest path to error\n");
+ fprintf(fd, " -I like -i, but approximate and faster\n");
+ fprintf(fd, " -J reverse eval order of nested unlesses\n");
+#ifdef BITSTATE
+ fprintf(fd, " -kN set N bits per state (defaults to 3)\n");
+#endif
+#ifdef SCHED
+ fprintf(fd, " -LN set scheduling restriction to N (default 10)\n");
+#endif
+#ifndef SAFETY
+#ifdef NP
+ fprintf(fd, " -l find non-progress cycles\n");
+#else
+ fprintf(fd, " -l find non-progress cycles -> ");
+ fprintf(fd, "disabled, requires ");
+ fprintf(fd, "compilation with -DNP\n");
+#endif
+#endif
+#ifdef BITSTATE
+ fprintf(fd, " -MN use N Megabytes for bitstate hash array\n");
+ fprintf(fd, " -GN use N Gigabytes for bitstate hash array\n");
+#endif
+ fprintf(fd, " -mN max depth N steps (default=10k)\n");
+ fprintf(fd, " -n no listing of unreached states\n");
+#ifdef SVDUMP
+ fprintf(fd, " -pN create svfile (save N bytes per state)\n");
+#endif
+ fprintf(fd, " -QN set time-limit on execution of N minutes\n");
+ fprintf(fd, " -q require empty chans in valid end states\n");
+#ifdef HAS_CODE
+ fprintf(fd, " -r read and execute trail - can add -v,-n,-PN,-g,-C\n");
+ fprintf(fd, " -rN read and execute N-th error trail\n");
+ fprintf(fd, " -C read and execute trail - columnated output (can add -v,-n)\n");
+ fprintf(fd, " -PN read and execute trail - restrict trail output to proc N\n");
+ fprintf(fd, " -g read and execute trail + msc gui support\n");
+ fprintf(fd, " -S silent replay: only user defined printfs show\n");
+#endif
+#ifdef BITSTATE
+ fprintf(fd, " -RN repeat run Nx with N ");
+ fprintf(fd, "[1..32] independent hash functions\n");
+ fprintf(fd, " -s same as -k1 (single bit per state)\n");
+#endif
+ fprintf(fd, " -T create trail files in read-only mode\n");
+ fprintf(fd, " -tsuf replace .trail with .suf on trailfiles\n");
+ fprintf(fd, " -V print SPIN version number\n");
+ fprintf(fd, " -v verbose -- filenames in unreached state listing\n");
+ fprintf(fd, " -wN hashtable of 2^N entries ");
+ fprintf(fd, "(defaults to -w%d)\n", ssize);
+ fprintf(fd, " -x do not overwrite an existing trail file\n");
+#if NCORE>1
+ fprintf(fd, " -zN handoff states below depth N to 2nd cpu (multi_core)\n");
+#endif
+#ifdef HAS_CODE
+ fprintf(fd, "\n options -r, -C, -PN, -g, and -S can optionally be followed by\n");
+ fprintf(fd, " a filename argument, as in '-r filename', naming the trailfile\n");
+#endif
+#if NCORE>1
+ multi_usage(fd);
+#endif
+ exit(1);
+}
+
+char *
+Malloc(unsigned long n)
+{ char *tmp;
+#ifdef MEMLIM
+ if (memcnt+ (double) n > memlim) goto err;
+#endif
+#if 1
+ tmp = (char *) malloc(n);
+ if (!tmp)
+#else
+ tmp = (char *) sbrk(n);
+ if (tmp == (char *) -ONE_L)
+#endif
+ {
+#ifdef MEMLIM
+err:
+#endif
+ printf("pan: out of memory\n");
+#ifdef MEMLIM
+ printf(" %g bytes used\n", memcnt);
+ printf(" %g bytes more needed\n", (double) n);
+ printf(" %g bytes limit\n",
+ memlim);
+#endif
+#ifdef COLLAPSE
+ printf("hint: to reduce memory, recompile with\n");
+#ifndef MA
+ printf(" -DMA=%d # better/slower compression, or\n", hmax);
+#endif
+ printf(" -DBITSTATE # supertrace, approximation\n");
+#else
+#ifndef BITSTATE
+ printf("hint: to reduce memory, recompile with\n");
+#ifndef HC
+ printf(" -DCOLLAPSE # good, fast compression, or\n");
+#ifndef MA
+ printf(" -DMA=%d # better/slower compression, or\n", hmax);
+#endif
+ printf(" -DHC # hash-compaction, approximation\n");
+#endif
+ printf(" -DBITSTATE # supertrace, approximation\n");
+#endif
+#endif
+#if NCORE>1
+ #ifdef FULL_TRAIL
+ printf(" omit -DFULL_TRAIL or use pan -c0 to reduce memory\n");
+ #endif
+ #ifdef SEP_STATE
+ printf("hint: to reduce memory, recompile without\n");
+ printf(" -DSEP_STATE # may be faster, but uses more memory\n");
+ #endif
+#endif
+ wrapup();
+ }
+ memcnt += (double) n;
+ return tmp;
+}
+
+#define CHUNK (100*VECTORSZ)
+
+char *
+emalloc(unsigned long n) /* never released or reallocated */
+{ char *tmp;
+ if (n == 0)
+ return (char *) NULL;
+ if (n&(sizeof(void *)-1)) /* for proper alignment */
+ n += sizeof(void *)-(n&(sizeof(void *)-1));
+ if ((unsigned long) left < n)
+ { grow = (n < CHUNK) ? CHUNK : n;
+ have = Malloc(grow);
+ fragment += (double) left;
+ left = grow;
+ }
+ tmp = have;
+ have += (long) n;
+ left -= (long) n;
+ memset(tmp, 0, n);
+ return tmp;
+}
+void
+Uerror(char *str)
+{ /* always fatal */
+ uerror(str);
+#if NCORE>1
+ sudden_stop("Uerror");
+#endif
+ wrapup();
+}
+
+#if defined(MA) && !defined(SAFETY)
+int
+Unwind(void)
+{ Trans *t; uchar ot, _m; int tt; short II;
+#ifdef VERBOSE
+ int i;
+#endif
+ uchar oat = now._a_t;
+ now._a_t &= ~(1|16|32);
+ memcpy((char *) &comp_now, (char *) &now, vsize);
+ now._a_t = oat;
+Up:
+#ifdef SC
+ trpt = getframe(depth);
+#endif
+#ifdef VERBOSE
+ printf("%d State: ", depth);
+ for (i = 0; i < vsize; i++) printf("%d%s,",
+ ((char *)&now)[i], Mask[i]?"*":"");
+ printf("\n");
+#endif
+#ifndef NOFAIR
+ if (trpt->o_pm&128) /* fairness alg */
+ { now._cnt[now._a_t&1] = trpt->bup.oval;
+ depth--;
+#ifdef SC
+ trpt = getframe(depth);
+#else
+ trpt--;
+#endif
+ goto Q999;
+ }
+#endif
+#ifdef HAS_LAST
+#ifdef VERI
+ { int d; Trail *trl;
+ now._last = 0;
+ for (d = 1; d < depth; d++)
+ { trl = getframe(depth-d); /* was trl = (trpt-d); */
+ if (trl->pr != 0)
+ { now._last = trl->pr - BASE;
+ break;
+ } } }
+#else
+ now._last = (depth<1)?0:(trpt-1)->pr;
+#endif
+#endif
+#ifdef EVENT_TRACE
+ now._event = trpt->o_event;
+#endif
+ if ((now._a_t&1) && depth <= A_depth)
+ { now._a_t &= ~(1|16|32);
+ if (fairness) now._a_t |= 2; /* ? */
+ A_depth = 0;
+ goto CameFromHere; /* checkcycles() */
+ }
+ t = trpt->o_t;
+ ot = trpt->o_ot; II = trpt->pr;
+ tt = trpt->o_tt; this = pptr(II);
+ _m = do_reverse(t, II, trpt->o_m);
+#ifdef VERBOSE
+ printf("%3d: proc %d ", depth, II);
+ printf("reverses %d, %d to %d,",
+ t->forw, tt, t->st);
+ printf(" %s [abit=%d,adepth=%d,",
+ t->tp, now._a_t, A_depth);
+ printf("tau=%d,%d] <unwind>\n",
+ trpt->tau, (trpt-1)->tau);
+#endif
+ depth--;
+#ifdef SC
+ trpt = getframe(depth);
+#else
+ trpt--;
+#endif
+ /* reached[ot][t->st] = 1; 3.4.13 */
+ ((P0 *)this)->_p = tt;
+#ifndef NOFAIR
+ if ((trpt->o_pm&32))
+ {
+#ifdef VERI
+ if (now._cnt[now._a_t&1] == 0)
+ now._cnt[now._a_t&1] = 1;
+#endif
+ now._cnt[now._a_t&1] += 1;
+ }
+Q999:
+ if (trpt->o_pm&8)
+ { now._a_t &= ~2;
+ now._cnt[now._a_t&1] = 0;
+ }
+ if (trpt->o_pm&16)
+ now._a_t |= 2;
+#endif
+CameFromHere:
+ if (memcmp((char *) &now, (char *) &comp_now, vsize) == 0)
+ return depth;
+ if (depth > 0) goto Up;
+ return 0;
+}
+#endif
+static char unwinding;
+void
+uerror(char *str)
+{ static char laststr[256];
+ int is_cycle;
+
+ if (unwinding) return; /* 1.4.2 */
+ if (strncmp(str, laststr, 254))
+#if NCORE>1
+ cpu_printf("pan: %s (at depth %ld)\n", str,
+#else
+ printf("pan: %s (at depth %ld)\n", str,
+#endif
+#if NCORE>1
+ (nr_handoffs * z_handoff) +
+#endif
+ ((depthfound==-1)?depth:depthfound));
+ strncpy(laststr, str, 254);
+ errors++;
+#ifdef HAS_CODE
+ if (readtrail) { wrap_trail(); return; }
+#endif
+ is_cycle = (strstr(str, " cycle") != (char *) 0);
+ if (!is_cycle)
+ { depth++; trpt++;
+ }
+ if ((every_error != 0)
+ || errors == upto)
+ {
+#if defined(MA) && !defined(SAFETY)
+ if (is_cycle)
+ { int od = depth;
+ unwinding = 1;
+ depthfound = Unwind();
+ unwinding = 0;
+ depth = od;
+ }
+#endif
+#if NCORE>1
+ writing_trail = 1;
+#endif
+#ifdef BFS
+ if (depth > 1) trpt--;
+ nuerror(str);
+ if (depth > 1) trpt++;
+#else
+ putrail();
+#endif
+#if defined(MA) && !defined(SAFETY)
+ if (strstr(str, " cycle"))
+ { if (every_error)
+ printf("sorry: MA writes 1 trail max\n");
+ wrapup(); /* no recovery from unwind */
+ }
+#endif
+#if NCORE>1
+ if (search_terminated != NULL)
+ { *search_terminated |= 4; /* uerror */
+ }
+ writing_trail = 0;
+#endif
+ }
+ if (!is_cycle)
+ { depth--; trpt--; /* undo */
+ }
+#ifndef BFS
+ if (iterative != 0 && maxdepth > 0)
+ { maxdepth = (iterative == 1)?(depth-1):(depth/2);
+ warned = 1;
+ printf("pan: reducing search depth to %ld\n",
+ maxdepth);
+ } else
+#endif
+ if (errors >= upto && upto != 0)
+ {
+#if NCORE>1
+ sudden_stop("uerror");
+#endif
+ wrapup();
+ }
+ depthfound = -1;
+}
+
+int
+xrefsrc(int lno, S_F_MAP *mp, int M, int i)
+{ Trans *T; int j, retval=1;
+ for (T = trans[M][i]; T; T = T->nxt)
+ if (T && T->tp)
+ { if (strcmp(T->tp, ".(goto)") == 0
+ || strncmp(T->tp, "goto :", 6) == 0)
+ return 1; /* not reported */
+
+ printf("\tline %d", lno);
+ if (verbose)
+ for (j = 0; j < sizeof(mp); j++)
+ if (i >= mp[j].from && i <= mp[j].upto)
+ { printf(", \"%s\"", mp[j].fnm);
+ break;
+ }
+ printf(", state %d", i);
+ if (strcmp(T->tp, "") != 0)
+ { char *q;
+ q = transmognify(T->tp);
+ printf(", \"%s\"", q?q:"");
+ } else if (stopstate[M][i])
+ printf(", -end state-");
+ printf("\n");
+ retval = 0; /* reported */
+ }
+ return retval;
+}
+
+void
+r_ck(uchar *which, int N, int M, short *src, S_F_MAP *mp)
+{ int i, m=0;
+
+#ifdef VERI
+ if (M == VERI && !verbose) return;
+#endif
+ printf("unreached in proctype %s\n", procname[M]);
+ for (i = 1; i < N; i++)
+ if (which[i] == 0
+ && (mapstate[M][i] == 0
+ || which[mapstate[M][i]] == 0))
+ m += xrefsrc((int) src[i], mp, M, i);
+ else
+ m++;
+ printf(" (%d of %d states)\n", N-1-m, N-1);
+}
+#if NCORE>1 && !defined(SEP_STATE)
+static long rev_trail_cnt;
+
+#ifdef FULL_TRAIL
+void
+rev_trail(int fd, volatile Stack_Tree *st_tr)
+{ long j; char snap[64];
+
+ if (!st_tr)
+ { return;
+ }
+ rev_trail(fd, st_tr->prv);
+#ifdef VERBOSE
+ printf("%d (%d) LRT [%d,%d] -- %9u (root %9u)\n",
+ depth, rev_trail_cnt, st_tr->pr, st_tr->t_id, st_tr, stack_last[core_id]);
+#endif
+ if (st_tr->pr != 255)
+ { sprintf(snap, "%ld:%d:%d\n",
+ rev_trail_cnt++, st_tr->pr, st_tr->t_id);
+ j = strlen(snap);
+ if (write(fd, snap, j) != j)
+ { printf("pan: error writing trailfile\n");
+ close(fd);
+ wrapup();
+ return;
+ }
+ } else /* handoff point */
+ { if (a_cycles)
+ { write(fd, "-1:-1:-1\n", 9);
+ } }
+}
+#endif
+#endif
+
+void
+putrail(void)
+{ int fd;
+#if defined VERI || defined(MERGED)
+ char snap[64];
+#endif
+#if NCORE==1 || defined(SEP_STATE) || !defined(FULL_TRAIL)
+ long i, j;
+ Trail *trl;
+#endif
+ fd = make_trail();
+ if (fd < 0) return;
+#ifdef VERI
+ sprintf(snap, "-2:%d:-2\n", VERI);
+ write(fd, snap, strlen(snap));
+#endif
+#ifdef MERGED
+ sprintf(snap, "-4:-4:-4\n");
+ write(fd, snap, strlen(snap));
+#endif
+#if NCORE>1 && !defined(SEP_STATE) && defined(FULL_TRAIL)
+ rev_trail_cnt = 1;
+ enter_critical(GLOBAL_LOCK);
+ rev_trail(fd, stack_last[core_id]);
+ leave_critical(GLOBAL_LOCK);
+#else
+ i = 1; /* trail starts at position 1 */
+ #if NCORE>1 && defined(SEP_STATE)
+ if (cur_Root.m_vsize > 0) { i++; depth++; }
+ #endif
+ for ( ; i <= depth; i++)
+ { if (i == depthfound+1)
+ write(fd, "-1:-1:-1\n", 9);
+ trl = getframe(i);
+ if (!trl->o_t) continue;
+ if (trl->o_pm&128) continue;
+ sprintf(snap, "%ld:%d:%d\n",
+ i, trl->pr, trl->o_t->t_id);
+ j = strlen(snap);
+ if (write(fd, snap, j) != j)
+ { printf("pan: error writing trailfile\n");
+ close(fd);
+ wrapup();
+ } }
+#endif
+ close(fd);
+#if NCORE>1
+ cpu_printf("pan: wrote trailfile\n");
+#endif
+}
+
+void
+sv_save(void) /* push state vector onto save stack */
+{ if (!svtack->nxt)
+ { svtack->nxt = (Svtack *) emalloc(sizeof(Svtack));
+ svtack->nxt->body = emalloc(vsize*sizeof(char));
+ svtack->nxt->lst = svtack;
+ svtack->nxt->m_delta = vsize;
+ svmax++;
+ } else if (vsize > svtack->nxt->m_delta)
+ { svtack->nxt->body = emalloc(vsize*sizeof(char));
+ svtack->nxt->lst = svtack;
+ svtack->nxt->m_delta = vsize;
+ svmax++;
+ }
+ svtack = svtack->nxt;
+#if SYNC
+ svtack->o_boq = boq;
+#endif
+ svtack->o_delta = vsize; /* don't compress */
+ memcpy((char *)(svtack->body), (char *) &now, vsize);
+#if defined(C_States) && defined(HAS_STACK) && (HAS_TRACK==1)
+ c_stack((uchar *) &(svtack->c_stack[0]));
+#endif
+#ifdef DEBUG
+ cpu_printf("%d: sv_save\n", depth);
+#endif
+}
+
+void
+sv_restor(void) /* pop state vector from save stack */
+{
+ memcpy((char *)&now, svtack->body, svtack->o_delta);
+#if SYNC
+ boq = svtack->o_boq;
+#endif
+#if defined(C_States) && (HAS_TRACK==1)
+#ifdef HAS_STACK
+ c_unstack((uchar *) &(svtack->c_stack[0]));
+#endif
+ c_revert((uchar *) &(now.c_state[0]));
+#endif
+ if (vsize != svtack->o_delta)
+ Uerror("sv_restor");
+ if (!svtack->lst)
+ Uerror("error: v_restor");
+ svtack = svtack->lst;
+#ifdef DEBUG
+ cpu_printf(" sv_restor\n");
+#endif
+}
+
+void
+p_restor(int h)
+{ int i; char *z = (char *) &now;
+
+ proc_offset[h] = stack->o_offset;
+ proc_skip[h] = (uchar) stack->o_skip;
+#ifndef XUSAFE
+ p_name[h] = stack->o_name;
+#endif
+#ifndef NOCOMP
+ for (i = vsize + stack->o_skip; i > vsize; i--)
+ Mask[i-1] = 1; /* align */
+#endif
+ vsize += stack->o_skip;
+ memcpy(z+vsize, stack->body, stack->o_delta);
+ vsize += stack->o_delta;
+#ifndef NOVSZ
+ now._vsz = vsize;
+#endif
+#ifndef NOCOMP
+ for (i = 1; i <= Air[((P0 *)pptr(h))->_t]; i++)
+ Mask[vsize - i] = 1; /* pad */
+ Mask[proc_offset[h]] = 1; /* _pid */
+#endif
+ if (BASE > 0 && h > 0)
+ ((P0 *)pptr(h))->_pid = h-BASE;
+ else
+ ((P0 *)pptr(h))->_pid = h;
+ i = stack->o_delqs;
+ now._nr_pr += 1;
+ if (!stack->lst) /* debugging */
+ Uerror("error: p_restor");
+ stack = stack->lst;
+ this = pptr(h);
+ while (i-- > 0)
+ q_restor();
+}
+
+void
+q_restor(void)
+{ char *z = (char *) &now;
+#ifndef NOCOMP
+ int k, k_end;
+#endif
+ q_offset[now._nr_qs] = stack->o_offset;
+ q_skip[now._nr_qs] = (uchar) stack->o_skip;
+#ifndef XUSAFE
+ q_name[now._nr_qs] = stack->o_name;
+#endif
+ vsize += stack->o_skip;
+ memcpy(z+vsize, stack->body, stack->o_delta);
+ vsize += stack->o_delta;
+#ifndef NOVSZ
+ now._vsz = vsize;
+#endif
+ now._nr_qs += 1;
+#ifndef NOCOMP
+ k_end = stack->o_offset;
+ k = k_end - stack->o_skip;
+#if SYNC
+#ifndef BFS
+ if (q_zero(now._nr_qs)) k_end += stack->o_delta;
+#endif
+#endif
+ for ( ; k < k_end; k++)
+ Mask[k] = 1;
+#endif
+ if (!stack->lst) /* debugging */
+ Uerror("error: q_restor");
+ stack = stack->lst;
+}
+typedef struct IntChunks {
+ int *ptr;
+ struct IntChunks *nxt;
+} IntChunks;
+IntChunks *filled_chunks[512];
+IntChunks *empty_chunks[512];
+int *
+grab_ints(int nr)
+{ IntChunks *z;
+ if (nr >= 512) Uerror("cannot happen grab_int");
+ if (filled_chunks[nr])
+ { z = filled_chunks[nr];
+ filled_chunks[nr] = filled_chunks[nr]->nxt;
+ } else
+ { z = (IntChunks *) emalloc(sizeof(IntChunks));
+ z->ptr = (int *) emalloc(nr * sizeof(int));
+ }
+ z->nxt = empty_chunks[nr];
+ empty_chunks[nr] = z;
+ return z->ptr;
+}
+void
+ungrab_ints(int *p, int nr)
+{ IntChunks *z;
+ if (!empty_chunks[nr]) Uerror("cannot happen ungrab_int");
+ z = empty_chunks[nr];
+ empty_chunks[nr] = empty_chunks[nr]->nxt;
+ z->ptr = p;
+ z->nxt = filled_chunks[nr];
+ filled_chunks[nr] = z;
+}
+int
+delproc(int sav, int h)
+{ int d, i=0;
+#ifndef NOCOMP
+ int o_vsize = vsize;
+#endif
+ if (h+1 != (int) now._nr_pr) return 0;
+
+ while (now._nr_qs
+ && q_offset[now._nr_qs-1] > proc_offset[h])
+ { delq(sav);
+ i++;
+ }
+ d = vsize - proc_offset[h];
+ if (sav)
+ { if (!stack->nxt)
+ { stack->nxt = (Stack *)
+ emalloc(sizeof(Stack));
+ stack->nxt->body =
+ emalloc(Maxbody*sizeof(char));
+ stack->nxt->lst = stack;
+ smax++;
+ }
+ stack = stack->nxt;
+ stack->o_offset = proc_offset[h];
+#if VECTORSZ>32000
+ stack->o_skip = (int) proc_skip[h];
+#else
+ stack->o_skip = (short) proc_skip[h];
+#endif
+#ifndef XUSAFE
+ stack->o_name = p_name[h];
+#endif
+ stack->o_delta = d;
+ stack->o_delqs = i;
+ memcpy(stack->body, (char *)pptr(h), d);
+ }
+ vsize = proc_offset[h];
+ now._nr_pr = now._nr_pr - 1;
+ memset((char *)pptr(h), 0, d);
+ vsize -= (int) proc_skip[h];
+#ifndef NOVSZ
+ now._vsz = vsize;
+#endif
+#ifndef NOCOMP
+ for (i = vsize; i < o_vsize; i++)
+ Mask[i] = 0; /* reset */
+#endif
+ return 1;
+}
+
+void
+delq(int sav)
+{ int h = now._nr_qs - 1;
+ int d = vsize - q_offset[now._nr_qs - 1];
+#ifndef NOCOMP
+ int k, o_vsize = vsize;
+#endif
+ if (sav)
+ { if (!stack->nxt)
+ { stack->nxt = (Stack *)
+ emalloc(sizeof(Stack));
+ stack->nxt->body =
+ emalloc(Maxbody*sizeof(char));
+ stack->nxt->lst = stack;
+ smax++;
+ }
+ stack = stack->nxt;
+ stack->o_offset = q_offset[h];
+#if VECTORSZ>32000
+ stack->o_skip = (int) q_skip[h];
+#else
+ stack->o_skip = (short) q_skip[h];
+#endif
+#ifndef XUSAFE
+ stack->o_name = q_name[h];
+#endif
+ stack->o_delta = d;
+ memcpy(stack->body, (char *)qptr(h), d);
+ }
+ vsize = q_offset[h];
+ now._nr_qs = now._nr_qs - 1;
+ memset((char *)qptr(h), 0, d);
+ vsize -= (int) q_skip[h];
+#ifndef NOVSZ
+ now._vsz = vsize;
+#endif
+#ifndef NOCOMP
+ for (k = vsize; k < o_vsize; k++)
+ Mask[k] = 0; /* reset */
+#endif
+}
+
+int
+qs_empty(void)
+{ int i;
+ for (i = 0; i < (int) now._nr_qs; i++)
+ { if (q_sz(i) > 0)
+ return 0;
+ }
+ return 1;
+}
+
+int
+endstate(void)
+{ int i; P0 *ptr;
+ for (i = BASE; i < (int) now._nr_pr; i++)
+ { ptr = (P0 *) pptr(i);
+ if (!stopstate[ptr->_t][ptr->_p])
+ return 0;
+ }
+ if (strict) return qs_empty();
+#if defined(EVENT_TRACE) && !defined(OTIM)
+ if (!stopstate[EVENT_TRACE][now._event] && !a_cycles)
+ { printf("pan: event_trace not completed\n");
+ return 0;
+ }
+#endif
+ return 1;
+}
+
+#ifndef SAFETY
+void
+checkcycles(void)
+{ uchar o_a_t = now._a_t;
+#ifdef SCHED
+ int o_limit;
+#endif
+#ifndef NOFAIR
+ uchar o_cnt = now._cnt[1];
+#endif
+#ifdef FULLSTACK
+#ifndef MA
+ struct H_el *sv = trpt->ostate; /* save */
+#else
+ uchar prov = trpt->proviso; /* save */
+#endif
+#endif
+#ifdef DEBUG
+ { int i; uchar *v = (uchar *) &now;
+ printf(" set Seed state ");
+#ifndef NOFAIR
+ if (fairness) printf("(cnt = %d:%d, nrpr=%d) ",
+ now._cnt[0], now._cnt[1], now._nr_pr);
+#endif
+ /* for (i = 0; i < n; i++) printf("%d,", v[i]); */
+ printf("\n");
+ }
+ printf("%d: cycle check starts\n", depth);
+#endif
+ now._a_t |= (1|16|32);
+ /* 1 = 2nd DFS; (16|32) to help hasher */
+#ifndef NOFAIR
+ now._cnt[1] = now._cnt[0];
+#endif
+ memcpy((char *)&A_Root, (char *)&now, vsize);
+ A_depth = depthfound = depth;
+#if NCORE>1
+ mem_put_acc();
+#else
+ #ifdef SCHED
+ o_limit = trpt->sched_limit;
+ trpt->sched_limit = 0;
+ #endif
+ new_state(); /* start 2nd DFS */
+ #ifdef SCHED
+ trpt->sched_limit = o_limit;
+ #endif
+#endif
+ now._a_t = o_a_t;
+#ifndef NOFAIR
+ now._cnt[1] = o_cnt;
+#endif
+ A_depth = 0; depthfound = -1;
+#ifdef DEBUG
+ printf("%d: cycle check returns\n", depth);
+#endif
+#ifdef FULLSTACK
+#ifndef MA
+ trpt->ostate = sv; /* restore */
+#else
+ trpt->proviso = prov;
+#endif
+#endif
+}
+#endif
+
+#if defined(FULLSTACK) && defined(BITSTATE)
+struct H_el *Free_list = (struct H_el *) 0;
+void
+onstack_init(void) /* to store stack states in a bitstate search */
+{ S_Tab = (struct H_el **) emalloc(maxdepth*sizeof(struct H_el *));
+}
+struct H_el *
+grab_state(int n)
+{ struct H_el *v, *last = 0;
+ if (H_tab == S_Tab)
+ { for (v = Free_list; v && ((int) v->tagged >= n); v=v->nxt)
+ { if ((int) v->tagged == n)
+ { if (last)
+ last->nxt = v->nxt;
+ else
+gotcha: Free_list = v->nxt;
+ v->tagged = 0;
+ v->nxt = 0;
+#ifdef COLLAPSE
+ v->ln = 0;
+#endif
+ return v;
+ }
+ Fh++; last=v;
+ }
+ /* new: second try */
+ v = Free_list;
+ if (v && ((int) v->tagged >= n))
+ goto gotcha;
+ ngrabs++;
+ }
+ return (struct H_el *)
+ emalloc(sizeof(struct H_el)+n-sizeof(unsigned));
+}
+
+#else
+#if NCORE>1
+struct H_el *
+grab_state(int n)
+{ struct H_el *grab_shared(int);
+ return grab_shared(sizeof(struct H_el)+n-sizeof(unsigned));
+}
+#else
+ #ifndef AUTO_RESIZE
+ #define grab_state(n) (struct H_el *) \
+ emalloc(sizeof(struct H_el)+n-sizeof(unsigned long));
+ #else
+ struct H_el *
+ grab_state(int n)
+ { struct H_el *p;
+ int cnt = sizeof(struct H_el)+n-sizeof(unsigned long);
+
+ if (reclaim_size >= cnt+WS)
+ { if ((cnt & (WS-1)) != 0) /* alignment */
+ { cnt += WS - (cnt & (WS-1));
+ }
+ p = (struct H_el *) reclaim_mem;
+ reclaim_mem += cnt;
+ reclaim_size -= cnt;
+ memset(p, 0, cnt);
+ } else
+ { p = (struct H_el *) emalloc(cnt);
+ }
+ return p;
+ }
+ #endif
+#endif
+#endif
+#ifdef COLLAPSE
+unsigned long
+ordinal(char *v, long n, short tp)
+{ struct H_el *tmp, *ntmp; long m;
+ struct H_el *olst = (struct H_el *) 0;
+ s_hash((uchar *)v, n);
+#if NCORE>1 && !defined(SEP_STATE)
+ enter_critical(CS_ID); /* uses spinlock - 1..128 */
+#endif
+ tmp = H_tab[j1];
+ if (!tmp)
+ { tmp = grab_state(n);
+ H_tab[j1] = tmp;
+ } else
+ for ( ;; olst = tmp, tmp = tmp->nxt)
+ { m = memcmp(((char *)&(tmp->state)), v, n);
+ if (n == tmp->ln)
+ {
+ if (m == 0)
+ goto done;
+ if (m < 0)
+ {
+Insert: ntmp = grab_state(n);
+ ntmp->nxt = tmp;
+ if (!olst)
+ H_tab[j1] = ntmp;
+ else
+ olst->nxt = ntmp;
+ tmp = ntmp;
+ break;
+ } else if (!tmp->nxt)
+ {
+Append: tmp->nxt = grab_state(n);
+ tmp = tmp->nxt;
+ break;
+ }
+ continue;
+ }
+ if (n < tmp->ln)
+ goto Insert;
+ else if (!tmp->nxt)
+ goto Append;
+ }
+ m = ++ncomps[tp];
+#ifdef FULLSTACK
+ tmp->tagged = m;
+#else
+ tmp->st_id = m;
+#endif
+#if defined(AUTO_RESIZE) && !defined(BITSTATE)
+ tmp->m_K1 = K1;
+#endif
+ memcpy(((char *)&(tmp->state)), v, n);
+ tmp->ln = n;
+done:
+#if NCORE>1 && !defined(SEP_STATE)
+ leave_critical(CS_ID); /* uses spinlock */
+#endif
+#ifdef FULLSTACK
+ return tmp->tagged;
+#else
+ return tmp->st_id;
+#endif
+}
+
+int
+compress(char *vin, int nin) /* collapse compression */
+{ char *w, *v = (char *) &comp_now;
+ int i, j;
+ unsigned long n;
+ static char *x;
+ static uchar nbytes[513]; /* 1 + 256 + 256 */
+ static unsigned short nbytelen;
+ long col_q(int, char *);
+ long col_p(int, char *);
+#ifndef SAFETY
+ if (a_cycles)
+ *v++ = now._a_t;
+#ifndef NOFAIR
+ if (fairness)
+ for (i = 0; i < NFAIR; i++)
+ *v++ = now._cnt[i];
+#endif
+#endif
+ nbytelen = 0;
+#ifndef JOINPROCS
+ for (i = 0; i < (int) now._nr_pr; i++)
+ { n = col_p(i, (char *) 0);
+#ifdef NOFIX
+ nbytes[nbytelen] = 0;
+#else
+ nbytes[nbytelen] = 1;
+ *v++ = ((P0 *) pptr(i))->_t;
+#endif
+ *v++ = n&255;
+ if (n >= (1<<8))
+ { nbytes[nbytelen]++;
+ *v++ = (n>>8)&255;
+ }
+ if (n >= (1<<16))
+ { nbytes[nbytelen]++;
+ *v++ = (n>>16)&255;
+ }
+ if (n >= (1<<24))
+ { nbytes[nbytelen]++;
+ *v++ = (n>>24)&255;
+ }
+ nbytelen++;
+ }
+#else
+ x = scratch;
+ for (i = 0; i < (int) now._nr_pr; i++)
+ x += col_p(i, x);
+ n = ordinal(scratch, x-scratch, 2); /* procs */
+ *v++ = n&255;
+ nbytes[nbytelen] = 0;
+ if (n >= (1<<8))
+ { nbytes[nbytelen]++;
+ *v++ = (n>>8)&255;
+ }
+ if (n >= (1<<16))
+ { nbytes[nbytelen]++;
+ *v++ = (n>>16)&255;
+ }
+ if (n >= (1<<24))
+ { nbytes[nbytelen]++;
+ *v++ = (n>>24)&255;
+ }
+ nbytelen++;
+#endif
+#ifdef SEPQS
+ for (i = 0; i < (int) now._nr_qs; i++)
+ { n = col_q(i, (char *) 0);
+ nbytes[nbytelen] = 0;
+ *v++ = n&255;
+ if (n >= (1<<8))
+ { nbytes[nbytelen]++;
+ *v++ = (n>>8)&255;
+ }
+ if (n >= (1<<16))
+ { nbytes[nbytelen]++;
+ *v++ = (n>>16)&255;
+ }
+ if (n >= (1<<24))
+ { nbytes[nbytelen]++;
+ *v++ = (n>>24)&255;
+ }
+ nbytelen++;
+ }
+#endif
+#ifdef NOVSZ
+ /* 3 = _a_t, _nr_pr, _nr_qs */
+ w = (char *) &now + 3 * sizeof(uchar);
+#ifndef NOFAIR
+ w += NFAIR;
+#endif
+#else
+#if VECTORSZ<65536
+ w = (char *) &(now._vsz) + sizeof(unsigned short);
+#else
+ w = (char *) &(now._vsz) + sizeof(unsigned long);
+#endif
+#endif
+ x = scratch;
+ *x++ = now._nr_pr;
+ *x++ = now._nr_qs;
+ if (now._nr_qs > 0 && qptr(0) < pptr(0))
+ n = qptr(0) - (uchar *) w;
+ else
+ n = pptr(0) - (uchar *) w;
+ j = w - (char *) &now;
+ for (i = 0; i < (int) n; i++, w++)
+ if (!Mask[j++]) *x++ = *w;
+#ifndef SEPQS
+ for (i = 0; i < (int) now._nr_qs; i++)
+ x += col_q(i, x);
+#endif
+ x--;
+ for (i = 0, j = 6; i < nbytelen; i++)
+ { if (j == 6)
+ { j = 0;
+ *(++x) = 0;
+ } else
+ j += 2;
+ *x |= (nbytes[i] << j);
+ }
+ x++;
+ for (j = 0; j < WS-1; j++)
+ *x++ = 0;
+ x -= j; j = 0;
+ n = ordinal(scratch, x-scratch, 0); /* globals */
+ *v++ = n&255;
+ if (n >= (1<< 8)) { *v++ = (n>> 8)&255; j++; }
+ if (n >= (1<<16)) { *v++ = (n>>16)&255; j++; }
+ if (n >= (1<<24)) { *v++ = (n>>24)&255; j++; }
+ *v++ = j; /* add last count as a byte */
+ for (i = 0; i < WS-1; i++)
+ *v++ = 0;
+ v -= i;
+#if 0
+ printf("collapse %d -> %d\n",
+ vsize, v - (char *)&comp_now);
+#endif
+ return v - (char *)&comp_now;
+}
+#else
+#if !defined(NOCOMP)
+int
+compress(char *vin, int n) /* default compression */
+{
+#ifdef HC
+ int delta = 0;
+ s_hash((uchar *)vin, n); /* sets K1 and K2 */
+#ifndef SAFETY
+ if (S_A)
+ { delta++; /* _a_t */
+#ifndef NOFAIR
+ if (S_A > NFAIR)
+ delta += NFAIR; /* _cnt[] */
+#endif
+ }
+#endif
+ memcpy((char *) &comp_now + delta, (char *) &K1, WS);
+ delta += WS;
+#if HC>0
+ memcpy((char *) &comp_now + delta, (char *) &K2, HC);
+ delta += HC;
+#endif
+ return delta;
+#else
+ char *vv = vin;
+ char *v = (char *) &comp_now;
+ int i;
+ #ifndef NO_FAST_C
+ int r = 0, unroll = n/8;
+ if (unroll > 0)
+ { i = 0;
+ while (r++ < unroll)
+ { /* unroll 8 times, avoid ifs */
+ /* 1 */ *v = *vv++;
+ v += 1 - Mask[i++];
+ /* 2 */ *v = *vv++;
+ v += 1 - Mask[i++];
+ /* 3 */ *v = *vv++;
+ v += 1 - Mask[i++];
+ /* 4 */ *v = *vv++;
+ v += 1 - Mask[i++];
+ /* 5 */ *v = *vv++;
+ v += 1 - Mask[i++];
+ /* 6 */ *v = *vv++;
+ v += 1 - Mask[i++];
+ /* 7 */ *v = *vv++;
+ v += 1 - Mask[i++];
+ /* 8 */ *v = *vv++;
+ v += 1 - Mask[i++];
+ }
+ r = n - i; /* the rest, at most 7 */
+ switch (r) {
+ case 7: *v = *vv++; v += 1 - Mask[i++];
+ case 6: *v = *vv++; v += 1 - Mask[i++];
+ case 5: *v = *vv++; v += 1 - Mask[i++];
+ case 4: *v = *vv++; v += 1 - Mask[i++];
+ case 3: *v = *vv++; v += 1 - Mask[i++];
+ case 2: *v = *vv++; v += 1 - Mask[i++];
+ case 1: *v = *vv++; v += 1 - Mask[i++];
+ case 0: break;
+ }
+ r = (n+WS-1)/WS; /* words rounded up */
+ r *= WS; /* bytes */
+ i = r - i; /* remainder */
+ switch (i) {
+ case 7: *v++ = 0; /* fall thru */
+ case 6: *v++ = 0;
+ case 5: *v++ = 0;
+ case 4: *v++ = 0;
+ case 3: *v++ = 0;
+ case 2: *v++ = 0;
+ case 1: *v++ = 0;
+ case 0: break;
+ default: Uerror("unexpected wordsize");
+ }
+ v -= i;
+ } else
+ #endif
+ { for (i = 0; i < n; i++, vv++)
+ if (!Mask[i]) *v++ = *vv;
+ for (i = 0; i < WS-1; i++)
+ *v++ = 0;
+ v -= i;
+ }
+#if 0
+ printf("compress %d -> %d\n",
+ n, v - (char *)&comp_now);
+#endif
+ return v - (char *)&comp_now;
+#endif
+}
+#endif
+#endif
+#if defined(FULLSTACK) && defined(BITSTATE)
+#if defined(MA)
+#if !defined(onstack_now)
+int onstack_now(void) {}
+#endif
+#if !defined(onstack_put)
+void onstack_put(void) {}
+#endif
+#if !defined(onstack_zap)
+void onstack_zap(void) {}
+#endif
+#else
+void
+onstack_zap(void)
+{ struct H_el *v, *w, *last = 0;
+ struct H_el **tmp = H_tab;
+ char *nv; int n, m;
+
+ static char warned = 0;
+
+ H_tab = S_Tab;
+#ifndef NOCOMP
+ nv = (char *) &comp_now;
+ n = compress((char *)&now, vsize);
+#else
+#if defined(BITSTATE) && defined(LC)
+ nv = (char *) &comp_now;
+ n = compact_stack((char *)&now, vsize);
+#else
+ nv = (char *) &now;
+ n = vsize;
+#endif
+#endif
+#if !defined(HC) && !(defined(BITSTATE) && defined(LC))
+ s_hash((uchar *)nv, n);
+#endif
+ H_tab = tmp;
+ for (v = S_Tab[j1]; v; Zh++, last=v, v=v->nxt)
+ { m = memcmp(&(v->state), nv, n);
+ if (m == 0)
+ goto Found;
+ if (m < 0)
+ break;
+ }
+/* NotFound: */
+#ifndef ZAPH
+ #if defined(BITSTATE) && NCORE>1
+ /* seen this happen, likely harmless, but not yet understood */
+ if (warned == 0)
+ #endif
+ { /* Uerror("stack out of wack - zap"); */
+ cpu_printf("pan: warning, stack incomplete\n");
+ warned = 1;
+ }
+#endif
+ return;
+Found:
+ ZAPS++;
+ if (last)
+ last->nxt = v->nxt;
+ else
+ S_Tab[j1] = v->nxt;
+ v->tagged = (unsigned) n;
+#if !defined(NOREDUCE) && !defined(SAFETY)
+ v->proviso = 0;
+#endif
+ v->nxt = last = (struct H_el *) 0;
+ for (w = Free_list; w; Fa++, last=w, w = w->nxt)
+ { if ((int) w->tagged <= n)
+ { if (last)
+ { v->nxt = w;
+ last->nxt = v;
+ } else
+ { v->nxt = Free_list;
+ Free_list = v;
+ }
+ return;
+ }
+ if (!w->nxt)
+ { w->nxt = v;
+ return;
+ } }
+ Free_list = v;
+}
+void
+onstack_put(void)
+{ struct H_el **tmp = H_tab;
+ H_tab = S_Tab;
+ if (hstore((char *)&now, vsize) != 0)
+#if defined(BITSTATE) && defined(LC)
+ printf("pan: warning, double stack entry\n");
+#else
+ #ifndef ZAPH
+ Uerror("cannot happen - unstack_put");
+ #endif
+#endif
+ H_tab = tmp;
+ trpt->ostate = Lstate;
+ PUT++;
+}
+int
+onstack_now(void)
+{ struct H_el *tmp;
+ struct H_el **tmp2 = H_tab;
+ char *v; int n, m = 1;
+
+ H_tab = S_Tab;
+#ifdef NOCOMP
+#if defined(BITSTATE) && defined(LC)
+ v = (char *) &comp_now;
+ n = compact_stack((char *)&now, vsize);
+#else
+ v = (char *) &now;
+ n = vsize;
+#endif
+#else
+ v = (char *) &comp_now;
+ n = compress((char *)&now, vsize);
+#endif
+#if !defined(HC) && !(defined(BITSTATE) && defined(LC))
+ s_hash((uchar *)v, n);
+#endif
+ H_tab = tmp2;
+ for (tmp = S_Tab[j1]; tmp; Zn++, tmp = tmp->nxt)
+ { m = memcmp(((char *)&(tmp->state)),v,n);
+ if (m <= 0)
+ { Lstate = (struct H_el *) tmp;
+ break;
+ } }
+ PROBE++;
+ return (m == 0);
+}
+#endif
+#endif
+#ifndef BITSTATE
+void
+hinit(void)
+{
+ #ifdef MA
+#ifdef R_XPT
+ { void r_xpoint(void);
+ r_xpoint();
+ }
+#else
+ dfa_init((unsigned short) (MA+a_cycles));
+#if NCORE>1 && !defined(COLLAPSE)
+ if (!readtrail)
+ { void init_HT(unsigned long);
+ init_HT(0L);
+ }
+#endif
+#endif
+ #endif
+ #if !defined(MA) || defined(COLLAPSE)
+#if NCORE>1
+ if (!readtrail)
+ { void init_HT(unsigned long);
+ init_HT((unsigned long) (ONE_L<<ssize)*sizeof(struct H_el *));
+ } else
+#endif
+ H_tab = (struct H_el **)
+ emalloc((ONE_L<<ssize)*sizeof(struct H_el *));
+ #endif
+}
+#endif
+
+#if !defined(BITSTATE) || defined(FULLSTACK)
+#ifdef DEBUG
+void
+dumpstate(int wasnew, char *v, int n, int tag)
+{ int i;
+#ifndef SAFETY
+ if (S_A)
+ { printf(" state tags %d (%d::%d): ",
+ V_A, wasnew, v[0]);
+#ifdef FULLSTACK
+ printf(" %d ", tag);
+#endif
+ printf("\n");
+ }
+#endif
+#ifdef SDUMP
+#ifndef NOCOMP
+ printf(" State: ");
+ for (i = 0; i < vsize; i++) printf("%d%s,",
+ ((char *)&now)[i], Mask[i]?"*":"");
+#endif
+ printf("\n Vector: ");
+ for (i = 0; i < n; i++) printf("%d,", v[i]);
+ printf("\n");
+#endif
+}
+#endif
+#ifdef MA
+int
+gstore(char *vin, int nin, uchar pbit)
+{ int n, i;
+ int ret_val = 1;
+ uchar *v;
+ static uchar Info[MA+1];
+#ifndef NOCOMP
+ n = compress(vin, nin);
+ v = (uchar *) &comp_now;
+#else
+ n = nin;
+ v = vin;
+#endif
+ if (n >= MA)
+ { printf("pan: error, MA too small, recompile pan.c");
+ printf(" with -DMA=N with N>%d\n", n);
+ Uerror("aborting");
+ }
+ if (n > (int) maxgs)
+ { maxgs = (unsigned int) n;
+ }
+ for (i = 0; i < n; i++)
+ { Info[i] = v[i];
+ }
+ for ( ; i < MA-1; i++)
+ { Info[i] = 0;
+ }
+ Info[MA-1] = pbit;
+ if (a_cycles) /* place _a_t at the end */
+ { Info[MA] = Info[0];
+ Info[0] = 0;
+ }
+
+#if NCORE>1 && !defined(SEP_STATE)
+ enter_critical(GLOBAL_LOCK); /* crude, but necessary */
+ /* to make this mode work, also replace emalloc with grab_shared inside store MA routines */
+#endif
+
+ if (!dfa_store(Info))
+ { if (pbit == 0
+ && (now._a_t&1)
+ && depth > A_depth)
+ { Info[MA] &= ~(1|16|32); /* _a_t */
+ if (dfa_member(MA))
+ { Info[MA-1] = 4; /* off-stack bit */
+ nShadow++;
+ if (!dfa_member(MA-1))
+ { ret_val = 3;
+ #ifdef VERBOSE
+ printf("intersected 1st dfs stack\n");
+ #endif
+ goto done;
+ } } }
+ ret_val = 0;
+ #ifdef VERBOSE
+ printf("new state\n");
+ #endif
+ goto done;
+ }
+#ifdef FULLSTACK
+ if (pbit == 0)
+ { Info[MA-1] = 1; /* proviso bit */
+#ifndef BFS
+ trpt->proviso = dfa_member(MA-1);
+#endif
+ Info[MA-1] = 4; /* off-stack bit */
+ if (dfa_member(MA-1))
+ { ret_val = 1; /* off-stack */
+ #ifdef VERBOSE
+ printf("old state\n");
+ #endif
+ } else
+ { ret_val = 2; /* on-stack */
+ #ifdef VERBOSE
+ printf("on-stack\n");
+ #endif
+ }
+ goto done;
+ }
+#endif
+ ret_val = 1;
+#ifdef VERBOSE
+ printf("old state\n");
+#endif
+done:
+#if NCORE>1 && !defined(SEP_STATE)
+ leave_critical(GLOBAL_LOCK);
+#endif
+ return ret_val; /* old state */
+}
+#endif
+#if defined(BITSTATE) && defined(LC)
+int
+compact_stack(char *vin, int n)
+{ int delta = 0;
+ s_hash((uchar *)vin, n); /* sets K1 and K2 */
+#ifndef SAFETY
+ delta++; /* room for state[0] |= 128 */
+#endif
+ memcpy((char *) &comp_now + delta, (char *) &K1, WS);
+ delta += WS;
+ memcpy((char *) &comp_now + delta, (char *) &K2, WS);
+ delta += WS; /* use all available bits */
+ return delta;
+}
+#endif
+int
+hstore(char *vin, int nin) /* hash table storage */
+{ struct H_el *ntmp;
+ struct H_el *tmp, *olst = (struct H_el *) 0;
+ char *v; int n, m=0;
+#ifdef HC
+ uchar rem_a;
+#endif
+#ifdef NOCOMP
+#if defined(BITSTATE) && defined(LC)
+ if (S_Tab == H_tab)
+ { v = (char *) &comp_now;
+ n = compact_stack(vin, nin);
+ } else
+ { v = vin; n = nin;
+ }
+#else
+ v = vin; n = nin;
+#endif
+#else
+ v = (char *) &comp_now;
+ #ifdef HC
+ rem_a = now._a_t;
+ now._a_t = 0;
+ #endif
+ n = compress(vin, nin);
+ #ifdef HC
+ now._a_t = rem_a;
+ #endif
+#ifndef SAFETY
+ if (S_A)
+ { v[0] = 0; /* _a_t */
+#ifndef NOFAIR
+ if (S_A > NFAIR)
+ for (m = 0; m < NFAIR; m++)
+ v[m+1] = 0; /* _cnt[] */
+#endif
+ m = 0;
+ }
+ #endif
+#endif
+#if !defined(HC) && !(defined(BITSTATE) && defined(LC))
+ s_hash((uchar *)v, n);
+#endif
+#if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)
+ enter_critical(CS_ID); /* uses spinlock */
+#endif
+ tmp = H_tab[j1];
+ if (!tmp)
+ { tmp = grab_state(n);
+#if NCORE>1
+ if (!tmp)
+ { /* if we get here -- we've already issued a warning */
+ /* but we want to allow the normal distributed termination */
+ /* to collect the stats on all cpus in the wrapup */
+ #if !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+ #endif
+ return 1; /* allow normal termination */
+ }
+#endif
+ H_tab[j1] = tmp;
+ } else
+ { for (;; hcmp++, olst = tmp, tmp = tmp->nxt)
+ { /* skip the _a_t and the _cnt bytes */
+#ifdef COLLAPSE
+ if (tmp->ln != 0)
+ { if (!tmp->nxt) goto Append;
+ continue;
+ }
+#endif
+ m = memcmp(((char *)&(tmp->state)) + S_A,
+ v + S_A, n - S_A);
+ if (m == 0) {
+#ifdef SAFETY
+#define wasnew 0
+#else
+ int wasnew = 0;
+#endif
+#ifndef SAFETY
+#ifndef NOCOMP
+ if (S_A)
+ { if ((((char *)&(tmp->state))[0] & V_A) != V_A)
+ { wasnew = 1; nShadow++;
+ ((char *)&(tmp->state))[0] |= V_A;
+ }
+#ifndef NOFAIR
+ if (S_A > NFAIR)
+ { /* 0 <= now._cnt[now._a_t&1] < MAXPROC */
+ unsigned ci, bp; /* index, bit pos */
+ ci = (now._cnt[now._a_t&1] / 8);
+ bp = (now._cnt[now._a_t&1] - 8*ci);
+ if (now._a_t&1) /* use tail-bits in _cnt */
+ { ci = (NFAIR - 1) - ci;
+ bp = 7 - bp; /* bp = 0..7 */
+ }
+ ci++; /* skip over _a_t */
+ bp = 1 << bp; /* the bit mask */
+ if ((((char *)&(tmp->state))[ci] & bp)==0)
+ { if (!wasnew)
+ { wasnew = 1;
+ nShadow++;
+ }
+ ((char *)&(tmp->state))[ci] |= bp;
+ }
+ }
+ /* else: wasnew == 0, i.e., old state */
+#endif
+ }
+#endif
+#endif
+#if NCORE>1
+ Lstate = (struct H_el *) tmp;
+#endif
+#ifdef FULLSTACK
+#ifndef SAFETY
+ if (wasnew)
+ { Lstate = (struct H_el *) tmp;
+ tmp->tagged |= V_A;
+ if ((now._a_t&1)
+ && (tmp->tagged&A_V)
+ && depth > A_depth)
+ {
+intersect:
+#ifdef CHECK
+#if NCORE>1
+ printf("cpu%d: ", core_id);
+#endif
+ printf("1st dfs-stack intersected on state %d+\n",
+ (int) tmp->st_id);
+#endif
+#if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+#endif
+ return 3;
+ }
+#ifdef CHECK
+#if NCORE>1
+ printf("cpu%d: ", core_id);
+#endif
+ printf(" New state %d+\n", (int) tmp->st_id);
+#endif
+#ifdef DEBUG
+ dumpstate(1, (char *)&(tmp->state),n,tmp->tagged);
+#endif
+#if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+#endif
+ return 0;
+ } else
+#endif
+ if ((S_A)?(tmp->tagged&V_A):tmp->tagged)
+ { Lstate = (struct H_el *) tmp;
+#ifndef SAFETY
+ /* already on current dfs stack */
+ /* but may also be on 1st dfs stack */
+ if ((now._a_t&1)
+ && (tmp->tagged&A_V)
+ && depth > A_depth
+#ifndef NOFAIR
+ && (!fairness || now._cnt[1] <= 1)
+#endif
+ )
+ goto intersect;
+#endif
+#ifdef CHECK
+#if NCORE>1
+ printf("cpu%d: ", core_id);
+#endif
+ printf(" Stack state %d\n", (int) tmp->st_id);
+#endif
+#ifdef DEBUG
+ dumpstate(0, (char *)&(tmp->state),n,tmp->tagged);
+#endif
+#if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+#endif
+ return 2; /* match on stack */
+ }
+#else
+ if (wasnew)
+ {
+#ifdef CHECK
+#if NCORE>1
+ printf("cpu%d: ", core_id);
+#endif
+ printf(" New state %d+\n", (int) tmp->st_id);
+#endif
+#ifdef DEBUG
+ dumpstate(1, (char *)&(tmp->state), n, 0);
+#endif
+#if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+#endif
+ return 0;
+ }
+#endif
+#ifdef CHECK
+#if NCORE>1
+ printf("cpu%d: ", core_id);
+#endif
+ printf(" Old state %d\n", (int) tmp->st_id);
+#endif
+#ifdef DEBUG
+ dumpstate(0, (char *)&(tmp->state), n, 0);
+#endif
+#ifdef REACH
+ if (tmp->D > depth)
+ { tmp->D = depth;
+#ifdef CHECK
+#if NCORE>1
+ printf("cpu%d: ", core_id);
+#endif
+ printf(" ReVisiting (from smaller depth)\n");
+#endif
+ nstates--;
+#if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+#endif
+ return 0;
+ }
+#endif
+#if (defined(BFS) && defined(Q_PROVISO)) || NCORE>1
+ Lstate = (struct H_el *) tmp;
+#endif
+#if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+#endif
+ return 1; /* match outside stack */
+ } else if (m < 0)
+ { /* insert state before tmp */
+ ntmp = grab_state(n);
+#if NCORE>1
+ if (!ntmp)
+ {
+ #if !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+ #endif
+ return 1; /* allow normal termination */
+ }
+#endif
+ ntmp->nxt = tmp;
+ if (!olst)
+ H_tab[j1] = ntmp;
+ else
+ olst->nxt = ntmp;
+ tmp = ntmp;
+ break;
+ } else if (!tmp->nxt)
+ { /* append after tmp */
+#ifdef COLLAPSE
+Append:
+#endif
+ tmp->nxt = grab_state(n);
+#if NCORE>1
+ if (!tmp->nxt)
+ {
+ #if !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+ #endif
+ return 1; /* allow normal termination */
+ }
+#endif
+ tmp = tmp->nxt;
+ break;
+ } }
+ }
+#ifdef CHECK
+ tmp->st_id = (unsigned) nstates;
+#if NCORE>1
+ printf("cpu%d: ", core_id);
+#endif
+#ifdef BITSTATE
+ printf(" Push state %d\n", ((int) nstates) - 1);
+#else
+ printf(" New state %d\n", (int) nstates);
+#endif
+#endif
+#if !defined(SAFETY) || defined(REACH)
+ tmp->D = depth;
+#endif
+#ifndef SAFETY
+#ifndef NOCOMP
+ if (S_A)
+ { v[0] = V_A;
+#ifndef NOFAIR
+ if (S_A > NFAIR)
+ { unsigned ci, bp; /* as above */
+ ci = (now._cnt[now._a_t&1] / 8);
+ bp = (now._cnt[now._a_t&1] - 8*ci);
+ if (now._a_t&1)
+ { ci = (NFAIR - 1) - ci;
+ bp = 7 - bp; /* bp = 0..7 */
+ }
+ v[1+ci] = 1 << bp;
+ }
+#endif
+ }
+#endif
+#endif
+#if defined(AUTO_RESIZE) && !defined(BITSTATE)
+ tmp->m_K1 = K1;
+#endif
+ memcpy(((char *)&(tmp->state)), v, n);
+#ifdef FULLSTACK
+ tmp->tagged = (S_A)?V_A:(depth+1);
+#ifdef DEBUG
+ dumpstate(-1, v, n, tmp->tagged);
+#endif
+ Lstate = (struct H_el *) tmp;
+#else
+ #ifdef DEBUG
+ dumpstate(-1, v, n, 0);
+ #endif
+ #if NCORE>1
+ Lstate = (struct H_el *) tmp;
+ #endif
+#endif
+/* #if NCORE>1 && !defined(SEP_STATE) */
+#if NCORE>1
+ #ifdef V_PROVISO
+ tmp->cpu_id = core_id;
+ #endif
+ #if !defined(SEP_STATE) && !defined(BITSTATE)
+ leave_critical(CS_ID);
+ #endif
+#endif
+ return 0;
+}
+#endif
+#include TRANSITIONS
+void
+do_reach(void)
+{
+ r_ck(reached0, nstates0, 0, src_ln0, src_file0);
+ r_ck(reached1, nstates1, 1, src_ln1, src_file1);
+ r_ck(reached2, nstates2, 2, src_ln2, src_file2);
+ r_ck(reached3, nstates3, 3, src_ln3, src_file3);
+ r_ck(reached4, nstates4, 4, src_ln4, src_file4);
+ r_ck(reached5, nstates5, 5, src_ln5, src_file5);
+}
+
+void
+iniglobals(void)
+{
+ deliver = 0;
+ { int l_in;
+ for (l_in = 0; l_in < 8; l_in++)
+ {
+ now.buffer_use[l_in] = 0;
+ }
+ }
+ now.write_off = 0;
+ { int l_in;
+ for (l_in = 0; l_in < 2; l_in++)
+ {
+ now.commit_count[l_in] = 0;
+ }
+ }
+ now._commit_sum = 0;
+ now.read_off = 0;
+ now.events_lost = 0;
+ now.refcount = 0;
+#ifdef VAR_RANGES
+ { int l_in;
+ for (l_in = 0; l_in < 8; l_in++)
+ {
+ logval("buffer_use[l_in]", now.buffer_use[l_in]);
+ }
+ }
+ logval("write_off", now.write_off);
+ { int l_in;
+ for (l_in = 0; l_in < 2; l_in++)
+ {
+ logval("commit_count[l_in]", now.commit_count[l_in]);
+ }
+ }
+ logval("_commit_sum", now._commit_sum);
+ logval("read_off", now.read_off);
+ logval("events_lost", now.events_lost);
+ logval("refcount", now.refcount);
+#endif
+ Maxbody = max(Maxbody, sizeof(State)-VECTORSZ);
+}
+
+int
+addqueue(int n, int is_rv)
+{ int j=0, i = now._nr_qs;
+#ifndef NOCOMP
+ int k;
+#endif
+ if (i >= MAXQ)
+ Uerror("too many queues");
+ switch (n) {
+ default: Uerror("bad queue - addqueue");
+ }
+ if (vsize%WS)
+ q_skip[i] = WS-(vsize%WS);
+ else
+ q_skip[i] = 0;
+#ifndef NOCOMP
+ k = vsize;
+#ifndef BFS
+ if (is_rv) k += j;
+#endif
+ for (k += (int) q_skip[i]; k > vsize; k--)
+ Mask[k-1] = 1;
+#endif
+ vsize += (int) q_skip[i];
+ q_offset[i] = vsize;
+ now._nr_qs += 1;
+ vsize += j;
+#ifndef NOVSZ
+ now._vsz = vsize;
+#endif
+ hmax = max(hmax, vsize);
+ if (vsize >= VECTORSZ)
+ Uerror("VECTORSZ is too small, edit pan.h");
+ memset((char *)qptr(i), 0, j);
+ ((Q0 *)qptr(i))->_t = n;
+ return i+1;
+}
+
+#if NQS>0
+void
+qsend(int into, int sorted, int args_given)
+{ int j; uchar *z;
+
+#ifdef HAS_SORTED
+ int k;
+#endif
+ if (!into--)
+ uerror("ref to uninitialized chan name (sending)");
+ if (into >= (int) now._nr_qs || into < 0)
+ Uerror("qsend bad queue#");
+ z = qptr(into);
+ j = ((Q0 *)qptr(into))->Qlen;
+ switch (((Q0 *)qptr(into))->_t) {
+ case 0: printf("queue %d was deleted\n", into+1);
+ default: Uerror("bad queue - qsend");
+ }
+#ifdef EVENT_TRACE
+ if (in_s_scope(into+1))
+ require('s', into);
+#endif
+}
+#endif
+
+#if SYNC
+int
+q_zero(int from)
+{ if (!from--)
+ { uerror("ref to uninitialized chan name (q_zero)");
+ return 0;
+ }
+ switch(((Q0 *)qptr(from))->_t) {
+ case 0: printf("queue %d was deleted\n", from+1);
+ }
+ Uerror("bad queue q-zero");
+ return -1;
+}
+int
+not_RV(int from)
+{ if (q_zero(from))
+ { printf("==>> a test of the contents of a rv ");
+ printf("channel always returns FALSE\n");
+ uerror("error to poll rendezvous channel");
+ }
+ return 1;
+}
+#endif
+#ifndef XUSAFE
+void
+setq_claim(int x, int m, char *s, int y, char *p)
+{ if (x == 0)
+ uerror("x[rs] claim on uninitialized channel");
+ if (x < 0 || x > MAXQ)
+ Uerror("cannot happen setq_claim");
+ q_claim[x] |= m;
+ p_name[y] = p;
+ q_name[x] = s;
+ if (m&2) q_S_check(x, y);
+ if (m&1) q_R_check(x, y);
+}
+short q_sender[MAXQ+1];
+int
+q_S_check(int x, int who)
+{ if (!q_sender[x])
+ { q_sender[x] = who+1;
+#if SYNC
+ if (q_zero(x))
+ { printf("chan %s (%d), ",
+ q_name[x], x-1);
+ printf("sndr proc %s (%d)\n",
+ p_name[who], who);
+ uerror("xs chans cannot be used for rv");
+ }
+#endif
+ } else
+ if (q_sender[x] != who+1)
+ { printf("pan: xs assertion violated: ");
+ printf("access to chan <%s> (%d)\npan: by ",
+ q_name[x], x-1);
+ if (q_sender[x] > 0 && p_name[q_sender[x]-1])
+ printf("%s (proc %d) and by ",
+ p_name[q_sender[x]-1], q_sender[x]-1);
+ printf("%s (proc %d)\n",
+ p_name[who], who);
+ uerror("error, partial order reduction invalid");
+ }
+ return 1;
+}
+short q_recver[MAXQ+1];
+int
+q_R_check(int x, int who)
+{ if (!q_recver[x])
+ { q_recver[x] = who+1;
+#if SYNC
+ if (q_zero(x))
+ { printf("chan %s (%d), ",
+ q_name[x], x-1);
+ printf("recv proc %s (%d)\n",
+ p_name[who], who);
+ uerror("xr chans cannot be used for rv");
+ }
+#endif
+ } else
+ if (q_recver[x] != who+1)
+ { printf("pan: xr assertion violated: ");
+ printf("access to chan %s (%d)\npan: ",
+ q_name[x], x-1);
+ if (q_recver[x] > 0 && p_name[q_recver[x]-1])
+ printf("by %s (proc %d) and ",
+ p_name[q_recver[x]-1], q_recver[x]-1);
+ printf("by %s (proc %d)\n",
+ p_name[who], who);
+ uerror("error, partial order reduction invalid");
+ }
+ return 1;
+}
+#endif
+int
+q_len(int x)
+{ if (!x--)
+ uerror("ref to uninitialized chan name (len)");
+ return ((Q0 *)qptr(x))->Qlen;
+}
+
+int
+q_full(int from)
+{ if (!from--)
+ uerror("ref to uninitialized chan name (qfull)");
+ switch(((Q0 *)qptr(from))->_t) {
+ case 0: printf("queue %d was deleted\n", from+1);
+ }
+ Uerror("bad queue - q_full");
+ return 0;
+}
+
+#ifdef HAS_UNLESS
+int
+q_e_f(int from)
+{ /* empty or full */
+ return !q_len(from) || q_full(from);
+}
+#endif
+#if NQS>0
+int
+qrecv(int from, int slot, int fld, int done)
+{ uchar *z;
+ int j, k, r=0;
+
+ if (!from--)
+ uerror("ref to uninitialized chan name (receiving)");
+ if (from >= (int) now._nr_qs || from < 0)
+ Uerror("qrecv bad queue#");
+ z = qptr(from);
+#ifdef EVENT_TRACE
+ if (done && (in_r_scope(from+1)))
+ require('r', from);
+#endif
+ switch (((Q0 *)qptr(from))->_t) {
+ case 0: printf("queue %d was deleted\n", from+1);
+ default: Uerror("bad queue - qrecv");
+ }
+ return r;
+}
+#endif
+
+#ifndef BITSTATE
+#ifdef COLLAPSE
+long
+col_q(int i, char *z)
+{ int j=0, k;
+ char *x, *y;
+ Q0 *ptr = (Q0 *) qptr(i);
+ switch (ptr->_t) {
+ default: Uerror("bad qtype - collapse");
+ }
+ if (z) x = z; else x = scratch;
+ y = (char *) ptr; k = q_offset[i];
+ /* no need to store the empty slots at the end */
+ j -= (q_max[ptr->_t] - ptr->Qlen) * ((j - 2)/q_max[ptr->_t]);
+ for ( ; j > 0; j--, y++)
+ if (!Mask[k++]) *x++ = *y;
+ for (j = 0; j < WS-1; j++)
+ *x++ = 0;
+ x -= j;
+ if (z) return (long) (x - z);
+ return ordinal(scratch, x-scratch, 1); /* chan */
+}
+#endif
+#endif
+int
+unsend(int into)
+{ int _m=0, j; uchar *z;
+
+#ifdef HAS_SORTED
+ int k;
+#endif
+ if (!into--)
+ uerror("ref to uninitialized chan (unsend)");
+ z = qptr(into);
+ j = ((Q0 *)z)->Qlen;
+ ((Q0 *)z)->Qlen = --j;
+ switch (((Q0 *)qptr(into))->_t) {
+ default: Uerror("bad queue - unsend");
+ }
+ return _m;
+}
+
+void
+unrecv(int from, int slot, int fld, int fldvar, int strt)
+{ int j; uchar *z;
+
+ if (!from--)
+ uerror("ref to uninitialized chan (unrecv)");
+ z = qptr(from);
+ j = ((Q0 *)z)->Qlen;
+ if (strt) ((Q0 *)z)->Qlen = j+1;
+ switch (((Q0 *)qptr(from))->_t) {
+ default: Uerror("bad queue - qrecv");
+ }
+}
+int
+q_cond(short II, Trans *t)
+{ int i = 0;
+ for (i = 0; i < 6; i++)
+ { if (t->ty[i] == TIMEOUT_F) return 1;
+ if (t->ty[i] == ALPHA_F)
+#ifdef GLOB_ALPHA
+ return 0;
+#else
+ return (II+1 == (short) now._nr_pr && II+1 < MAXPROC);
+#endif
+ switch (t->qu[i]) {
+ case 0: break;
+ default: Uerror("unknown qid - q_cond");
+ return 0;
+ }
+ }
+ return 1;
+}
+void
+to_compile(void)
+{ char ctd[1024], carg[64];
+#ifdef BITSTATE
+ strcpy(ctd, "-DBITSTATE ");
+#else
+ strcpy(ctd, "");
+#endif
+#ifdef NOVSZ
+ strcat(ctd, "-DNOVSZ ");
+#endif
+#ifdef REVERSE
+ strcat(ctd, "-DREVERSE ");
+#endif
+#ifdef T_REVERSE
+ strcat(ctd, "-DT_REVERSE ");
+#endif
+#ifdef RANDOMIZE
+ #if RANDOMIZE>0
+ sprintf(carg, "-DRANDOMIZE=%d ", RANDOMIZE);
+ strcat(ctd, carg);
+ #else
+ strcat(ctd, "-DRANDOMIZE ");
+ #endif
+#endif
+#ifdef SCHED
+ sprintf(carg, "-DSCHED=%d ", SCHED);
+ strcat(ctd, carg);
+#endif
+#ifdef BFS
+ strcat(ctd, "-DBFS ");
+#endif
+#ifdef MEMLIM
+ sprintf(carg, "-DMEMLIM=%d ", MEMLIM);
+ strcat(ctd, carg);
+#else
+#ifdef MEMCNT
+ sprintf(carg, "-DMEMCNT=%d ", MEMCNT);
+ strcat(ctd, carg);
+#endif
+#endif
+#ifdef NOCLAIM
+ strcat(ctd, "-DNOCLAIM ");
+#endif
+#ifdef SAFETY
+ strcat(ctd, "-DSAFETY ");
+#else
+#ifdef NOFAIR
+ strcat(ctd, "-DNOFAIR ");
+#else
+#ifdef NFAIR
+ if (NFAIR != 2)
+ { sprintf(carg, "-DNFAIR=%d ", NFAIR);
+ strcat(ctd, carg);
+ }
+#endif
+#endif
+#endif
+#ifdef NOREDUCE
+ strcat(ctd, "-DNOREDUCE ");
+#else
+#ifdef XUSAFE
+ strcat(ctd, "-DXUSAFE ");
+#endif
+#endif
+#ifdef NP
+ strcat(ctd, "-DNP ");
+#endif
+#ifdef PEG
+ strcat(ctd, "-DPEG ");
+#endif
+#ifdef VAR_RANGES
+ strcat(ctd, "-DVAR_RANGES ");
+#endif
+#ifdef HC0
+ strcat(ctd, "-DHC0 ");
+#endif
+#ifdef HC1
+ strcat(ctd, "-DHC1 ");
+#endif
+#ifdef HC2
+ strcat(ctd, "-DHC2 ");
+#endif
+#ifdef HC3
+ strcat(ctd, "-DHC3 ");
+#endif
+#ifdef HC4
+ strcat(ctd, "-DHC4 ");
+#endif
+#ifdef CHECK
+ strcat(ctd, "-DCHECK ");
+#endif
+#ifdef CTL
+ strcat(ctd, "-DCTL ");
+#endif
+#ifdef NIBIS
+ strcat(ctd, "-DNIBIS ");
+#endif
+#ifdef NOBOUNDCHECK
+ strcat(ctd, "-DNOBOUNDCHECK ");
+#endif
+#ifdef NOSTUTTER
+ strcat(ctd, "-DNOSTUTTER ");
+#endif
+#ifdef REACH
+ strcat(ctd, "-DREACH ");
+#endif
+#ifdef PRINTF
+ strcat(ctd, "-DPRINTF ");
+#endif
+#ifdef OTIM
+ strcat(ctd, "-DOTIM ");
+#endif
+#ifdef COLLAPSE
+ strcat(ctd, "-DCOLLAPSE ");
+#endif
+#ifdef MA
+ sprintf(carg, "-DMA=%d ", MA);
+ strcat(ctd, carg);
+#endif
+#ifdef SVDUMP
+ strcat(ctd, "-DSVDUMP ");
+#endif
+#ifdef VECTORSZ
+ if (VECTORSZ != 1024)
+ { sprintf(carg, "-DVECTORSZ=%d ", VECTORSZ);
+ strcat(ctd, carg);
+ }
+#endif
+#ifdef VERBOSE
+ strcat(ctd, "-DVERBOSE ");
+#endif
+#ifdef CHECK
+ strcat(ctd, "-DCHECK ");
+#endif
+#ifdef SDUMP
+ strcat(ctd, "-DSDUMP ");
+#endif
+#if NCORE>1
+ sprintf(carg, "-DNCORE=%d ", NCORE);
+ strcat(ctd, carg);
+#endif
+#ifdef SFH
+ sprintf(carg, "-DSFH ");
+ strcat(ctd, carg);
+#endif
+#ifdef VMAX
+ if (VMAX != 256)
+ { sprintf(carg, "-DVMAX=%d ", VMAX);
+ strcat(ctd, carg);
+ }
+#endif
+#ifdef PMAX
+ if (PMAX != 16)
+ { sprintf(carg, "-DPMAX=%d ", PMAX);
+ strcat(ctd, carg);
+ }
+#endif
+#ifdef QMAX
+ if (QMAX != 16)
+ { sprintf(carg, "-DQMAX=%d ", QMAX);
+ strcat(ctd, carg);
+ }
+#endif
+#ifdef SET_WQ_SIZE
+ sprintf(carg, "-DSET_WQ_SIZE=%d ", SET_WQ_SIZE);
+ strcat(ctd, carg);
+#endif
+ printf("Compiled as: cc -o pan %span.c\n", ctd);
+}
+void
+active_procs(void)
+{
+ if (!permuted) {
+ Addproc(4);
+ } else {
+ Addproc(4);
+ }
+}
+#ifdef MA
+/*
+#include <stdio.h>
+#define uchar unsigned char
+*/
+#define ulong unsigned long
+#define ushort unsigned short
+
+#define TWIDTH 256
+#define HASH(y,n) (n)*(((long)y))
+#define INRANGE(e,h) ((h>=e->From && h<=e->To)||(e->s==1 && e->S==h))
+
+extern char *emalloc(unsigned long); /* imported routine */
+extern void dfa_init(ushort); /* 4 exported routines */
+extern int dfa_member(ulong);
+extern int dfa_store(uchar *);
+extern void dfa_stats(void);
+
+typedef struct Edge {
+ uchar From, To; /* max range 0..255 */
+ uchar s, S; /* if s=1, S is singleton */
+ struct Vertex *Dst;
+ struct Edge *Nxt;
+} Edge;
+
+typedef struct Vertex {
+ ulong key, num; /* key for splay tree, nr incoming edges */
+ uchar from[2], to[2]; /* in-node predefined edge info */
+ struct Vertex *dst[2];/* most nodes have 2 or more edges */
+ struct Edge *Succ; /* in case there are more edges */
+ struct Vertex *lnk, *left, *right; /* splay tree plumbing */
+} Vertex;
+
+static Edge *free_edges;
+static Vertex *free_vertices;
+static Vertex **layers; /* one splay tree of nodes per layer */
+static Vertex **path; /* run of word in the DFA */
+static Vertex *R, *F, *NF; /* Root, Final, Not-Final */
+static uchar *word, *lastword;/* string, and last string inserted */
+static int dfa_depth, iv=0, nv=0, pfrst=0, Tally;
+
+static void insert_it(Vertex *, int); /* splay-tree code */
+static void delete_it(Vertex *, int);
+static Vertex *find_it(Vertex *, Vertex *, uchar, int);
+
+static void
+recyc_edges(Edge *e)
+{
+ if (!e) return;
+ recyc_edges(e->Nxt);
+ e->Nxt = free_edges;
+ free_edges = e;
+}
+
+static Edge *
+new_edge(Vertex *dst)
+{ Edge *e;
+
+ if (free_edges)
+ { e = free_edges;
+ free_edges = e->Nxt;
+ e->From = e->To = e->s = e->S = 0;
+ e->Nxt = (Edge *) 0;
+ } else
+ e = (Edge *) emalloc(sizeof(Edge));
+ e->Dst = dst;
+
+ return e;
+}
+
+static void
+recyc_vertex(Vertex *v)
+{
+ recyc_edges(v->Succ);
+ v->Succ = (Edge *) free_vertices;
+ free_vertices = v;
+ nr_states--;
+}
+
+static Vertex *
+new_vertex(void)
+{ Vertex *v;
+
+ if (free_vertices)
+ { v = free_vertices;
+ free_vertices = (Vertex *) v->Succ;
+ v->Succ = (Edge *) 0;
+ v->num = 0;
+ } else
+ v = (Vertex *) emalloc(sizeof(Vertex));
+
+ nr_states++;
+ return v;
+}
+
+static Vertex *
+allDelta(Vertex *v, int n)
+{ Vertex *dst = new_vertex();
+
+ v->from[0] = 0;
+ v->to[0] = 255;
+ v->dst[0] = dst;
+ dst->num = 256;
+ insert_it(v, n);
+ return dst;
+}
+
+static void
+insert_edge(Vertex *v, Edge *e)
+{ /* put new edge first */
+ if (!v->dst[0])
+ { v->dst[0] = e->Dst;
+ v->from[0] = e->From;
+ v->to[0] = e->To;
+ recyc_edges(e);
+ return;
+ }
+ if (!v->dst[1])
+ { v->from[1] = v->from[0]; v->from[0] = e->From;
+ v->to[1] = v->to[0]; v->to[0] = e->To;
+ v->dst[1] = v->dst[0]; v->dst[0] = e->Dst;
+ recyc_edges(e);
+ return;
+ } /* shift */
+ { int f = v->from[1];
+ int t = v->to[1];
+ Vertex *d = v->dst[1];
+ v->from[1] = v->from[0]; v->from[0] = e->From;
+ v->to[1] = v->to[0]; v->to[0] = e->To;
+ v->dst[1] = v->dst[0]; v->dst[0] = e->Dst;
+ e->From = f;
+ e->To = t;
+ e->Dst = d;
+ }
+ e->Nxt = v->Succ;
+ v->Succ = e;
+}
+
+static void
+copyRecursive(Vertex *v, Edge *e)
+{ Edge *f;
+ if (e->Nxt) copyRecursive(v, e->Nxt);
+ f = new_edge(e->Dst);
+ f->From = e->From;
+ f->To = e->To;
+ f->s = e->s;
+ f->S = e->S;
+ f->Nxt = v->Succ;
+ v->Succ = f;
+}
+
+static void
+copyEdges(Vertex *to, Vertex *from)
+{ int i;
+ for (i = 0; i < 2; i++)
+ { to->from[i] = from->from[i];
+ to->to[i] = from->to[i];
+ to->dst[i] = from->dst[i];
+ }
+ if (from->Succ) copyRecursive(to, from->Succ);
+}
+
+static Edge *
+cacheDelta(Vertex *v, int h, int first)
+{ static Edge *ov, tmp; int i;
+
+ if (!first && INRANGE(ov,h))
+ return ov; /* intercepts about 10% */
+ for (i = 0; i < 2; i++)
+ if (v->dst[i] && h >= v->from[i] && h <= v->to[i])
+ { tmp.From = v->from[i];
+ tmp.To = v->to[i];
+ tmp.Dst = v->dst[i];
+ tmp.s = tmp.S = 0;
+ ov = &tmp;
+ return ov;
+ }
+ for (ov = v->Succ; ov; ov = ov->Nxt)
+ if (INRANGE(ov,h)) return ov;
+
+ Uerror("cannot get here, cacheDelta");
+ return (Edge *) 0;
+}
+
+static Vertex *
+Delta(Vertex *v, int h) /* v->delta[h] */
+{ Edge *e;
+
+ if (v->dst[0] && h >= v->from[0] && h <= v->to[0])
+ return v->dst[0]; /* oldest edge */
+ if (v->dst[1] && h >= v->from[1] && h <= v->to[1])
+ return v->dst[1];
+ for (e = v->Succ; e; e = e->Nxt)
+ if (INRANGE(e,h))
+ return e->Dst;
+ Uerror("cannot happen Delta");
+ return (Vertex *) 0;
+}
+
+static void
+numDelta(Vertex *v, int d)
+{ Edge *e;
+ ulong cnt;
+ int i;
+
+ for (i = 0; i < 2; i++)
+ if (v->dst[i])
+ { cnt = v->dst[i]->num + d*(1 + v->to[i] - v->from[i]);
+ if (d == 1 && cnt < v->dst[i]->num) goto bad;
+ v->dst[i]->num = cnt;
+ }
+ for (e = v->Succ; e; e = e->Nxt)
+ { cnt = e->Dst->num + d*(1 + e->To - e->From + e->s);
+ if (d == 1 && cnt < e->Dst->num)
+bad: Uerror("too many incoming edges");
+ e->Dst->num = cnt;
+ }
+}
+
+static void
+setDelta(Vertex *v, int h, Vertex *newdst) /* v->delta[h] = newdst; */
+{ Edge *e, *f = (Edge *) 0, *g;
+ int i;
+
+ /* remove the old entry, if there */
+ for (i = 0; i < 2; i++)
+ if (v->dst[i] && h >= v->from[i] && h <= v->to[i])
+ { if (h == v->from[i])
+ { if (h == v->to[i])
+ { v->dst[i] = (Vertex *) 0;
+ v->from[i] = v->to[i] = 0;
+ } else
+ v->from[i]++;
+ } else if (h == v->to[i])
+ { v->to[i]--;
+ } else
+ { g = new_edge(v->dst[i]);/* same dst */
+ g->From = v->from[i];
+ g->To = h-1; /* left half */
+ v->from[i] = h+1; /* right half */
+ insert_edge(v, g);
+ }
+ goto part2;
+ }
+ for (e = v->Succ; e; f = e, e = e->Nxt)
+ { if (e->s == 1 && e->S == h)
+ { e->s = e->S = 0;
+ goto rem_tst;
+ }
+ if (h >= e->From && h <= e->To)
+ { if (h == e->From)
+ { if (h == e->To)
+ { if (e->s)
+ { e->From = e->To = e->S;
+ e->s = 0;
+ break;
+ } else
+ goto rem_do;
+ } else
+ e->From++;
+ } else if (h == e->To)
+ { e->To--;
+ } else /* split */
+ { g = new_edge(e->Dst); /* same dst */
+ g->From = e->From;
+ g->To = h-1; /* g=left half */
+ e->From = h+1; /* e=right half */
+ g->Nxt = e->Nxt; /* insert g */
+ e->Nxt = g; /* behind e */
+ break; /* done */
+ }
+
+rem_tst: if (e->From > e->To)
+ { if (e->s == 0) {
+rem_do: if (f)
+ f->Nxt = e->Nxt;
+ else
+ v->Succ = e->Nxt;
+ e->Nxt = (Edge *) 0;
+ recyc_edges(e);
+ } else
+ { e->From = e->To = e->S;
+ e->s = 0;
+ } }
+ break;
+ } }
+part2:
+ /* check if newdst is already there */
+ for (i = 0; i < 2; i++)
+ if (v->dst[i] == newdst)
+ { if (h+1 == (int) v->from[i])
+ { v->from[i] = h;
+ return;
+ }
+ if (h == (int) v->to[i]+1)
+ { v->to[i] = h;
+ return;
+ } }
+ for (e = v->Succ; e; e = e->Nxt)
+ { if (e->Dst == newdst)
+ { if (h+1 == (int) e->From)
+ { e->From = h;
+ if (e->s == 1 && e->S+1 == e->From)
+ { e->From = e->S;
+ e->s = e->S = 0;
+ }
+ return;
+ }
+ if (h == (int) e->To+1)
+ { e->To = h;
+ if (e->s == 1 && e->S == e->To+1)
+ { e->To = e->S;
+ e->s = e->S = 0;
+ }
+ return;
+ }
+ if (e->s == 0)
+ { e->s = 1;
+ e->S = h;
+ return;
+ } } }
+ /* add as a new edge */
+ e = new_edge(newdst);
+ e->From = e->To = h;
+ insert_edge(v, e);
+}
+
+static ulong
+cheap_key(Vertex *v)
+{ ulong vk2 = 0;
+
+ if (v->dst[0])
+ { vk2 = (ulong) v->dst[0];
+ if ((ulong) v->dst[1] > vk2)
+ vk2 = (ulong) v->dst[1];
+ } else if (v->dst[1])
+ vk2 = (ulong) v->dst[1];
+ if (v->Succ)
+ { Edge *e;
+ for (e = v->Succ; e; e = e->Nxt)
+ if ((ulong) e->Dst > vk2)
+ vk2 = (ulong) e->Dst;
+ }
+ Tally = (vk2>>2)&(TWIDTH-1);
+ return v->key;
+}
+
+static ulong
+mk_key(Vertex *v) /* not sensitive to order */
+{ ulong m = 0, vk2 = 0;
+ Edge *e;
+
+ if (v->dst[0])
+ { m += HASH(v->dst[0], v->to[0] - v->from[0] + 1);
+ vk2 = (ulong) v->dst[0];
+ }
+ if (v->dst[1])
+ { m += HASH(v->dst[1], v->to[1] - v->from[1] + 1);
+ if ((ulong) v->dst[1] > vk2) vk2 = (ulong) v->dst[1];
+ }
+ for (e = v->Succ; e; e = e->Nxt)
+ { m += HASH(e->Dst, e->To - e->From + 1 + e->s);
+ if ((ulong) e->Dst > vk2) vk2 = (ulong) e->Dst;
+ }
+ Tally = (vk2>>2)&(TWIDTH-1);
+ return m;
+}
+
+static ulong
+mk_special(int sigma, Vertex *n, Vertex *v)
+{ ulong m = 0, vk2 = 0;
+ Edge *f;
+ int i;
+
+ for (i = 0; i < 2; i++)
+ if (v->dst[i])
+ { if (sigma >= v->from[i] && sigma <= v->to[i])
+ { m += HASH(v->dst[i], v->to[i]-v->from[i]);
+ if ((ulong) v->dst[i] > vk2
+ && v->to[i] > v->from[i])
+ vk2 = (ulong) v->dst[i];
+ } else
+ { m += HASH(v->dst[i], v->to[i]-v->from[i]+1);
+ if ((ulong) v->dst[i] > vk2)
+ vk2 = (ulong) v->dst[i];
+ } }
+ for (f = v->Succ; f; f = f->Nxt)
+ { if (sigma >= f->From && sigma <= f->To)
+ { m += HASH(f->Dst, f->To - f->From + f->s);
+ if ((ulong) f->Dst > vk2
+ && f->To - f->From + f->s > 0)
+ vk2 = (ulong) f->Dst;
+ } else if (f->s == 1 && sigma == f->S)
+ { m += HASH(f->Dst, f->To - f->From + 1);
+ if ((ulong) f->Dst > vk2) vk2 = (ulong) f->Dst;
+ } else
+ { m += HASH(f->Dst, f->To - f->From + 1 + f->s);
+ if ((ulong) f->Dst > vk2) vk2 = (ulong) f->Dst;
+ } }
+
+ if ((ulong) n > vk2) vk2 = (ulong) n;
+ Tally = (vk2>>2)&(TWIDTH-1);
+ m += HASH(n, 1);
+ return m;
+}
+
+void
+dfa_init(ushort nr_layers)
+{ int i; Vertex *r, *t;
+
+ dfa_depth = nr_layers; /* one byte per layer */
+ path = (Vertex **) emalloc((dfa_depth+1)*sizeof(Vertex *));
+ layers = (Vertex **) emalloc(TWIDTH*(dfa_depth+1)*sizeof(Vertex *));
+ lastword = (uchar *) emalloc((dfa_depth+1)*sizeof(uchar));
+ lastword[dfa_depth] = lastword[0] = 255;
+ path[0] = R = new_vertex(); F = new_vertex();
+
+ for (i = 1, r = R; i < dfa_depth; i++, r = t)
+ t = allDelta(r, i-1);
+ NF = allDelta(r, i-1);
+}
+
+#if 0
+static void complement_dfa(void) { Vertex *tmp = F; F = NF; NF = tmp; }
+#endif
+
+double
+tree_stats(Vertex *t)
+{ Edge *e; double cnt=0.0;
+ if (!t) return 0;
+ if (!t->key) return 0;
+ t->key = 0; /* precaution */
+ if (t->dst[0]) cnt++;
+ if (t->dst[1]) cnt++;
+ for (e = t->Succ; e; e = e->Nxt)
+ cnt++;
+ cnt += tree_stats(t->lnk);
+ cnt += tree_stats(t->left);
+ cnt += tree_stats(t->right);
+ return cnt;
+}
+
+void
+dfa_stats(void)
+{ int i, j; double cnt = 0.0;
+ for (j = 0; j < TWIDTH; j++)
+ for (i = 0; i < dfa_depth+1; i++)
+ cnt += tree_stats(layers[i*TWIDTH+j]);
+ printf("Minimized Automaton: %6d nodes and %6g edges\n",
+ nr_states, cnt);
+}
+
+int
+dfa_member(ulong n)
+{ Vertex **p, **q;
+ uchar *w = &word[n];
+ int i;
+
+ p = &path[n]; q = (p+1);
+ for (i = n; i < dfa_depth; i++)
+ *q++ = Delta(*p++, *w++);
+ return (*p == F);
+}
+
+int
+dfa_store(uchar *sv)
+{ Vertex **p, **q, *s, *y, *old, *new = F;
+ uchar *w, *u = lastword;
+ int i, j, k;
+
+ w = word = sv;
+ while (*w++ == *u++) /* find first byte that differs */
+ ;
+ pfrst = (int) (u - lastword) - 1;
+ memcpy(&lastword[pfrst], &sv[pfrst], dfa_depth-pfrst);
+ if (pfrst > iv) pfrst = iv;
+ if (pfrst > nv) pfrst = nv;
+/* phase1: */
+ p = &path[pfrst]; q = (p+1); w = &word[pfrst];
+ for (i = pfrst; i < dfa_depth; i++)
+ *q++ = Delta(*p++, *w++); /* (*p)->delta[*w++]; */
+
+ if (*p == F) return 1; /* it's already there */
+/* phase2: */
+ iv = dfa_depth;
+ do { iv--;
+ old = new;
+ new = find_it(path[iv], old, word[iv], iv);
+ } while (new && iv > 0);
+
+/* phase3: */
+ nv = k = 0; s = path[0];
+ for (j = 1; j <= iv; ++j)
+ if (path[j]->num > 1)
+ { y = new_vertex();
+ copyEdges(y, path[j]);
+ insert_it(y, j);
+ numDelta(y, 1);
+ delete_it(s, j-1);
+ setDelta(s, word[j-1], y);
+ insert_it(s, j-1);
+ y->num = 1; /* initial value 1 */
+ s = y;
+ path[j]->num--; /* only 1 moved from j to y */
+ k = 1;
+ } else
+ { s = path[j];
+ if (!k) nv = j;
+ }
+ y = Delta(s, word[iv]);
+ y->num--;
+ delete_it(s, iv);
+ setDelta(s, word[iv], old);
+ insert_it(s, iv);
+ old->num++;
+
+ for (j = iv+1; j < dfa_depth; j++)
+ if (path[j]->num == 0)
+ { numDelta(path[j], -1);
+ delete_it(path[j], j);
+ recyc_vertex(path[j]);
+ } else
+ break;
+ return 0;
+}
+
+static Vertex *
+splay(ulong i, Vertex *t)
+{ Vertex N, *l, *r, *y;
+
+ if (!t) return t;
+ N.left = N.right = (Vertex *) 0;
+ l = r = &N;
+ for (;;)
+ { if (i < t->key)
+ { if (!t->left) break;
+ if (i < t->left->key)
+ { y = t->left;
+ t->left = y->right;
+ y->right = t;
+ t = y;
+ if (!t->left) break;
+ }
+ r->left = t;
+ r = t;
+ t = t->left;
+ } else if (i > t->key)
+ { if (!t->right) break;
+ if (i > t->right->key)
+ { y = t->right;
+ t->right = y->left;
+ y->left = t;
+ t = y;
+ if (!t->right) break;
+ }
+ l->right = t;
+ l = t;
+ t = t->right;
+ } else
+ break;
+ }
+ l->right = t->left;
+ r->left = t->right;
+ t->left = N.right;
+ t->right = N.left;
+ return t;
+}
+
+static void
+insert_it(Vertex *v, int L)
+{ Vertex *new, *t;
+ ulong i; int nr;
+
+ i = mk_key(v);
+ nr = ((L*TWIDTH)+Tally);
+ t = layers[nr];
+
+ v->key = i;
+ if (!t)
+ { layers[nr] = v;
+ return;
+ }
+ t = splay(i, t);
+ if (i < t->key)
+ { new = v;
+ new->left = t->left;
+ new->right = t;
+ t->left = (Vertex *) 0;
+ } else if (i > t->key)
+ { new = v;
+ new->right = t->right;
+ new->left = t;
+ t->right = (Vertex *) 0;
+ } else /* it's already there */
+ { v->lnk = t->lnk; /* put in linked list off v */
+ t->lnk = v;
+ new = t;
+ }
+ layers[nr] = new;
+}
+
+static int
+checkit(Vertex *h, Vertex *v, Vertex *n, uchar sigma)
+{ Edge *g, *f;
+ int i, k, j = 1;
+
+ for (k = 0; k < 2; k++)
+ if (h->dst[k])
+ { if (sigma >= h->from[k] && sigma <= h->to[k])
+ { if (h->dst[k] != n) goto no_match;
+ }
+ for (i = h->from[k]; i <= h->to[k]; i++)
+ { if (i == sigma) continue;
+ g = cacheDelta(v, i, j); j = 0;
+ if (h->dst[k] != g->Dst)
+ goto no_match;
+ if (g->s == 0 || g->S != i)
+ i = g->To;
+ } }
+ for (f = h->Succ; f; f = f->Nxt)
+ { if (INRANGE(f,sigma))
+ { if (f->Dst != n) goto no_match;
+ }
+ for (i = f->From; i <= f->To; i++)
+ { if (i == sigma) continue;
+ g = cacheDelta(v, i, j); j = 0;
+ if (f->Dst != g->Dst)
+ goto no_match;
+ if (g->s == 1 && i == g->S)
+ continue;
+ i = g->To;
+ }
+ if (f->s && f->S != sigma)
+ { g = cacheDelta(v, f->S, 1);
+ if (f->Dst != g->Dst)
+ goto no_match;
+ }
+ }
+ if (h->Succ || h->dst[0] || h->dst[1]) return 1;
+no_match:
+ return 0;
+}
+
+static Vertex *
+find_it(Vertex *v, Vertex *n, uchar sigma, int L)
+{ Vertex *z, *t;
+ ulong i; int nr;
+
+ i = mk_special(sigma,n,v);
+ nr = ((L*TWIDTH)+Tally);
+ t = layers[nr];
+
+ if (!t) return (Vertex *) 0;
+ layers[nr] = t = splay(i, t);
+ if (i == t->key)
+ for (z = t; z; z = z->lnk)
+ if (checkit(z, v, n, sigma))
+ return z;
+
+ return (Vertex *) 0;
+}
+
+static void
+delete_it(Vertex *v, int L)
+{ Vertex *x, *t;
+ ulong i; int nr;
+
+ i = cheap_key(v);
+ nr = ((L*TWIDTH)+Tally);
+ t = layers[nr];
+ if (!t) return;
+
+ t = splay(i, t);
+ if (i == t->key)
+ { Vertex *z, *y = (Vertex *) 0;
+ for (z = t; z && z != v; y = z, z = z->lnk)
+ ;
+ if (z != v) goto bad;
+ if (y)
+ { y->lnk = z->lnk;
+ z->lnk = (Vertex *) 0;
+ layers[nr] = t;
+ return;
+ } else if (z->lnk) /* z == t == v */
+ { y = z->lnk;
+ y->left = t->left;
+ y->right = t->right;
+ t->left = t->right = t->lnk = (Vertex *) 0;
+ layers[nr] = y;
+ return;
+ }
+ /* delete the node itself */
+ if (!t->left)
+ { x = t->right;
+ } else
+ { x = splay(i, t->left);
+ x->right = t->right;
+ }
+ t->left = t->right = t->lnk = (Vertex *) 0;
+ layers[nr] = x;
+ return;
+ }
+bad: Uerror("cannot happen delete");
+}
+#endif
+#if defined(MA) && (defined(W_XPT) || defined(R_XPT))
+static Vertex **temptree;
+static char wbuf[4096];
+static int WCNT = 4096, wcnt=0;
+static uchar stacker[MA+1];
+static ulong stackcnt = 0;
+extern double nstates, nlinks, truncs, truncs2;
+
+static void
+xwrite(int fd, char *b, int n)
+{
+ if (wcnt+n >= 4096)
+ { write(fd, wbuf, wcnt);
+ wcnt = 0;
+ }
+ memcpy(&wbuf[wcnt], b, n);
+ wcnt += n;
+}
+
+static void
+wclose(fd)
+{
+ if (wcnt > 0)
+ write(fd, wbuf, wcnt);
+ wcnt = 0;
+ close(fd);
+}
+
+static void
+w_vertex(int fd, Vertex *v)
+{ char t[3]; int i; Edge *e;
+
+ xwrite(fd, (char *) &v, sizeof(Vertex *));
+ t[0] = 0;
+ for (i = 0; i < 2; i++)
+ if (v->dst[i])
+ { t[1] = v->from[i], t[2] = v->to[i];
+ xwrite(fd, t, 3);
+ xwrite(fd, (char *) &(v->dst[i]), sizeof(Vertex *));
+ }
+ for (e = v->Succ; e; e = e->Nxt)
+ { t[1] = e->From, t[2] = e->To;
+ xwrite(fd, t, 3);
+ xwrite(fd, (char *) &(e->Dst), sizeof(Vertex *));
+
+ if (e->s)
+ { t[1] = t[2] = e->S;
+ xwrite(fd, t, 3);
+ xwrite(fd, (char *) &(e->Dst), sizeof(Vertex *));
+ } }
+}
+
+static void
+w_layer(int fd, Vertex *v)
+{ uchar c=1;
+
+ if (!v) return;
+ xwrite(fd, (char *) &c, 1);
+ w_vertex(fd, v);
+ w_layer(fd, v->lnk);
+ w_layer(fd, v->left);
+ w_layer(fd, v->right);
+}
+
+void
+w_xpoint(void)
+{ int fd; char nm[64];
+ int i, j; uchar c;
+ static uchar xwarned = 0;
+
+ sprintf(nm, "%s.xpt", PanSource);
+ if ((fd = creat(nm, 0666)) <= 0)
+ if (!xwarned)
+ { xwarned = 1;
+ printf("cannot creat checkpoint file\n");
+ return;
+ }
+ xwrite(fd, (char *) &nstates, sizeof(double));
+ xwrite(fd, (char *) &truncs, sizeof(double));
+ xwrite(fd, (char *) &truncs2, sizeof(double));
+ xwrite(fd, (char *) &nlinks, sizeof(double));
+ xwrite(fd, (char *) &dfa_depth, sizeof(int));
+ xwrite(fd, (char *) &R, sizeof(Vertex *));
+ xwrite(fd, (char *) &F, sizeof(Vertex *));
+ xwrite(fd, (char *) &NF, sizeof(Vertex *));
+
+ for (j = 0; j < TWIDTH; j++)
+ for (i = 0; i < dfa_depth+1; i++)
+ { w_layer(fd, layers[i*TWIDTH+j]);
+ c = 2; xwrite(fd, (char *) &c, 1);
+ }
+ wclose(fd);
+}
+
+static void
+xread(int fd, char *b, int n)
+{ int m = wcnt; int delta = 0;
+ if (m < n)
+ { if (m > 0) memcpy(b, &wbuf[WCNT-m], m);
+ delta = m;
+ WCNT = wcnt = read(fd, wbuf, 4096);
+ if (wcnt < n-m)
+ Uerror("xread failed -- insufficient data");
+ n -= m;
+ }
+ memcpy(&b[delta], &wbuf[WCNT-wcnt], n);
+ wcnt -= n;
+}
+
+static void
+x_cleanup(Vertex *c)
+{ Edge *e; /* remove the tree and edges from c */
+ if (!c) return;
+ for (e = c->Succ; e; e = e->Nxt)
+ x_cleanup(e->Dst);
+ recyc_vertex(c);
+}
+
+static void
+x_remove(void)
+{ Vertex *tmp; int i, s;
+ int r, j;
+ /* double-check: */
+ stacker[dfa_depth-1] = 0; r = dfa_store(stacker);
+ stacker[dfa_depth-1] = 4; j = dfa_member(dfa_depth-1);
+ if (r != 1 || j != 0)
+ { printf("%d: ", stackcnt);
+ for (i = 0; i < dfa_depth; i++)
+ printf("%d,", stacker[i]);
+ printf(" -- not a stackstate <o:%d,4:%d>\n", r, j);
+ return;
+ }
+ stacker[dfa_depth-1] = 1;
+ s = dfa_member(dfa_depth-1);
+
+ { tmp = F; F = NF; NF = tmp; } /* complement */
+ if (s) dfa_store(stacker);
+ stacker[dfa_depth-1] = 0;
+ dfa_store(stacker);
+ stackcnt++;
+ { tmp = F; F = NF; NF = tmp; }
+}
+
+static void
+x_rm_stack(Vertex *t, int k)
+{ int j; Edge *e;
+
+ if (k == 0)
+ { x_remove();
+ return;
+ }
+ if (t)
+ for (e = t->Succ; e; e = e->Nxt)
+ { for (j = e->From; j <= (int) e->To; j++)
+ { stacker[k] = (uchar) j;
+ x_rm_stack(e->Dst, k-1);
+ }
+ if (e->s)
+ { stacker[k] = e->S;
+ x_rm_stack(e->Dst, k-1);
+ } }
+}
+
+static Vertex *
+insert_withkey(Vertex *v, int L)
+{ Vertex *new, *t = temptree[L];
+
+ if (!t) { temptree[L] = v; return v; }
+ t = splay(v->key, t);
+ if (v->key < t->key)
+ { new = v;
+ new->left = t->left;
+ new->right = t;
+ t->left = (Vertex *) 0;
+ } else if (v->key > t->key)
+ { new = v;
+ new->right = t->right;
+ new->left = t;
+ t->right = (Vertex *) 0;
+ } else
+ { if (t != R && t != F && t != NF)
+ Uerror("double insert, bad checkpoint data");
+ else
+ { recyc_vertex(v);
+ new = t;
+ } }
+ temptree[L] = new;
+
+ return new;
+}
+
+static Vertex *
+find_withkey(Vertex *v, int L)
+{ Vertex *t = temptree[L];
+ if (t)
+ { temptree[L] = t = splay((ulong) v, t);
+ if (t->key == (ulong) v)
+ return t;
+ }
+ Uerror("not found error, bad checkpoint data");
+ return (Vertex *) 0;
+}
+
+void
+r_layer(int fd, int n)
+{ Vertex *v;
+ Edge *e;
+ char c, t[2];
+
+ for (;;)
+ { xread(fd, &c, 1);
+ if (c == 2) break;
+ if (c == 1)
+ { v = new_vertex();
+ xread(fd, (char *) &(v->key), sizeof(Vertex *));
+ v = insert_withkey(v, n);
+ } else /* c == 0 */
+ { e = new_edge((Vertex *) 0);
+ xread(fd, t, 2);
+ e->From = t[0];
+ e->To = t[1];
+ xread(fd, (char *) &(e->Dst), sizeof(Vertex *));
+ insert_edge(v, e);
+ } }
+}
+
+static void
+v_fix(Vertex *t, int nr)
+{ int i; Edge *e;
+
+ if (!t) return;
+
+ for (i = 0; i < 2; i++)
+ if (t->dst[i])
+ t->dst[i] = find_withkey(t->dst[i], nr);
+
+ for (e = t->Succ; e; e = e->Nxt)
+ e->Dst = find_withkey(e->Dst, nr);
+
+ v_fix(t->left, nr);
+ v_fix(t->right, nr);
+}
+
+static void
+v_insert(Vertex *t, int nr)
+{ Edge *e; int i;
+
+ if (!t) return;
+ v_insert(t->left, nr);
+ v_insert(t->right, nr);
+
+ /* remove only leafs from temptree */
+ t->left = t->right = t->lnk = (Vertex *) 0;
+ insert_it(t, nr); /* into layers */
+ for (i = 0; i < 2; i++)
+ if (t->dst[i])
+ t->dst[i]->num += (t->to[i] - t->from[i] + 1);
+ for (e = t->Succ; e; e = e->Nxt)
+ e->Dst->num += (e->To - e->From + 1 + e->s);
+}
+
+static void
+x_fixup(void)
+{ int i;
+
+ for (i = 0; i < dfa_depth; i++)
+ v_fix(temptree[i], (i+1));
+
+ for (i = dfa_depth; i >= 0; i--)
+ v_insert(temptree[i], i);
+}
+
+static Vertex *
+x_tail(Vertex *t, ulong want)
+{ int i, yes, no; Edge *e; Vertex *v = (Vertex *) 0;
+
+ if (!t) return v;
+
+ yes = no = 0;
+ for (i = 0; i < 2; i++)
+ if ((ulong) t->dst[i] == want)
+ { /* was t->from[i] <= 0 && t->to[i] >= 0 */
+ /* but from and to are uchar */
+ if (t->from[i] == 0)
+ yes = 1;
+ else
+ if (t->from[i] <= 4 && t->to[i] >= 4)
+ no = 1;
+ }
+
+ for (e = t->Succ; e; e = e->Nxt)
+ if ((ulong) e->Dst == want)
+ { /* was INRANGE(e,0) but From and To are uchar */
+ if ((e->From == 0) || (e->s==1 && e->S==0))
+ yes = 1;
+ else if (INRANGE(e, 4))
+ no = 1;
+ }
+ if (yes && !no) return t;
+ v = x_tail(t->left, want); if (v) return v;
+ v = x_tail(t->right, want); if (v) return v;
+ return (Vertex *) 0;
+}
+
+static void
+x_anytail(Vertex *t, Vertex *c, int nr)
+{ int i; Edge *e, *f; Vertex *v;
+
+ if (!t) return;
+
+ for (i = 0; i < 2; i++)
+ if ((ulong) t->dst[i] == c->key)
+ { v = new_vertex(); v->key = t->key;
+ f = new_edge(v);
+ f->From = t->from[i];
+ f->To = t->to[i];
+ f->Nxt = c->Succ;
+ c->Succ = f;
+ if (nr > 0)
+ x_anytail(temptree[nr-1], v, nr-1);
+ }
+
+ for (e = t->Succ; e; e = e->Nxt)
+ if ((ulong) e->Dst == c->key)
+ { v = new_vertex(); v->key = t->key;
+ f = new_edge(v);
+ f->From = e->From;
+ f->To = e->To;
+ f->s = e->s;
+ f->S = e->S;
+ f->Nxt = c->Succ;
+ c->Succ = f;
+ x_anytail(temptree[nr-1], v, nr-1);
+ }
+
+ x_anytail(t->left, c, nr);
+ x_anytail(t->right, c, nr);
+}
+
+static Vertex *
+x_cpy_rev(void)
+{ Vertex *c, *v; /* find 0 and !4 predecessor of F */
+
+ v = x_tail(temptree[dfa_depth-1], F->key);
+ if (!v) return (Vertex *) 0;
+
+ c = new_vertex(); c->key = v->key;
+
+ /* every node on dfa_depth-2 that has v->key as succ */
+ /* make copy and let c point to these (reversing ptrs) */
+
+ x_anytail(temptree[dfa_depth-2], c, dfa_depth-2);
+
+ return c;
+}
+
+void
+r_xpoint(void)
+{ int fd; char nm[64]; Vertex *d;
+ int i, j;
+
+ wcnt = 0;
+ sprintf(nm, "%s.xpt", PanSource);
+ if ((fd = open(nm, 0)) < 0) /* O_RDONLY */
+ Uerror("cannot open checkpoint file");
+
+ xread(fd, (char *) &nstates, sizeof(double));
+ xread(fd, (char *) &truncs, sizeof(double));
+ xread(fd, (char *) &truncs2, sizeof(double));
+ xread(fd, (char *) &nlinks, sizeof(double));
+ xread(fd, (char *) &dfa_depth, sizeof(int));
+
+ if (dfa_depth != MA+a_cycles)
+ Uerror("bad dfa_depth in checkpoint file");
+
+ path = (Vertex **) emalloc((dfa_depth+1)*sizeof(Vertex *));
+ layers = (Vertex **) emalloc(TWIDTH*(dfa_depth+1)*sizeof(Vertex *));
+ temptree = (Vertex **) emalloc((dfa_depth+2)*sizeof(Vertex *));
+ lastword = (uchar *) emalloc((dfa_depth+1)*sizeof(uchar));
+ lastword[dfa_depth] = lastword[0] = 255;
+
+ path[0] = R = new_vertex();
+ xread(fd, (char *) &R->key, sizeof(Vertex *));
+ R = insert_withkey(R, 0);
+
+ F = new_vertex();
+ xread(fd, (char *) &F->key, sizeof(Vertex *));
+ F = insert_withkey(F, dfa_depth);
+
+ NF = new_vertex();
+ xread(fd, (char *) &NF->key, sizeof(Vertex *));
+ NF = insert_withkey(NF, dfa_depth);
+
+ for (j = 0; j < TWIDTH; j++)
+ for (i = 0; i < dfa_depth+1; i++)
+ r_layer(fd, i);
+
+ if (wcnt != 0) Uerror("bad count in checkpoint file");
+
+ d = x_cpy_rev();
+ x_fixup();
+ stacker[dfa_depth-1] = 0;
+ x_rm_stack(d, dfa_depth-2);
+ x_cleanup(d);
+ close(fd);
+
+ printf("pan: removed %d stackstates\n", stackcnt);
+ nstates -= (double) stackcnt;
+}
+#endif
+#ifdef VERI
+void
+check_claim(int st)
+{
+ if (st == endclaim)
+ uerror("claim violated!");
+ if (stopstate[VERI][st])
+ uerror("end state in claim reached");
+}
+#endif
+void
+c_globals(void)
+{ /* int i; */
+ printf("global vars:\n");
+ printf(" byte write_off: %d\n", now.write_off);
+ { int l_in;
+ for (l_in = 0; l_in < 2; l_in++)
+ {
+ printf(" byte commit_count[%d]: %d\n", l_in, now.commit_count[l_in]);
+ }
+ }
+ printf(" byte _commit_sum: %d\n", now._commit_sum);
+ printf(" byte read_off: %d\n", now.read_off);
+ printf(" byte events_lost: %d\n", now.events_lost);
+ printf(" byte refcount: %d\n", now.refcount);
+ { int l_in;
+ for (l_in = 0; l_in < 8; l_in++)
+ {
+ printf(" bit buffer_use[%d]: %d\n", l_in, now.buffer_use[l_in]);
+ }
+ }
+}
+void
+c_locals(int pid, int tp)
+{ /* int i; */
+ switch(tp) {
+ case 5:
+ /* none */
+ break;
+ case 4:
+ printf("local vars proc %d (:init:):\n", pid);
+ printf(" byte i: %d\n", ((P4 *)pptr(pid))->i);
+ printf(" byte j: %d\n", ((P4 *)pptr(pid))->j);
+ printf(" byte sum: %d\n", ((P4 *)pptr(pid))->sum);
+ printf(" byte commit_sum: %d\n", ((P4 *)pptr(pid))->commit_sum);
+ break;
+ case 3:
+ /* none */
+ break;
+ case 2:
+ printf("local vars proc %d (reader):\n", pid);
+ printf(" byte i: %d\n", ((P2 *)pptr(pid))->i);
+ printf(" byte j: %d\n", ((P2 *)pptr(pid))->j);
+ break;
+ case 1:
+ printf("local vars proc %d (tracer):\n", pid);
+ printf(" byte size: %d\n", ((P1 *)pptr(pid))->size);
+ printf(" byte prev_off: %d\n", ((P1 *)pptr(pid))->prev_off);
+ printf(" byte new_off: %d\n", ((P1 *)pptr(pid))->new_off);
+ printf(" byte tmp_commit: %d\n", ((P1 *)pptr(pid))->tmp_commit);
+ printf(" byte i: %d\n", ((P1 *)pptr(pid))->i);
+ printf(" byte j: %d\n", ((P1 *)pptr(pid))->j);
+ break;
+ case 0:
+ printf("local vars proc %d (switcher):\n", pid);
+ printf(" byte prev_off: %d\n", ((P0 *)pptr(pid))->prev_off);
+ printf(" byte new_off: %d\n", ((P0 *)pptr(pid))->new_off);
+ printf(" byte tmp_commit: %d\n", ((P0 *)pptr(pid))->tmp_commit);
+ printf(" byte size: %d\n", ((P0 *)pptr(pid))->size);
+ break;
+ }
+}
+void
+printm(int x)
+{
+ switch (x) {
+ default: Printf("%d", x);
+ }
+}
+void
+c_chandump(int unused) { unused++; /* avoid complaints */ }
--- /dev/null
+#define SpinVersion "Spin Version 5.1.6 -- 9 May 2008"
+#define PanSource "pan.spin"
+
+#ifdef WIN64
+#define ONE_L ((unsigned long) 1)
+#define long long long
+#else
+#define ONE_L (1L)
+#endif
+char *TrailFile = PanSource; /* default */
+char *trailfilename;
+#if defined(BFS)
+#ifndef SAFETY
+#define SAFETY
+#endif
+#ifndef XUSAFE
+#define XUSAFE
+#endif
+#endif
+#ifndef uchar
+#define uchar unsigned char
+#endif
+#ifndef uint
+#define uint unsigned int
+#endif
+#define DELTA 500
+#ifdef MA
+ #if NCORE>1 && !defined(SEP_STATE)
+ #define SEP_STATE
+ #endif
+#if MA==1
+#undef MA
+#define MA 100
+#endif
+#endif
+#ifdef W_XPT
+#if W_XPT==1
+#undef W_XPT
+#define W_XPT 1000000
+#endif
+#endif
+#ifndef NFAIR
+#define NFAIR 2 /* must be >= 2 */
+#endif
+#define HAS_CODE
+#define MERGED 1
+#ifdef NP /* includes np_ demon */
+#define HAS_NP 2
+#define VERI 6
+#define endclaim 3 /* none */
+#endif
+#if !defined(NOCLAIM) && !defined NP
+#define VERI 5
+#define endclaim endstate5
+#endif
+typedef struct S_F_MAP {
+ char *fnm; int from; int upto;
+} S_F_MAP;
+
+#define nstates5 9 /* :never: */
+#define nstates_claim nstates5
+#define endstate5 8
+short src_ln5 [] = {
+ 0, 304, 304, 305, 305, 303, 307, 308,
+ 309, 0, };
+S_F_MAP src_file5 [] = {
+ { "-", 0, 0 },
+ { "pan.___", 1, 8 },
+ { "-", 9, 10 }
+};
+#define src_claim src_ln5
+uchar reached5 [] = {
+ 0, 1, 1, 1, 1, 0, 1, 1,
+ 0, 0, };
+uchar *loopstate5;
+#define reached_claim reached5
+
+#define nstates4 44 /* :init: */
+#define endstate4 43
+short src_ln4 [] = {
+ 0, 255, 257, 258, 259, 260, 260, 256,
+ 263, 256, 263, 265, 267, 268, 269, 270,
+ 270, 266, 272, 266, 272, 273, 274, 276,
+ 277, 278, 279, 280, 280, 275, 282, 275,
+ 282, 284, 285, 286, 287, 288, 288, 283,
+ 290, 283, 254, 291, 0, };
+S_F_MAP src_file4 [] = {
+ { "-", 0, 0 },
+ { "pan.___", 1, 43 },
+ { "-", 44, 45 }
+};
+uchar reached4 [] = {
+ 0, 1, 1, 0, 0, 1, 1, 0,
+ 1, 1, 0, 0, 1, 0, 0, 1,
+ 1, 0, 1, 1, 0, 0, 0, 1,
+ 0, 0, 0, 1, 1, 0, 1, 1,
+ 0, 1, 0, 0, 0, 1, 1, 0,
+ 1, 1, 0, 0, 0, };
+uchar *loopstate4;
+
+#define nstates3 10 /* cleaner */
+#define endstate3 9
+short src_ln3 [] = {
+ 0, 240, 241, 242, 243, 239, 245, 239,
+ 238, 246, 0, };
+S_F_MAP src_file3 [] = {
+ { "-", 0, 0 },
+ { "pan.___", 1, 9 },
+ { "-", 10, 11 }
+};
+uchar reached3 [] = {
+ 0, 1, 0, 0, 1, 0, 1, 1,
+ 0, 0, 0, };
+uchar *loopstate3;
+
+#define nstates2 30 /* reader */
+#define endstate2 29
+short src_ln2 [] = {
+ 0, 203, 205, 207, 208, 209, 210, 211,
+ 211, 206, 213, 206, 204, 219, 221, 222,
+ 223, 224, 224, 220, 226, 220, 226, 218,
+ 228, 228, 198, 230, 198, 230, 0, };
+S_F_MAP src_file2 [] = {
+ { "-", 0, 0 },
+ { "pan.___", 1, 29 },
+ { "-", 30, 31 }
+};
+uchar reached2 [] = {
+ 0, 1, 1, 1, 0, 0, 0, 1,
+ 1, 0, 1, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 1, 0, 0,
+ 1, 1, 0, 1, 1, 0, 0, };
+uchar *loopstate2;
+
+#define nstates1 52 /* tracer */
+#define endstate1 51
+short src_ln1 [] = {
+ 0, 126, 127, 125, 131, 132, 133, 133,
+ 130, 135, 129, 138, 138, 139, 139, 137,
+ 141, 141, 143, 144, 145, 146, 147, 147,
+ 142, 149, 142, 136, 155, 157, 158, 159,
+ 160, 160, 156, 162, 156, 162, 164, 167,
+ 170, 171, 172, 173, 168, 175, 154, 177,
+ 179, 181, 176, 183, 0, };
+S_F_MAP src_file1 [] = {
+ { "-", 0, 0 },
+ { "pan.___", 1, 51 },
+ { "-", 52, 53 }
+};
+uchar reached1 [] = {
+ 0, 1, 0, 0, 1, 1, 1, 0,
+ 1, 1, 0, 1, 1, 1, 0, 1,
+ 1, 0, 1, 0, 0, 0, 1, 1,
+ 0, 1, 1, 0, 1, 1, 0, 0,
+ 1, 1, 0, 1, 1, 0, 0, 0,
+ 1, 0, 1, 0, 0, 1, 0, 1,
+ 0, 0, 0, 0, 0, };
+uchar *loopstate1;
+
+#define nstates0 32 /* switcher */
+#define endstate0 31
+short src_ln0 [] = {
+ 0, 75, 76, 77, 80, 81, 82, 83,
+ 83, 78, 85, 74, 88, 88, 89, 89,
+ 87, 91, 86, 94, 96, 99, 102, 103,
+ 104, 105, 100, 107, 107, 93, 110, 111,
+ 0, };
+S_F_MAP src_file0 [] = {
+ { "-", 0, 0 },
+ { "pan.___", 1, 31 },
+ { "-", 32, 33 }
+};
+uchar reached0 [] = {
+ 0, 1, 0, 0, 1, 0, 1, 1,
+ 0, 0, 1, 0, 1, 1, 1, 0,
+ 1, 1, 0, 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0, 0, 1, 0,
+ 0, };
+uchar *loopstate0;
+struct {
+ int tp; short *src;
+} src_all[] = {
+ { 5, &src_ln5[0] },
+ { 4, &src_ln4[0] },
+ { 3, &src_ln3[0] },
+ { 2, &src_ln2[0] },
+ { 1, &src_ln1[0] },
+ { 0, &src_ln0[0] },
+ { 0, (short *) 0 }
+};
+short *frm_st0;
+struct {
+ char *c; char *t;
+} code_lookup[] = {
+ { (char *) 0, "" }
+};
+#define _T5 62
+#define _T2 63
+#define T_ID unsigned char
+#define SYNC 0
+#define ASYNC 0
+
+#ifndef NCORE
+ #ifdef DUAL_CORE
+ #define NCORE 2
+ #elif QUAD_CORE
+ #define NCORE 4
+ #else
+ #define NCORE 1
+ #endif
+#endif
+char *procname[] = {
+ "switcher",
+ "tracer",
+ "reader",
+ "cleaner",
+ ":init:",
+ ":never:",
+ ":np_:",
+};
+
+typedef struct P5 { /* :never: */
+ unsigned _pid : 8; /* 0..255 */
+ unsigned _t : 4; /* proctype */
+ unsigned _p : 7; /* state */
+} P5;
+#define Air5 (sizeof(P5) - 3)
+#define Pinit ((P4 *)this)
+typedef struct P4 { /* :init: */
+ unsigned _pid : 8; /* 0..255 */
+ unsigned _t : 4; /* proctype */
+ unsigned _p : 7; /* state */
+ uchar i;
+ uchar j;
+ uchar sum;
+ uchar commit_sum;
+} P4;
+#define Air4 (sizeof(P4) - Offsetof(P4, commit_sum) - 1*sizeof(uchar))
+#define Pcleaner ((P3 *)this)
+typedef struct P3 { /* cleaner */
+ unsigned _pid : 8; /* 0..255 */
+ unsigned _t : 4; /* proctype */
+ unsigned _p : 7; /* state */
+} P3;
+#define Air3 (sizeof(P3) - 3)
+#define Preader ((P2 *)this)
+typedef struct P2 { /* reader */
+ unsigned _pid : 8; /* 0..255 */
+ unsigned _t : 4; /* proctype */
+ unsigned _p : 7; /* state */
+ uchar i;
+ uchar j;
+} P2;
+#define Air2 (sizeof(P2) - Offsetof(P2, j) - 1*sizeof(uchar))
+#define Ptracer ((P1 *)this)
+typedef struct P1 { /* tracer */
+ unsigned _pid : 8; /* 0..255 */
+ unsigned _t : 4; /* proctype */
+ unsigned _p : 7; /* state */
+ uchar size;
+ uchar prev_off;
+ uchar new_off;
+ uchar tmp_commit;
+ uchar i;
+ uchar j;
+} P1;
+#define Air1 (sizeof(P1) - Offsetof(P1, j) - 1*sizeof(uchar))
+#define Pswitcher ((P0 *)this)
+typedef struct P0 { /* switcher */
+ unsigned _pid : 8; /* 0..255 */
+ unsigned _t : 4; /* proctype */
+ unsigned _p : 7; /* state */
+ uchar prev_off;
+ uchar new_off;
+ uchar tmp_commit;
+ uchar size;
+} P0;
+#define Air0 (sizeof(P0) - Offsetof(P0, size) - 1*sizeof(uchar))
+typedef struct P6 { /* np_ */
+ unsigned _pid : 8; /* 0..255 */
+ unsigned _t : 4; /* proctype */
+ unsigned _p : 7; /* state */
+} P6;
+#define Air6 (sizeof(P6) - 3)
+#if defined(BFS) && defined(REACH)
+#undef REACH
+#endif
+#ifdef VERI
+#define BASE 1
+#else
+#define BASE 0
+#endif
+typedef struct Trans {
+ short atom; /* if &2 = atomic trans; if &8 local */
+#ifdef HAS_UNLESS
+ short escp[HAS_UNLESS]; /* lists the escape states */
+ short e_trans; /* if set, this is an escp-trans */
+#endif
+ short tpe[2]; /* class of operation (for reduction) */
+ short qu[6]; /* for conditional selections: qid's */
+ uchar ty[6]; /* ditto: type's */
+#ifdef NIBIS
+ short om; /* completion status of preselects */
+#endif
+ char *tp; /* src txt of statement */
+ int st; /* the nextstate */
+ int t_id; /* transition id, unique within proc */
+ int forw; /* index forward transition */
+ int back; /* index return transition */
+ struct Trans *nxt;
+} Trans;
+
+#define qptr(x) (((uchar *)&now)+(int)q_offset[x])
+#define pptr(x) (((uchar *)&now)+(int)proc_offset[x])
+extern uchar *Pptr(int);
+#define q_sz(x) (((Q0 *)qptr(x))->Qlen)
+
+#ifndef VECTORSZ
+#define VECTORSZ 1024 /* sv size in bytes */
+#endif
+
+#ifdef VERBOSE
+#ifndef CHECK
+#define CHECK
+#endif
+#ifndef DEBUG
+#define DEBUG
+#endif
+#endif
+#ifdef SAFETY
+#ifndef NOFAIR
+#define NOFAIR
+#endif
+#endif
+#ifdef NOREDUCE
+#ifndef XUSAFE
+#define XUSAFE
+#endif
+#if !defined(SAFETY) && !defined(MA)
+#define FULLSTACK
+#endif
+#else
+#ifdef BITSTATE
+#if defined(SAFETY) && !defined(HASH64)
+#define CNTRSTACK
+#else
+#define FULLSTACK
+#endif
+#else
+#define FULLSTACK
+#endif
+#endif
+#ifdef BITSTATE
+#ifndef NOCOMP
+#define NOCOMP
+#endif
+#if !defined(LC) && defined(SC)
+#define LC
+#endif
+#endif
+#if defined(COLLAPSE2) || defined(COLLAPSE3) || defined(COLLAPSE4)
+/* accept the above for backward compatibility */
+#define COLLAPSE
+#endif
+#ifdef HC
+#undef HC
+#define HC4
+#endif
+#ifdef HC0
+#define HC 0
+#endif
+#ifdef HC1
+#define HC 1
+#endif
+#ifdef HC2
+#define HC 2
+#endif
+#ifdef HC3
+#define HC 3
+#endif
+#ifdef HC4
+#define HC 4
+#endif
+#ifdef COLLAPSE
+#if NCORE>1 && !defined(SEP_STATE)
+unsigned long *ncomps; /* in shared memory */
+#else
+unsigned long ncomps[256+2];
+#endif
+#endif
+#define MAXQ 255
+#define MAXPROC 255
+#define WS sizeof(void *) /* word size in bytes */
+typedef struct Stack { /* for queues and processes */
+#if VECTORSZ>32000
+ int o_delta;
+ int o_offset;
+ int o_skip;
+ int o_delqs;
+#else
+ short o_delta;
+ short o_offset;
+ short o_skip;
+ short o_delqs;
+#endif
+ short o_boq;
+#ifndef XUSAFE
+ char *o_name;
+#endif
+ char *body;
+ struct Stack *nxt;
+ struct Stack *lst;
+} Stack;
+
+typedef struct Svtack { /* for complete state vector */
+#if VECTORSZ>32000
+ int o_delta;
+ int m_delta;
+#else
+ short o_delta; /* current size of frame */
+ short m_delta; /* maximum size of frame */
+#endif
+#if SYNC
+ short o_boq;
+#endif
+#define StackSize (WS)
+ char *body;
+ struct Svtack *nxt;
+ struct Svtack *lst;
+} Svtack;
+
+Trans ***trans; /* 1 ptr per state per proctype */
+
+struct H_el *Lstate;
+int depthfound = -1; /* loop detection */
+#if VECTORSZ>32000
+int proc_offset[MAXPROC];
+int q_offset[MAXQ];
+#else
+short proc_offset[MAXPROC];
+short q_offset[MAXQ];
+#endif
+uchar proc_skip[MAXPROC];
+uchar q_skip[MAXQ];
+unsigned long vsize; /* vector size in bytes */
+#ifdef SVDUMP
+int vprefix=0, svfd; /* runtime option -pN */
+#endif
+char *tprefix = "trail"; /* runtime option -tsuffix */
+short boq = -1; /* blocked_on_queue status */
+typedef struct State {
+ uchar _nr_pr;
+ uchar _nr_qs;
+ uchar _a_t; /* cycle detection */
+#ifndef NOFAIR
+ uchar _cnt[NFAIR]; /* counters, weak fairness */
+#endif
+#ifndef NOVSZ
+#if VECTORSZ<65536
+ unsigned short _vsz;
+#else
+ unsigned long _vsz;
+#endif
+#endif
+#ifdef HAS_LAST
+ uchar _last; /* pid executed in last step */
+#endif
+#ifdef EVENT_TRACE
+#if nstates_event<256
+ uchar _event;
+#else
+ unsigned short _event;
+#endif
+#endif
+ uchar buffer_use[8];
+ uchar write_off;
+ uchar commit_count[2];
+ uchar _commit_sum;
+ uchar read_off;
+ uchar events_lost;
+ uchar refcount;
+ uchar sv[VECTORSZ];
+} State;
+
+#define HAS_TRACK 0
+/* hidden variable: */ uchar deliver;
+int _; /* a predefined write-only variable */
+
+#define FORWARD_MOVES "pan.m"
+#define REVERSE_MOVES "pan.b"
+#define TRANSITIONS "pan.t"
+#define _NP_ 6
+uchar reached6[3]; /* np_ */
+uchar *loopstate6; /* np_ */
+#define nstates6 3 /* np_ */
+#define endstate6 2 /* np_ */
+
+#define start6 0 /* np_ */
+#define start5 5
+#define start_claim 5
+#define start4 42
+#define start3 8
+#define start2 26
+#define start1 3
+#define start0 11
+#ifdef NP
+ #define ACCEPT_LAB 1 /* at least 1 in np_ */
+#else
+ #define ACCEPT_LAB 1 /* user-defined accept labels */
+#endif
+#ifdef MEMCNT
+ #ifdef MEMLIM
+ #warning -DMEMLIM takes precedence over -DMEMCNT
+ #undef MEMCNT
+ #else
+ #if MEMCNT<20
+ #warning using minimal value -DMEMCNT=20 (=1MB)
+ #define MEMLIM (1)
+ #undef MEMCNT
+ #else
+ #if MEMCNT==20
+ #define MEMLIM (1)
+ #undef MEMCNT
+ #else
+ #if MEMCNT>=50
+ #error excessive value for MEMCNT
+ #else
+ #define MEMLIM (1<<(MEMCNT-20))
+ #endif
+ #endif
+ #endif
+ #endif
+#endif
+#if NCORE>1 && !defined(MEMLIM)
+ #define MEMLIM (2048) /* need a default, using 2 GB */
+#endif
+#define PROG_LAB 0 /* progress labels */
+uchar *accpstate[7];
+uchar *progstate[7];
+uchar *loopstate[7];
+uchar *reached[7];
+uchar *stopstate[7];
+uchar *visstate[7];
+short *mapstate[7];
+#ifdef HAS_CODE
+int NrStates[7];
+#endif
+#define NQS 0
+short q_flds[1];
+short q_max[1];
+typedef struct Q0 { /* generic q */
+ uchar Qlen; /* q_size */
+ uchar _t;
+} Q0;
+
+/** function prototypes **/
+char *emalloc(unsigned long);
+char *Malloc(unsigned long);
+int Boundcheck(int, int, int, int, Trans *);
+int addqueue(int, int);
+/* int atoi(char *); */
+/* int abort(void); */
+int close(int);
+int delproc(int, int);
+int endstate(void);
+int hstore(char *, int);
+#ifdef MA
+int gstore(char *, int, uchar);
+#endif
+int q_cond(short, Trans *);
+int q_full(int);
+int q_len(int);
+int q_zero(int);
+int qrecv(int, int, int, int);
+int unsend(int);
+/* void *sbrk(int); */
+void Uerror(char *);
+void assert(int, char *, int, int, Trans *);
+void c_chandump(int);
+void c_globals(void);
+void c_locals(int, int);
+void checkcycles(void);
+void crack(int, int, Trans *, short *);
+void d_sfh(const char *, int);
+void sfh(const char *, int);
+void d_hash(uchar *, int);
+void s_hash(uchar *, int);
+void r_hash(uchar *, int);
+void delq(int);
+void do_reach(void);
+void pan_exit(int);
+void exit(int);
+void hinit(void);
+void imed(Trans *, int, int, int);
+void new_state(void);
+void p_restor(int);
+void putpeg(int, int);
+void putrail(void);
+void q_restor(void);
+void retrans(int, int, int, short *, uchar *, uchar *);
+void settable(void);
+void setq_claim(int, int, char *, int, char *);
+void sv_restor(void);
+void sv_save(void);
+void tagtable(int, int, int, short *, uchar *);
+void do_dfs(int, int, int, short *, uchar *, uchar *);
+void uerror(char *);
+void unrecv(int, int, int, int, int);
+void usage(FILE *);
+void wrap_stats(void);
+#if defined(FULLSTACK) && defined(BITSTATE)
+int onstack_now(void);
+void onstack_init(void);
+void onstack_put(void);
+void onstack_zap(void);
+#endif
+#ifndef XUSAFE
+int q_S_check(int, int);
+int q_R_check(int, int);
+uchar q_claim[MAXQ+1];
+char *q_name[MAXQ+1];
+char *p_name[MAXPROC+1];
+#endif
+void qsend(int, int, int);
+#define Addproc(x) addproc(x)
+#define LOCAL 1
+#define Q_FULL_F 2
+#define Q_EMPT_F 3
+#define Q_EMPT_T 4
+#define Q_FULL_T 5
+#define TIMEOUT_F 6
+#define GLOBAL 7
+#define BAD 8
+#define ALPHA_F 9
+#define NTRANS 64
+#ifdef PEG
+long peg[NTRANS];
+#endif
--- /dev/null
+#define rwoff1 (write_off - read_off >= 0)
+#define rwoff2 (write_off - read_off < HALF_UCHAR)
+
+#define wcsum1 (write_off - _commit_sum >= 0)
+#define wcsum2 (write_off - _commit_sum < HALF_UCHAR)
+
+#define buffer_large_enough (NUMPROCS + NUMSWITCH <= BUFSIZE)
+#define have_events_lost (events_lost != 0)
+never { /* !( []((buffer_large_enough) -> (!have_events_lost))) */
+T0_init:
+ if
+ :: ((buffer_large_enough) && (have_events_lost)) -> goto accept_all
+ :: (1) -> goto T0_init
+ fi;
+accept_all:
+ skip
+}
--- /dev/null
+#define rand pan_rand
+#if defined(HAS_CODE) && defined(VERBOSE)
+ cpu_printf("Pr: %d Tr: %d\n", II, t->forw);
+#endif
+ switch (t->forw) {
+ default: Uerror("bad forward move");
+ case 0: /* if without executable clauses */
+ continue;
+ case 1: /* generic 'goto' or 'skip' */
+ IfNotBlocked
+ _m = 3; goto P999;
+ case 2: /* generic 'else' */
+ IfNotBlocked
+ if (trpt->o_pm&1) continue;
+ _m = 3; goto P999;
+
+ /* PROC :never: */
+ case 3: /* STATE 1 - line 304 "pan.___" - [((((4+1)<=8)&&(events_lost!=0)))] (0:0:0 - 1) */
+
+#if defined(VERI) && !defined(NP)
+ { static int reported1 = 0;
+ if (verbose && !reported1)
+ { printf("depth %d: Claim reached state %d (line %d)\n",
+ depth, frm_st0[t->forw], src_claim[1]);
+ reported1 = 1;
+ fflush(stdout);
+ } }
+#endif
+ reached[5][1] = 1;
+ if (!((((4+1)<=8)&&(((int)now.events_lost)!=0))))
+ continue;
+ _m = 3; goto P999; /* 0 */
+ case 4: /* STATE 8 - line 309 "pan.___" - [-end-] (0:0:0 - 1) */
+
+#if defined(VERI) && !defined(NP)
+ { static int reported8 = 0;
+ if (verbose && !reported8)
+ { printf("depth %d: Claim reached state %d (line %d)\n",
+ depth, frm_st0[t->forw], src_claim[8]);
+ reported8 = 1;
+ fflush(stdout);
+ } }
+#endif
+ reached[5][8] = 1;
+ if (!delproc(1, II)) continue;
+ _m = 3; goto P999; /* 0 */
+
+ /* PROC :init: */
+ case 5: /* STATE 1 - line 255 "pan.___" - [i = 0] (0:0:1 - 1) */
+ IfNotBlocked
+ reached[4][1] = 1;
+ (trpt+1)->bup.oval = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ _m = 3; goto P999; /* 0 */
+ case 6: /* STATE 2 - line 257 "pan.___" - [((i<2))] (7:0:2 - 1) */
+ IfNotBlocked
+ reached[4][2] = 1;
+ if (!((((int)((P4 *)this)->i)<2)))
+ continue;
+ /* merge: commit_count[i] = 0(7, 3, 7) */
+ reached[4][3] = 1;
+ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((int)now.commit_count[ Index(((int)((P4 *)this)->i), 2) ]);
+ now.commit_count[ Index(((P4 *)this)->i, 2) ] = 0;
+#ifdef VAR_RANGES
+ logval("commit_count[:init::i]", ((int)now.commit_count[ Index(((int)((P4 *)this)->i), 2) ]));
+#endif
+ ;
+ /* merge: i = (i+1)(7, 4, 7) */
+ reached[4][4] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = (((int)((P4 *)this)->i)+1);
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 8, 7) */
+ reached[4][8] = 1;
+ ;
+ _m = 3; goto P999; /* 3 */
+ case 7: /* STATE 5 - line 260 "pan.___" - [((i>=2))] (17:0:3 - 1) */
+ IfNotBlocked
+ reached[4][5] = 1;
+ if (!((((int)((P4 *)this)->i)>=2)))
+ continue;
+ /* dead 1: i */ (trpt+1)->bup.ovals = grab_ints(3);
+ (trpt+1)->bup.ovals[0] = ((P4 *)this)->i;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P4 *)this)->i = 0;
+ /* merge: goto :b6(17, 6, 17) */
+ reached[4][6] = 1;
+ ;
+ /* merge: _commit_sum = 0(17, 10, 17) */
+ reached[4][10] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)now._commit_sum);
+ now._commit_sum = 0;
+#ifdef VAR_RANGES
+ logval("_commit_sum", ((int)now._commit_sum));
+#endif
+ ;
+ /* merge: i = 0(17, 11, 17) */
+ reached[4][11] = 1;
+ (trpt+1)->bup.ovals[2] = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 18, 17) */
+ reached[4][18] = 1;
+ ;
+ _m = 3; goto P999; /* 4 */
+ case 8: /* STATE 10 - line 263 "pan.___" - [_commit_sum = 0] (0:17:2 - 3) */
+ IfNotBlocked
+ reached[4][10] = 1;
+ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((int)now._commit_sum);
+ now._commit_sum = 0;
+#ifdef VAR_RANGES
+ logval("_commit_sum", ((int)now._commit_sum));
+#endif
+ ;
+ /* merge: i = 0(17, 11, 17) */
+ reached[4][11] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 18, 17) */
+ reached[4][18] = 1;
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 9: /* STATE 12 - line 267 "pan.___" - [((i<8))] (17:0:2 - 1) */
+ IfNotBlocked
+ reached[4][12] = 1;
+ if (!((((int)((P4 *)this)->i)<8)))
+ continue;
+ /* merge: buffer_use[i] = 0(17, 13, 17) */
+ reached[4][13] = 1;
+ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((int)now.buffer_use[ Index(((int)((P4 *)this)->i), 8) ]);
+ now.buffer_use[ Index(((P4 *)this)->i, 8) ] = 0;
+#ifdef VAR_RANGES
+ logval("buffer_use[:init::i]", ((int)now.buffer_use[ Index(((int)((P4 *)this)->i), 8) ]));
+#endif
+ ;
+ /* merge: i = (i+1)(17, 14, 17) */
+ reached[4][14] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = (((int)((P4 *)this)->i)+1);
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 18, 17) */
+ reached[4][18] = 1;
+ ;
+ _m = 3; goto P999; /* 3 */
+ case 10: /* STATE 15 - line 270 "pan.___" - [((i>=8))] (0:0:1 - 1) */
+ IfNotBlocked
+ reached[4][15] = 1;
+ if (!((((int)((P4 *)this)->i)>=8)))
+ continue;
+ /* dead 1: i */ (trpt+1)->bup.oval = ((P4 *)this)->i;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P4 *)this)->i = 0;
+ _m = 3; goto P999; /* 0 */
+ case 11: /* STATE 20 - line 272 "pan.___" - [(run reader())] (0:0:0 - 3) */
+ IfNotBlocked
+ reached[4][20] = 1;
+ if (!(addproc(2)))
+ continue;
+ _m = 3; goto P999; /* 0 */
+ case 12: /* STATE 21 - line 273 "pan.___" - [(run cleaner())] (29:0:1 - 1) */
+ IfNotBlocked
+ reached[4][21] = 1;
+ if (!(addproc(3)))
+ continue;
+ /* merge: i = 0(0, 22, 29) */
+ reached[4][22] = 1;
+ (trpt+1)->bup.oval = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 30, 29) */
+ reached[4][30] = 1;
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 13: /* STATE 23 - line 276 "pan.___" - [((i<4))] (25:0:1 - 1) */
+ IfNotBlocked
+ reached[4][23] = 1;
+ if (!((((int)((P4 *)this)->i)<4)))
+ continue;
+ /* merge: refcount = (refcount+1)(0, 24, 25) */
+ reached[4][24] = 1;
+ (trpt+1)->bup.oval = ((int)now.refcount);
+ now.refcount = (((int)now.refcount)+1);
+#ifdef VAR_RANGES
+ logval("refcount", ((int)now.refcount));
+#endif
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 14: /* STATE 25 - line 278 "pan.___" - [(run tracer())] (29:0:1 - 1) */
+ IfNotBlocked
+ reached[4][25] = 1;
+ if (!(addproc(1)))
+ continue;
+ /* merge: i = (i+1)(0, 26, 29) */
+ reached[4][26] = 1;
+ (trpt+1)->bup.oval = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = (((int)((P4 *)this)->i)+1);
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 30, 29) */
+ reached[4][30] = 1;
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 15: /* STATE 27 - line 280 "pan.___" - [((i>=4))] (39:0:2 - 1) */
+ IfNotBlocked
+ reached[4][27] = 1;
+ if (!((((int)((P4 *)this)->i)>=4)))
+ continue;
+ /* dead 1: i */ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((P4 *)this)->i;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P4 *)this)->i = 0;
+ /* merge: goto :b8(39, 28, 39) */
+ reached[4][28] = 1;
+ ;
+ /* merge: i = 0(39, 32, 39) */
+ reached[4][32] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 40, 39) */
+ reached[4][40] = 1;
+ ;
+ _m = 3; goto P999; /* 3 */
+ case 16: /* STATE 32 - line 282 "pan.___" - [i = 0] (0:39:1 - 3) */
+ IfNotBlocked
+ reached[4][32] = 1;
+ (trpt+1)->bup.oval = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 40, 39) */
+ reached[4][40] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 17: /* STATE 33 - line 284 "pan.___" - [((i<1))] (35:0:1 - 1) */
+ IfNotBlocked
+ reached[4][33] = 1;
+ if (!((((int)((P4 *)this)->i)<1)))
+ continue;
+ /* merge: refcount = (refcount+1)(0, 34, 35) */
+ reached[4][34] = 1;
+ (trpt+1)->bup.oval = ((int)now.refcount);
+ now.refcount = (((int)now.refcount)+1);
+#ifdef VAR_RANGES
+ logval("refcount", ((int)now.refcount));
+#endif
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 18: /* STATE 35 - line 286 "pan.___" - [(run switcher())] (39:0:1 - 1) */
+ IfNotBlocked
+ reached[4][35] = 1;
+ if (!(addproc(0)))
+ continue;
+ /* merge: i = (i+1)(0, 36, 39) */
+ reached[4][36] = 1;
+ (trpt+1)->bup.oval = ((int)((P4 *)this)->i);
+ ((P4 *)this)->i = (((int)((P4 *)this)->i)+1);
+#ifdef VAR_RANGES
+ logval(":init::i", ((int)((P4 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 40, 39) */
+ reached[4][40] = 1;
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 19: /* STATE 37 - line 288 "pan.___" - [((i>=1))] (41:0:1 - 1) */
+ IfNotBlocked
+ reached[4][37] = 1;
+ if (!((((int)((P4 *)this)->i)>=1)))
+ continue;
+ /* dead 1: i */ (trpt+1)->bup.oval = ((P4 *)this)->i;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P4 *)this)->i = 0;
+ /* merge: goto :b9(0, 38, 41) */
+ reached[4][38] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 20: /* STATE 43 - line 291 "pan.___" - [-end-] (0:0:0 - 1) */
+ IfNotBlocked
+ reached[4][43] = 1;
+ if (!delproc(1, II)) continue;
+ _m = 3; goto P999; /* 0 */
+
+ /* PROC cleaner */
+ case 21: /* STATE 1 - line 240 "pan.___" - [((refcount==0))] (3:0:1 - 1) */
+ IfNotBlocked
+ reached[3][1] = 1;
+ if (!((((int)now.refcount)==0)))
+ continue;
+ /* merge: refcount = (refcount+1)(0, 2, 3) */
+ reached[3][2] = 1;
+ (trpt+1)->bup.oval = ((int)now.refcount);
+ now.refcount = (((int)now.refcount)+1);
+#ifdef VAR_RANGES
+ logval("refcount", ((int)now.refcount));
+#endif
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 22: /* STATE 3 - line 242 "pan.___" - [(run switcher())] (7:0:0 - 1) */
+ IfNotBlocked
+ reached[3][3] = 1;
+ if (!(addproc(0)))
+ continue;
+ /* merge: goto :b5(0, 4, 7) */
+ reached[3][4] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 23: /* STATE 9 - line 246 "pan.___" - [-end-] (0:0:0 - 1) */
+ IfNotBlocked
+ reached[3][9] = 1;
+ if (!delproc(1, II)) continue;
+ _m = 3; goto P999; /* 0 */
+
+ /* PROC reader */
+ case 24: /* STATE 1 - line 203 "pan.___" - [((((((write_off/(8/2))-(read_off/(8/2)))>0)&&(((write_off/(8/2))-(read_off/(8/2)))<(255/2)))&&(((commit_count[((read_off%8)/(8/2))]-(8/2))-(((read_off/8)*8)/2))==0)))] (0:0:0 - 1) */
+ IfNotBlocked
+ reached[2][1] = 1;
+ if (!((((((((int)now.write_off)/(8/2))-(((int)now.read_off)/(8/2)))>0)&&(((((int)now.write_off)/(8/2))-(((int)now.read_off)/(8/2)))<(255/2)))&&(((((int)now.commit_count[ Index(((((int)now.read_off)%8)/(8/2)), 2) ])-(8/2))-(((((int)now.read_off)/8)*8)/2))==0))))
+ continue;
+ _m = 3; goto P999; /* 0 */
+ case 25: /* STATE 2 - line 205 "pan.___" - [i = 0] (0:0:1 - 1) */
+ IfNotBlocked
+ reached[2][2] = 1;
+ (trpt+1)->bup.oval = ((int)((P2 *)this)->i);
+ ((P2 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval("reader:i", ((int)((P2 *)this)->i));
+#endif
+ ;
+ _m = 3; goto P999; /* 0 */
+ case 26: /* STATE 3 - line 207 "pan.___" - [((i<(8/2)))] (9:0:2 - 1) */
+ IfNotBlocked
+ reached[2][3] = 1;
+ if (!((((int)((P2 *)this)->i)<(8/2))))
+ continue;
+ /* merge: assert((buffer_use[((read_off+i)%8)]==0))(9, 4, 9) */
+ reached[2][4] = 1;
+ assert((((int)now.buffer_use[ Index(((((int)now.read_off)+((int)((P2 *)this)->i))%8), 8) ])==0), "(buffer_use[((read_off+i)%8)]==0)", II, tt, t);
+ /* merge: buffer_use[((read_off+i)%8)] = 1(9, 5, 9) */
+ reached[2][5] = 1;
+ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((int)now.buffer_use[ Index(((((int)now.read_off)+((int)((P2 *)this)->i))%8), 8) ]);
+ now.buffer_use[ Index(((now.read_off+((P2 *)this)->i)%8), 8) ] = 1;
+#ifdef VAR_RANGES
+ logval("buffer_use[((read_off+reader:i)%8)]", ((int)now.buffer_use[ Index(((((int)now.read_off)+((int)((P2 *)this)->i))%8), 8) ]));
+#endif
+ ;
+ /* merge: i = (i+1)(9, 6, 9) */
+ reached[2][6] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P2 *)this)->i);
+ ((P2 *)this)->i = (((int)((P2 *)this)->i)+1);
+#ifdef VAR_RANGES
+ logval("reader:i", ((int)((P2 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 10, 9) */
+ reached[2][10] = 1;
+ ;
+ _m = 3; goto P999; /* 4 */
+ case 27: /* STATE 7 - line 211 "pan.___" - [((i>=(8/2)))] (11:0:1 - 1) */
+ IfNotBlocked
+ reached[2][7] = 1;
+ if (!((((int)((P2 *)this)->i)>=(8/2))))
+ continue;
+ /* dead 1: i */ (trpt+1)->bup.oval = ((P2 *)this)->i;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P2 *)this)->i = 0;
+ /* merge: goto :b3(0, 8, 11) */
+ reached[2][8] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+/* STATE 13 - line 219 "pan.___" - [i = 0] (0:0 - 1) same as 25 (0:0 - 1) */
+ case 28: /* STATE 14 - line 221 "pan.___" - [((i<(8/2)))] (19:0:2 - 1) */
+ IfNotBlocked
+ reached[2][14] = 1;
+ if (!((((int)((P2 *)this)->i)<(8/2))))
+ continue;
+ /* merge: buffer_use[((read_off+i)%8)] = 0(19, 15, 19) */
+ reached[2][15] = 1;
+ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((int)now.buffer_use[ Index(((((int)now.read_off)+((int)((P2 *)this)->i))%8), 8) ]);
+ now.buffer_use[ Index(((now.read_off+((P2 *)this)->i)%8), 8) ] = 0;
+#ifdef VAR_RANGES
+ logval("buffer_use[((read_off+reader:i)%8)]", ((int)now.buffer_use[ Index(((((int)now.read_off)+((int)((P2 *)this)->i))%8), 8) ]));
+#endif
+ ;
+ /* merge: i = (i+1)(19, 16, 19) */
+ reached[2][16] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P2 *)this)->i);
+ ((P2 *)this)->i = (((int)((P2 *)this)->i)+1);
+#ifdef VAR_RANGES
+ logval("reader:i", ((int)((P2 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 20, 19) */
+ reached[2][20] = 1;
+ ;
+ _m = 3; goto P999; /* 3 */
+ case 29: /* STATE 17 - line 224 "pan.___" - [((i>=(8/2)))] (0:0:1 - 1) */
+ IfNotBlocked
+ reached[2][17] = 1;
+ if (!((((int)((P2 *)this)->i)>=(8/2))))
+ continue;
+ /* dead 1: i */ (trpt+1)->bup.oval = ((P2 *)this)->i;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P2 *)this)->i = 0;
+ _m = 3; goto P999; /* 0 */
+ case 30: /* STATE 22 - line 226 "pan.___" - [read_off = (read_off+(8/2))] (0:0:1 - 1) */
+ IfNotBlocked
+ reached[2][22] = 1;
+ (trpt+1)->bup.oval = ((int)now.read_off);
+ now.read_off = (((int)now.read_off)+(8/2));
+#ifdef VAR_RANGES
+ logval("read_off", ((int)now.read_off));
+#endif
+ ;
+ _m = 3; goto P999; /* 0 */
+ case 31: /* STATE 24 - line 228 "pan.___" - [((read_off>=(4-events_lost)))] (0:0:0 - 1) */
+ IfNotBlocked
+ reached[2][24] = 1;
+ if (!((((int)now.read_off)>=(4-((int)now.events_lost)))))
+ continue;
+ _m = 3; goto P999; /* 0 */
+ case 32: /* STATE 29 - line 230 "pan.___" - [-end-] (0:0:0 - 3) */
+ IfNotBlocked
+ reached[2][29] = 1;
+ if (!delproc(1, II)) continue;
+ _m = 3; goto P999; /* 0 */
+
+ /* PROC tracer */
+ case 33: /* STATE 1 - line 126 "pan.___" - [prev_off = write_off] (0:10:2 - 1) */
+ IfNotBlocked
+ reached[1][1] = 1;
+ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((int)((P1 *)this)->prev_off);
+ ((P1 *)this)->prev_off = ((int)now.write_off);
+#ifdef VAR_RANGES
+ logval("tracer:prev_off", ((int)((P1 *)this)->prev_off));
+#endif
+ ;
+ /* merge: new_off = (prev_off+size)(10, 2, 10) */
+ reached[1][2] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P1 *)this)->new_off);
+ ((P1 *)this)->new_off = (((int)((P1 *)this)->prev_off)+((int)((P1 *)this)->size));
+#ifdef VAR_RANGES
+ logval("tracer:new_off", ((int)((P1 *)this)->new_off));
+#endif
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 34: /* STATE 4 - line 131 "pan.___" - [((((new_off-read_off)>8)&&((new_off-read_off)<(255/2))))] (0:0:1 - 1) */
+ IfNotBlocked
+ reached[1][4] = 1;
+ if (!((((((int)((P1 *)this)->new_off)-((int)now.read_off))>8)&&((((int)((P1 *)this)->new_off)-((int)now.read_off))<(255/2)))))
+ continue;
+ /* dead 1: new_off */ (trpt+1)->bup.oval = ((P1 *)this)->new_off;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P1 *)this)->new_off = 0;
+ _m = 3; goto P999; /* 0 */
+ case 35: /* STATE 7 - line 133 "pan.___" - [(1)] (27:0:0 - 1) */
+ IfNotBlocked
+ reached[1][7] = 1;
+ if (!(1))
+ continue;
+ /* merge: .(goto)(0, 9, 27) */
+ reached[1][9] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 36: /* STATE 11 - line 138 "pan.___" - [((prev_off!=write_off))] (3:0:1 - 1) */
+ IfNotBlocked
+ reached[1][11] = 1;
+ if (!((((int)((P1 *)this)->prev_off)!=((int)now.write_off))))
+ continue;
+ /* dead 1: prev_off */ (trpt+1)->bup.oval = ((P1 *)this)->prev_off;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P1 *)this)->prev_off = 0;
+ /* merge: goto cmpxchg_loop(0, 12, 3) */
+ reached[1][12] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 37: /* STATE 14 - line 139 "pan.___" - [write_off = new_off] (0:24:2 - 1) */
+ IfNotBlocked
+ reached[1][14] = 1;
+ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((int)now.write_off);
+ now.write_off = ((int)((P1 *)this)->new_off);
+#ifdef VAR_RANGES
+ logval("write_off", ((int)now.write_off));
+#endif
+ ;
+ /* merge: .(goto)(24, 16, 24) */
+ reached[1][16] = 1;
+ ;
+ /* merge: i = 0(24, 17, 24) */
+ reached[1][17] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P1 *)this)->i);
+ ((P1 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval("tracer:i", ((int)((P1 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 25, 24) */
+ reached[1][25] = 1;
+ ;
+ _m = 3; goto P999; /* 3 */
+ case 38: /* STATE 17 - line 141 "pan.___" - [i = 0] (0:24:1 - 2) */
+ IfNotBlocked
+ reached[1][17] = 1;
+ (trpt+1)->bup.oval = ((int)((P1 *)this)->i);
+ ((P1 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval("tracer:i", ((int)((P1 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 25, 24) */
+ reached[1][25] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 39: /* STATE 18 - line 143 "pan.___" - [((i<size))] (24:0:2 - 1) */
+ IfNotBlocked
+ reached[1][18] = 1;
+ if (!((((int)((P1 *)this)->i)<((int)((P1 *)this)->size))))
+ continue;
+ /* merge: assert((buffer_use[((prev_off+i)%8)]==0))(24, 19, 24) */
+ reached[1][19] = 1;
+ assert((((int)now.buffer_use[ Index(((((int)((P1 *)this)->prev_off)+((int)((P1 *)this)->i))%8), 8) ])==0), "(buffer_use[((prev_off+i)%8)]==0)", II, tt, t);
+ /* merge: buffer_use[((prev_off+i)%8)] = 1(24, 20, 24) */
+ reached[1][20] = 1;
+ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((int)now.buffer_use[ Index(((((int)((P1 *)this)->prev_off)+((int)((P1 *)this)->i))%8), 8) ]);
+ now.buffer_use[ Index(((((P1 *)this)->prev_off+((P1 *)this)->i)%8), 8) ] = 1;
+#ifdef VAR_RANGES
+ logval("buffer_use[((tracer:prev_off+tracer:i)%8)]", ((int)now.buffer_use[ Index(((((int)((P1 *)this)->prev_off)+((int)((P1 *)this)->i))%8), 8) ]));
+#endif
+ ;
+ /* merge: i = (i+1)(24, 21, 24) */
+ reached[1][21] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P1 *)this)->i);
+ ((P1 *)this)->i = (((int)((P1 *)this)->i)+1);
+#ifdef VAR_RANGES
+ logval("tracer:i", ((int)((P1 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 25, 24) */
+ reached[1][25] = 1;
+ ;
+ _m = 3; goto P999; /* 4 */
+ case 40: /* STATE 22 - line 147 "pan.___" - [((i>=size))] (26:0:1 - 1) */
+ IfNotBlocked
+ reached[1][22] = 1;
+ if (!((((int)((P1 *)this)->i)>=((int)((P1 *)this)->size))))
+ continue;
+ /* dead 1: i */ (trpt+1)->bup.oval = ((P1 *)this)->i;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P1 *)this)->i = 0;
+ /* merge: goto :b0(0, 23, 26) */
+ reached[1][23] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 41: /* STATE 28 - line 155 "pan.___" - [i = 0] (0:0:1 - 1) */
+ IfNotBlocked
+ reached[1][28] = 1;
+ (trpt+1)->bup.oval = ((int)((P1 *)this)->i);
+ ((P1 *)this)->i = 0;
+#ifdef VAR_RANGES
+ logval("tracer:i", ((int)((P1 *)this)->i));
+#endif
+ ;
+ _m = 3; goto P999; /* 0 */
+ case 42: /* STATE 29 - line 157 "pan.___" - [((i<size))] (34:0:2 - 1) */
+ IfNotBlocked
+ reached[1][29] = 1;
+ if (!((((int)((P1 *)this)->i)<((int)((P1 *)this)->size))))
+ continue;
+ /* merge: buffer_use[((prev_off+i)%8)] = 0(34, 30, 34) */
+ reached[1][30] = 1;
+ (trpt+1)->bup.ovals = grab_ints(2);
+ (trpt+1)->bup.ovals[0] = ((int)now.buffer_use[ Index(((((int)((P1 *)this)->prev_off)+((int)((P1 *)this)->i))%8), 8) ]);
+ now.buffer_use[ Index(((((P1 *)this)->prev_off+((P1 *)this)->i)%8), 8) ] = 0;
+#ifdef VAR_RANGES
+ logval("buffer_use[((tracer:prev_off+tracer:i)%8)]", ((int)now.buffer_use[ Index(((((int)((P1 *)this)->prev_off)+((int)((P1 *)this)->i))%8), 8) ]));
+#endif
+ ;
+ /* merge: i = (i+1)(34, 31, 34) */
+ reached[1][31] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P1 *)this)->i);
+ ((P1 *)this)->i = (((int)((P1 *)this)->i)+1);
+#ifdef VAR_RANGES
+ logval("tracer:i", ((int)((P1 *)this)->i));
+#endif
+ ;
+ /* merge: .(goto)(0, 35, 34) */
+ reached[1][35] = 1;
+ ;
+ _m = 3; goto P999; /* 3 */
+ case 43: /* STATE 32 - line 160 "pan.___" - [((i>=size))] (44:0:4 - 1) */
+ IfNotBlocked
+ reached[1][32] = 1;
+ if (!((((int)((P1 *)this)->i)>=((int)((P1 *)this)->size))))
+ continue;
+ /* dead 1: i */ (trpt+1)->bup.ovals = grab_ints(4);
+ (trpt+1)->bup.ovals[0] = ((P1 *)this)->i;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P1 *)this)->i = 0;
+ /* merge: goto :b1(44, 33, 44) */
+ reached[1][33] = 1;
+ ;
+ /* merge: tmp_commit = (commit_count[((prev_off%8)/(8/2))]+size)(44, 37, 44) */
+ reached[1][37] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P1 *)this)->tmp_commit);
+ ((P1 *)this)->tmp_commit = (((int)now.commit_count[ Index(((((int)((P1 *)this)->prev_off)%8)/(8/2)), 2) ])+((int)((P1 *)this)->size));
+#ifdef VAR_RANGES
+ logval("tracer:tmp_commit", ((int)((P1 *)this)->tmp_commit));
+#endif
+ ;
+ /* merge: _commit_sum = ((_commit_sum-commit_count[((prev_off%8)/(8/2))])+tmp_commit)(44, 38, 44) */
+ reached[1][38] = 1;
+ (trpt+1)->bup.ovals[2] = ((int)now._commit_sum);
+ now._commit_sum = ((((int)now._commit_sum)-((int)now.commit_count[ Index(((((int)((P1 *)this)->prev_off)%8)/(8/2)), 2) ]))+((int)((P1 *)this)->tmp_commit));
+#ifdef VAR_RANGES
+ logval("_commit_sum", ((int)now._commit_sum));
+#endif
+ ;
+ /* merge: commit_count[((prev_off%8)/(8/2))] = tmp_commit(44, 39, 44) */
+ reached[1][39] = 1;
+ (trpt+1)->bup.ovals[3] = ((int)now.commit_count[ Index(((((int)((P1 *)this)->prev_off)%8)/(8/2)), 2) ]);
+ now.commit_count[ Index(((((P1 *)this)->prev_off%8)/(8/2)), 2) ] = ((int)((P1 *)this)->tmp_commit);
+#ifdef VAR_RANGES
+ logval("commit_count[((tracer:prev_off%8)/(8/2))]", ((int)now.commit_count[ Index(((((int)((P1 *)this)->prev_off)%8)/(8/2)), 2) ]));
+#endif
+ ;
+ _m = 3; goto P999; /* 4 */
+ case 44: /* STATE 37 - line 162 "pan.___" - [tmp_commit = (commit_count[((prev_off%8)/(8/2))]+size)] (0:44:3 - 3) */
+ IfNotBlocked
+ reached[1][37] = 1;
+ (trpt+1)->bup.ovals = grab_ints(3);
+ (trpt+1)->bup.ovals[0] = ((int)((P1 *)this)->tmp_commit);
+ ((P1 *)this)->tmp_commit = (((int)now.commit_count[ Index(((((int)((P1 *)this)->prev_off)%8)/(8/2)), 2) ])+((int)((P1 *)this)->size));
+#ifdef VAR_RANGES
+ logval("tracer:tmp_commit", ((int)((P1 *)this)->tmp_commit));
+#endif
+ ;
+ /* merge: _commit_sum = ((_commit_sum-commit_count[((prev_off%8)/(8/2))])+tmp_commit)(44, 38, 44) */
+ reached[1][38] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)now._commit_sum);
+ now._commit_sum = ((((int)now._commit_sum)-((int)now.commit_count[ Index(((((int)((P1 *)this)->prev_off)%8)/(8/2)), 2) ]))+((int)((P1 *)this)->tmp_commit));
+#ifdef VAR_RANGES
+ logval("_commit_sum", ((int)now._commit_sum));
+#endif
+ ;
+ /* merge: commit_count[((prev_off%8)/(8/2))] = tmp_commit(44, 39, 44) */
+ reached[1][39] = 1;
+ (trpt+1)->bup.ovals[2] = ((int)now.commit_count[ Index(((((int)((P1 *)this)->prev_off)%8)/(8/2)), 2) ]);
+ now.commit_count[ Index(((((P1 *)this)->prev_off%8)/(8/2)), 2) ] = ((int)((P1 *)this)->tmp_commit);
+#ifdef VAR_RANGES
+ logval("commit_count[((tracer:prev_off%8)/(8/2))]", ((int)now.commit_count[ Index(((((int)((P1 *)this)->prev_off)%8)/(8/2)), 2) ]));
+#endif
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 45: /* STATE 40 - line 170 "pan.___" - [((((((prev_off/8)*8)/2)+(8/2))-tmp_commit))] (50:0:3 - 1) */
+ IfNotBlocked
+ reached[1][40] = 1;
+ if (!((((((((int)((P1 *)this)->prev_off)/8)*8)/2)+(8/2))-((int)((P1 *)this)->tmp_commit))))
+ continue;
+ /* dead 1: prev_off */ (trpt+1)->bup.ovals = grab_ints(3);
+ (trpt+1)->bup.ovals[0] = ((P1 *)this)->prev_off;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P1 *)this)->prev_off = 0;
+ /* dead 1: tmp_commit */ (trpt+1)->bup.ovals[1] = ((P1 *)this)->tmp_commit;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P1 *)this)->tmp_commit = 0;
+ /* merge: deliver = 1(50, 41, 50) */
+ reached[1][41] = 1;
+ (trpt+1)->bup.ovals[2] = ((int)deliver);
+ deliver = 1;
+#ifdef VAR_RANGES
+ logval("deliver", ((int)deliver));
+#endif
+ ;
+ /* merge: .(goto)(50, 45, 50) */
+ reached[1][45] = 1;
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 46: /* STATE 45 - line 175 "pan.___" - [.(goto)] (0:50:0 - 2) */
+ IfNotBlocked
+ reached[1][45] = 1;
+ ;
+ _m = 3; goto P999; /* 0 */
+ case 47: /* STATE 43 - line 173 "pan.___" - [(1)] (50:0:0 - 1) */
+ IfNotBlocked
+ reached[1][43] = 1;
+ if (!(1))
+ continue;
+ /* merge: .(goto)(50, 45, 50) */
+ reached[1][45] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 48: /* STATE 48 - line 179 "pan.___" - [events_lost = (events_lost+1)] (0:0:1 - 2) */
+ IfNotBlocked
+ reached[1][48] = 1;
+ (trpt+1)->bup.oval = ((int)now.events_lost);
+ now.events_lost = (((int)now.events_lost)+1);
+#ifdef VAR_RANGES
+ logval("events_lost", ((int)now.events_lost));
+#endif
+ ;
+ _m = 3; goto P999; /* 0 */
+ case 49: /* STATE 49 - line 181 "pan.___" - [refcount = (refcount-1)] (0:0:1 - 2) */
+ IfNotBlocked
+ reached[1][49] = 1;
+ (trpt+1)->bup.oval = ((int)now.refcount);
+ now.refcount = (((int)now.refcount)-1);
+#ifdef VAR_RANGES
+ logval("refcount", ((int)now.refcount));
+#endif
+ ;
+ _m = 3; goto P999; /* 0 */
+ case 50: /* STATE 51 - line 183 "pan.___" - [-end-] (0:0:0 - 1) */
+ IfNotBlocked
+ reached[1][51] = 1;
+ if (!delproc(1, II)) continue;
+ _m = 3; goto P999; /* 0 */
+
+ /* PROC switcher */
+ case 51: /* STATE 1 - line 75 "pan.___" - [prev_off = write_off] (0:9:3 - 1) */
+ IfNotBlocked
+ reached[0][1] = 1;
+ (trpt+1)->bup.ovals = grab_ints(3);
+ (trpt+1)->bup.ovals[0] = ((int)((P0 *)this)->prev_off);
+ ((P0 *)this)->prev_off = ((int)now.write_off);
+#ifdef VAR_RANGES
+ logval("switcher:prev_off", ((int)((P0 *)this)->prev_off));
+#endif
+ ;
+ /* merge: size = ((8/2)-(prev_off%(8/2)))(9, 2, 9) */
+ reached[0][2] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)((P0 *)this)->size);
+ ((P0 *)this)->size = ((8/2)-(((int)((P0 *)this)->prev_off)%(8/2)));
+#ifdef VAR_RANGES
+ logval("switcher:size", ((int)((P0 *)this)->size));
+#endif
+ ;
+ /* merge: new_off = (prev_off+size)(9, 3, 9) */
+ reached[0][3] = 1;
+ (trpt+1)->bup.ovals[2] = ((int)((P0 *)this)->new_off);
+ ((P0 *)this)->new_off = (((int)((P0 *)this)->prev_off)+((int)((P0 *)this)->size));
+#ifdef VAR_RANGES
+ logval("switcher:new_off", ((int)((P0 *)this)->new_off));
+#endif
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 52: /* STATE 4 - line 80 "pan.___" - [(((((new_off-read_off)>8)&&((new_off-read_off)<(255/2)))||(size==(8/2))))] (30:0:3 - 1) */
+ IfNotBlocked
+ reached[0][4] = 1;
+ if (!(((((((int)((P0 *)this)->new_off)-((int)now.read_off))>8)&&((((int)((P0 *)this)->new_off)-((int)now.read_off))<(255/2)))||(((int)((P0 *)this)->size)==(8/2)))))
+ continue;
+ /* dead 1: new_off */ (trpt+1)->bup.ovals = grab_ints(3);
+ (trpt+1)->bup.ovals[0] = ((P0 *)this)->new_off;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P0 *)this)->new_off = 0;
+ /* dead 1: size */ (trpt+1)->bup.ovals[1] = ((P0 *)this)->size;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P0 *)this)->size = 0;
+ /* merge: refcount = (refcount-1)(30, 5, 30) */
+ reached[0][5] = 1;
+ (trpt+1)->bup.ovals[2] = ((int)now.refcount);
+ now.refcount = (((int)now.refcount)-1);
+#ifdef VAR_RANGES
+ logval("refcount", ((int)now.refcount));
+#endif
+ ;
+ /* merge: goto not_needed(30, 6, 30) */
+ reached[0][6] = 1;
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 53: /* STATE 8 - line 83 "pan.___" - [(1)] (18:0:0 - 1) */
+ IfNotBlocked
+ reached[0][8] = 1;
+ if (!(1))
+ continue;
+ /* merge: .(goto)(0, 10, 18) */
+ reached[0][10] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 54: /* STATE 12 - line 88 "pan.___" - [((prev_off!=write_off))] (11:0:1 - 1) */
+ IfNotBlocked
+ reached[0][12] = 1;
+ if (!((((int)((P0 *)this)->prev_off)!=((int)now.write_off))))
+ continue;
+ /* dead 1: prev_off */ (trpt+1)->bup.oval = ((P0 *)this)->prev_off;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P0 *)this)->prev_off = 0;
+ /* merge: goto cmpxchg_loop(0, 13, 11) */
+ reached[0][13] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 55: /* STATE 17 - line 91 "pan.___" - [.(goto)] (0:29:0 - 1) */
+ IfNotBlocked
+ reached[0][17] = 1;
+ ;
+ _m = 3; goto P999; /* 0 */
+ case 56: /* STATE 15 - line 89 "pan.___" - [write_off = new_off] (0:29:1 - 1) */
+ IfNotBlocked
+ reached[0][15] = 1;
+ (trpt+1)->bup.oval = ((int)now.write_off);
+ now.write_off = ((int)((P0 *)this)->new_off);
+#ifdef VAR_RANGES
+ logval("write_off", ((int)now.write_off));
+#endif
+ ;
+ /* merge: .(goto)(29, 17, 29) */
+ reached[0][17] = 1;
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 57: /* STATE 19 - line 94 "pan.___" - [tmp_commit = (commit_count[((prev_off%8)/(8/2))]+size)] (0:26:3 - 1) */
+ IfNotBlocked
+ reached[0][19] = 1;
+ (trpt+1)->bup.ovals = grab_ints(3);
+ (trpt+1)->bup.ovals[0] = ((int)((P0 *)this)->tmp_commit);
+ ((P0 *)this)->tmp_commit = (((int)now.commit_count[ Index(((((int)((P0 *)this)->prev_off)%8)/(8/2)), 2) ])+((int)((P0 *)this)->size));
+#ifdef VAR_RANGES
+ logval("switcher:tmp_commit", ((int)((P0 *)this)->tmp_commit));
+#endif
+ ;
+ /* merge: _commit_sum = ((_commit_sum-commit_count[((prev_off%8)/(8/2))])+tmp_commit)(26, 20, 26) */
+ reached[0][20] = 1;
+ (trpt+1)->bup.ovals[1] = ((int)now._commit_sum);
+ now._commit_sum = ((((int)now._commit_sum)-((int)now.commit_count[ Index(((((int)((P0 *)this)->prev_off)%8)/(8/2)), 2) ]))+((int)((P0 *)this)->tmp_commit));
+#ifdef VAR_RANGES
+ logval("_commit_sum", ((int)now._commit_sum));
+#endif
+ ;
+ /* merge: commit_count[((prev_off%8)/(8/2))] = tmp_commit(26, 21, 26) */
+ reached[0][21] = 1;
+ (trpt+1)->bup.ovals[2] = ((int)now.commit_count[ Index(((((int)((P0 *)this)->prev_off)%8)/(8/2)), 2) ]);
+ now.commit_count[ Index(((((P0 *)this)->prev_off%8)/(8/2)), 2) ] = ((int)((P0 *)this)->tmp_commit);
+#ifdef VAR_RANGES
+ logval("commit_count[((switcher:prev_off%8)/(8/2))]", ((int)now.commit_count[ Index(((((int)((P0 *)this)->prev_off)%8)/(8/2)), 2) ]));
+#endif
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 58: /* STATE 22 - line 102 "pan.___" - [((((((prev_off/8)*8)/2)+(8/2))-tmp_commit))] (30:0:4 - 1) */
+ IfNotBlocked
+ reached[0][22] = 1;
+ if (!((((((((int)((P0 *)this)->prev_off)/8)*8)/2)+(8/2))-((int)((P0 *)this)->tmp_commit))))
+ continue;
+ /* dead 1: prev_off */ (trpt+1)->bup.ovals = grab_ints(4);
+ (trpt+1)->bup.ovals[0] = ((P0 *)this)->prev_off;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P0 *)this)->prev_off = 0;
+ /* dead 1: tmp_commit */ (trpt+1)->bup.ovals[1] = ((P0 *)this)->tmp_commit;
+#ifdef HAS_CODE
+ if (!readtrail)
+#endif
+ ((P0 *)this)->tmp_commit = 0;
+ /* merge: deliver = 1(30, 23, 30) */
+ reached[0][23] = 1;
+ (trpt+1)->bup.ovals[2] = ((int)deliver);
+ deliver = 1;
+#ifdef VAR_RANGES
+ logval("deliver", ((int)deliver));
+#endif
+ ;
+ /* merge: .(goto)(30, 27, 30) */
+ reached[0][27] = 1;
+ ;
+ /* merge: refcount = (refcount-1)(30, 28, 30) */
+ reached[0][28] = 1;
+ (trpt+1)->bup.ovals[3] = ((int)now.refcount);
+ now.refcount = (((int)now.refcount)-1);
+#ifdef VAR_RANGES
+ logval("refcount", ((int)now.refcount));
+#endif
+ ;
+ _m = 3; goto P999; /* 3 */
+ case 59: /* STATE 27 - line 107 "pan.___" - [.(goto)] (0:30:1 - 2) */
+ IfNotBlocked
+ reached[0][27] = 1;
+ ;
+ /* merge: refcount = (refcount-1)(30, 28, 30) */
+ reached[0][28] = 1;
+ (trpt+1)->bup.oval = ((int)now.refcount);
+ now.refcount = (((int)now.refcount)-1);
+#ifdef VAR_RANGES
+ logval("refcount", ((int)now.refcount));
+#endif
+ ;
+ _m = 3; goto P999; /* 1 */
+ case 60: /* STATE 25 - line 105 "pan.___" - [(1)] (30:0:1 - 1) */
+ IfNotBlocked
+ reached[0][25] = 1;
+ if (!(1))
+ continue;
+ /* merge: .(goto)(30, 27, 30) */
+ reached[0][27] = 1;
+ ;
+ /* merge: refcount = (refcount-1)(30, 28, 30) */
+ reached[0][28] = 1;
+ (trpt+1)->bup.oval = ((int)now.refcount);
+ now.refcount = (((int)now.refcount)-1);
+#ifdef VAR_RANGES
+ logval("refcount", ((int)now.refcount));
+#endif
+ ;
+ _m = 3; goto P999; /* 2 */
+ case 61: /* STATE 31 - line 111 "pan.___" - [-end-] (0:0:0 - 1) */
+ IfNotBlocked
+ reached[0][31] = 1;
+ if (!delproc(1, II)) continue;
+ _m = 3; goto P999; /* 0 */
+ case _T5: /* np_ */
+ if (!((!(trpt->o_pm&4) && !(trpt->tau&128))))
+ continue;
+ /* else fall through */
+ case _T2: /* true */
+ _m = 3; goto P999;
+#undef rand
+ }
+
--- /dev/null
+#define BUFSIZE 8
+/* LTTng ltt-tracer.c atomic lockless buffering scheme Promela model v2
+ * Created for the Spin validator.
+ * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ * October 2008
+
+ * TODO : create test cases that will generate an overflow on the offset and
+ * counter type. Counter types smaller than a byte should be used.
+
+ * Promela only has unsigned char, no signed char.
+ * Because detection of difference < 0 depends on a signed type, but we want
+ * compactness, check also for the values being higher than half of the unsigned
+ * char range (and consider them negative). The model, by design, does not use
+ * offsets or counts higher than 127 because we would then have to use a larger
+ * type (short or int).
+ */
+#define HALF_UCHAR (255/2)
+
+/* NUMPROCS 4 : causes event loss with some reader timings.
+ * e.g. 3 events, 1 switch, 1 event (lost, buffer full), read 1 subbuffer
+ */
+#define NUMPROCS 4
+
+/* NUMPROCS 3 : does not cause event loss because buffers are big enough.
+ * #define NUMPROCS 3
+ * e.g. 3 events, 1 switch, read 1 subbuffer
+ */
+
+#define NUMSWITCH 1
+#ifndef BUFSIZE
+#define BUFSIZE 4
+#endif
+#define NR_SUBBUFS 2
+#define SUBBUF_SIZE (BUFSIZE / NR_SUBBUFS)
+
+/* Writer counters
+*/
+byte write_off = 0;
+byte commit_count[NR_SUBBUFS];
+
+/* <formal_verif> */
+byte _commit_sum;
+/* </formal_verif> */
+
+/* Reader counters
+*/
+byte read_off = 0;
+
+byte events_lost = 0;
+byte refcount = 0;
+
+bool deliver = 0;
+
+//#ifdef RACE_TEST
+/* buffer slot in-use bit. Detects racy use (more than a single process
+ * accessing a slot at any given step).
+ */
+bool buffer_use[BUFSIZE];
+//#endif
+
+/* Proceed to a sub-subber switch is needed.
+ * Used in a periodical timer interrupt to fill and ship the current subbuffer
+ * to the reader so we can guarantee a steady flow. If a subbuffer is
+ * completely empty, do not switch.
+ * Also used as "finalize" operation to complete the last subbuffer after
+ * all writers have finished so the last subbuffer can be read by the reader.
+ */
+proctype switcher()
+{
+ byte prev_off, new_off, tmp_commit;
+ byte size;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ size = SUBBUF_SIZE - (prev_off % SUBBUF_SIZE);
+ new_off = prev_off + size;
+ if
+ :: (new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR)
+ || size == SUBBUF_SIZE ->
+ refcount = refcount - 1;
+ goto not_needed;
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ }
+
+ atomic {
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ /* <formal_verif> */
+ _commit_sum = _commit_sum - commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE]
+ + tmp_commit;
+ /* </formal_verif> */
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ refcount = refcount - 1;
+ }
+not_needed:
+ skip;
+}
+
+/* tracer
+ * Writes 1 byte of information in the buffer at the current
+ * "write_off" position and then increment the commit_count of the sub-buffer
+ * the information has been written to.
+ */
+proctype tracer()
+{
+ byte size = 1;
+ byte prev_off, new_off, tmp_commit;
+ byte i, j;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ new_off = prev_off + size;
+ }
+ atomic {
+ if
+ :: new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR ->
+ goto lost
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ i = 0;
+ do
+ :: i < size ->
+ assert(buffer_use[(prev_off + i) % BUFSIZE] == 0);
+ buffer_use[(prev_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= size -> break
+ od;
+ }
+
+ /* writing to buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < size ->
+ buffer_use[(prev_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= size -> break
+ od;
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ /* <formal_verif> */
+ _commit_sum = _commit_sum - commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE]
+ + tmp_commit;
+ /* </formal_verif> */
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ }
+ atomic {
+ goto end;
+lost:
+ events_lost++;
+end:
+ refcount = refcount - 1;
+ }
+}
+
+/* reader
+ * Read the information sub-buffer per sub-buffer when available.
+ *
+ * Reads the information as soon as it is ready, or may be delayed by
+ * an asynchronous delivery. Being modeled as a process insures all cases
+ * (scheduled very quickly or very late, causing event loss) are covered.
+ * Only one reader per buffer (normally ensured by a mutex). This is modeled
+ * by using a single reader process.
+ */
+proctype reader()
+{
+ byte i, j;
+
+ do
+ :: (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) > 0
+ && (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) < HALF_UCHAR
+ && (commit_count[(read_off % BUFSIZE) / SUBBUF_SIZE]
+ - SUBBUF_SIZE - (((read_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS)
+ == 0) ->
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ assert(buffer_use[(read_off + i) % BUFSIZE] == 0);
+ buffer_use[(read_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ }
+
+ /* reading from buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ buffer_use[(read_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ read_off = read_off + SUBBUF_SIZE;
+ }
+ :: read_off >= (NUMPROCS - events_lost) -> break;
+ od;
+}
+
+/* Waits for all tracer and switcher processes to finish before finalizing
+ * the buffer. Only after that will the reader be allowed to read the
+ * last subbuffer.
+ */
+proctype cleaner()
+{
+ atomic {
+ do
+ :: refcount == 0 ->
+ refcount = refcount + 1;
+ run switcher(); /* Finalize the last sub-buffer so it can be read. */
+ break;
+ od;
+ }
+}
+
+init {
+ byte i = 0;
+ byte j = 0;
+ byte sum = 0;
+ byte commit_sum = 0;
+
+ atomic {
+ i = 0;
+ do
+ :: i < NR_SUBBUFS ->
+ commit_count[i] = 0;
+ i++
+ :: i >= NR_SUBBUFS -> break
+ od;
+ /* <formal_verif> */
+ _commit_sum = 0;
+ /* </formal_verif> */
+ i = 0;
+ do
+ :: i < BUFSIZE ->
+ buffer_use[i] = 0;
+ i++
+ :: i >= BUFSIZE -> break
+ od;
+ run reader();
+ run cleaner();
+ i = 0;
+ do
+ :: i < NUMPROCS ->
+ refcount = refcount + 1;
+ run tracer();
+ i++
+ :: i >= NUMPROCS -> break
+ od;
+ i = 0;
+ do
+ :: i < NUMSWITCH ->
+ refcount = refcount + 1;
+ run switcher();
+ i++
+ :: i >= NUMSWITCH -> break
+ od;
+ }
+}
+
--- /dev/null
+#ifdef PEG
+struct T_SRC {
+ char *fl; int ln;
+} T_SRC[NTRANS];
+
+void
+tr_2_src(int m, char *file, int ln)
+{ T_SRC[m].fl = file;
+ T_SRC[m].ln = ln;
+}
+
+void
+putpeg(int n, int m)
+{ printf("%5d trans %4d ", m, n);
+ printf("file %s line %3d\n",
+ T_SRC[n].fl, T_SRC[n].ln);
+}
+#endif
+
+void
+settable(void)
+{ Trans *T;
+ Trans *settr(int, int, int, int, int, char *, int, int, int);
+
+ trans = (Trans ***) emalloc(7*sizeof(Trans **));
+
+ /* proctype 5: :never: */
+
+ trans[5] = (Trans **) emalloc(9*sizeof(Trans *));
+
+ T = trans[5][5] = settr(167,0,0,0,0,"IF", 0, 2, 0);
+ T = T->nxt = settr(167,0,1,0,0,"IF", 0, 2, 0);
+ T->nxt = settr(167,0,3,0,0,"IF", 0, 2, 0);
+ trans[5][1] = settr(163,0,7,3,0,"((((4+1)<=8)&&(events_lost!=0)))", 1, 2, 0);
+ trans[5][2] = settr(164,0,7,1,0,"goto accept_all", 0, 2, 0);
+ trans[5][6] = settr(168,0,7,1,0,".(goto)", 0, 2, 0);
+ trans[5][3] = settr(165,0,5,1,0,"(1)", 0, 2, 0);
+ trans[5][4] = settr(166,0,5,1,0,"goto T0_init", 0, 2, 0);
+ trans[5][7] = settr(169,0,8,1,0,"(1)", 0, 2, 0);
+ trans[5][8] = settr(170,0,0,4,4,"-end-", 0, 3500, 0);
+
+ /* proctype 4: :init: */
+
+ trans[4] = (Trans **) emalloc(44*sizeof(Trans *));
+
+ T = trans[ 4][42] = settr(161,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(161,2,1,0,0,"ATOMIC", 1, 2, 0);
+ trans[4][1] = settr(120,2,7,5,5,"i = 0", 1, 2, 0);
+ trans[4][8] = settr(127,2,7,1,0,".(goto)", 1, 2, 0);
+ T = trans[4][7] = settr(126,2,0,0,0,"DO", 1, 2, 0);
+ T = T->nxt = settr(126,2,2,0,0,"DO", 1, 2, 0);
+ T->nxt = settr(126,2,5,0,0,"DO", 1, 2, 0);
+ trans[4][2] = settr(121,2,7,6,6,"((i<2))", 1, 2, 0); /* m: 3 -> 7,0 */
+ reached4[3] = 1;
+ trans[4][3] = settr(0,0,0,0,0,"commit_count[i] = 0",0,0,0);
+ trans[4][4] = settr(0,0,0,0,0,"i = (i+1)",0,0,0);
+ trans[4][5] = settr(124,2,17,7,7,"((i>=2))", 1, 2, 0); /* m: 10 -> 17,0 */
+ reached4[10] = 1;
+ trans[4][6] = settr(125,2,10,1,0,"goto :b6", 1, 2, 0); /* m: 10 -> 0,17 */
+ reached4[10] = 1;
+ trans[4][9] = settr(128,2,10,1,0,"break", 1, 2, 0);
+ trans[4][10] = settr(129,2,17,8,8,"_commit_sum = 0", 1, 2, 0); /* m: 11 -> 0,17 */
+ reached4[11] = 1;
+ trans[4][11] = settr(0,0,0,0,0,"i = 0",0,0,0);
+ trans[4][18] = settr(137,2,17,1,0,".(goto)", 1, 2, 0);
+ T = trans[4][17] = settr(136,2,0,0,0,"DO", 1, 2, 0);
+ T = T->nxt = settr(136,2,12,0,0,"DO", 1, 2, 0);
+ T->nxt = settr(136,2,15,0,0,"DO", 1, 2, 0);
+ trans[4][12] = settr(131,2,17,9,9,"((i<8))", 1, 2, 0); /* m: 13 -> 17,0 */
+ reached4[13] = 1;
+ trans[4][13] = settr(0,0,0,0,0,"buffer_use[i] = 0",0,0,0);
+ trans[4][14] = settr(0,0,0,0,0,"i = (i+1)",0,0,0);
+ trans[4][15] = settr(134,2,20,10,10,"((i>=8))", 1, 2, 0);
+ trans[4][16] = settr(135,2,20,1,0,"goto :b7", 1, 2, 0);
+ trans[4][19] = settr(138,2,20,1,0,"break", 1, 2, 0);
+ trans[4][20] = settr(139,2,21,11,11,"(run reader())", 1, 2, 0);
+ trans[4][21] = settr(140,2,29,12,12,"(run cleaner())", 1, 2, 0); /* m: 22 -> 29,0 */
+ reached4[22] = 1;
+ trans[4][22] = settr(0,0,0,0,0,"i = 0",0,0,0);
+ trans[4][30] = settr(149,2,29,1,0,".(goto)", 1, 2, 0);
+ T = trans[4][29] = settr(148,2,0,0,0,"DO", 1, 2, 0);
+ T = T->nxt = settr(148,2,23,0,0,"DO", 1, 2, 0);
+ T->nxt = settr(148,2,27,0,0,"DO", 1, 2, 0);
+ trans[4][23] = settr(142,2,25,13,13,"((i<4))", 1, 2, 0); /* m: 24 -> 25,0 */
+ reached4[24] = 1;
+ trans[4][24] = settr(0,0,0,0,0,"refcount = (refcount+1)",0,0,0);
+ trans[4][25] = settr(144,2,29,14,14,"(run tracer())", 1, 2, 0); /* m: 26 -> 29,0 */
+ reached4[26] = 1;
+ trans[4][26] = settr(0,0,0,0,0,"i = (i+1)",0,0,0);
+ trans[4][27] = settr(146,2,39,15,15,"((i>=4))", 1, 2, 0); /* m: 32 -> 39,0 */
+ reached4[32] = 1;
+ trans[4][28] = settr(147,2,32,1,0,"goto :b8", 1, 2, 0); /* m: 32 -> 0,39 */
+ reached4[32] = 1;
+ trans[4][31] = settr(150,2,32,1,0,"break", 1, 2, 0);
+ trans[4][32] = settr(151,2,39,16,16,"i = 0", 1, 2, 0);
+ trans[4][40] = settr(159,2,39,1,0,".(goto)", 1, 2, 0);
+ T = trans[4][39] = settr(158,2,0,0,0,"DO", 1, 2, 0);
+ T = T->nxt = settr(158,2,33,0,0,"DO", 1, 2, 0);
+ T->nxt = settr(158,2,37,0,0,"DO", 1, 2, 0);
+ trans[4][33] = settr(152,2,35,17,17,"((i<1))", 1, 2, 0); /* m: 34 -> 35,0 */
+ reached4[34] = 1;
+ trans[4][34] = settr(0,0,0,0,0,"refcount = (refcount+1)",0,0,0);
+ trans[4][35] = settr(154,2,39,18,18,"(run switcher())", 1, 2, 0); /* m: 36 -> 39,0 */
+ reached4[36] = 1;
+ trans[4][36] = settr(0,0,0,0,0,"i = (i+1)",0,0,0);
+ trans[4][37] = settr(156,2,41,19,19,"((i>=1))", 1, 2, 0); /* m: 38 -> 41,0 */
+ reached4[38] = 1;
+ trans[4][38] = settr(157,2,41,1,0,"goto :b9", 1, 2, 0);
+ trans[4][41] = settr(160,0,43,1,0,"break", 1, 2, 0);
+ trans[4][43] = settr(162,0,0,20,20,"-end-", 0, 3500, 0);
+
+ /* proctype 3: cleaner */
+
+ trans[3] = (Trans **) emalloc(10*sizeof(Trans *));
+
+ T = trans[ 3][8] = settr(118,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(118,2,5,0,0,"ATOMIC", 1, 2, 0);
+ trans[3][6] = settr(116,2,5,1,0,".(goto)", 1, 2, 0);
+ T = trans[3][5] = settr(115,2,0,0,0,"DO", 1, 2, 0);
+ T->nxt = settr(115,2,1,0,0,"DO", 1, 2, 0);
+ trans[3][1] = settr(111,2,3,21,21,"((refcount==0))", 1, 2, 0); /* m: 2 -> 3,0 */
+ reached3[2] = 1;
+ trans[3][2] = settr(0,0,0,0,0,"refcount = (refcount+1)",0,0,0);
+ trans[3][3] = settr(113,2,7,22,22,"(run switcher())", 1, 2, 0); /* m: 4 -> 7,0 */
+ reached3[4] = 1;
+ trans[3][4] = settr(114,2,7,1,0,"goto :b5", 1, 2, 0);
+ trans[3][7] = settr(117,0,9,1,0,"break", 1, 2, 0);
+ trans[3][9] = settr(119,0,0,23,23,"-end-", 0, 3500, 0);
+
+ /* proctype 2: reader */
+
+ trans[2] = (Trans **) emalloc(30*sizeof(Trans *));
+
+ trans[2][27] = settr(108,0,26,1,0,".(goto)", 0, 2, 0);
+ T = trans[2][26] = settr(107,0,0,0,0,"DO", 0, 2, 0);
+ T = T->nxt = settr(107,0,1,0,0,"DO", 0, 2, 0);
+ T->nxt = settr(107,0,24,0,0,"DO", 0, 2, 0);
+ trans[2][1] = settr(82,0,12,24,0,"((((((write_off/(8/2))-(read_off/(8/2)))>0)&&(((write_off/(8/2))-(read_off/(8/2)))<(255/2)))&&(((commit_count[((read_off%8)/(8/2))]-(8/2))-(((read_off/8)*8)/2))==0)))", 1, 2, 0);
+ T = trans[ 2][12] = settr(93,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(93,2,2,0,0,"ATOMIC", 1, 2, 0);
+ trans[2][2] = settr(83,2,9,25,25,"i = 0", 1, 2, 0);
+ trans[2][10] = settr(91,2,9,1,0,".(goto)", 1, 2, 0);
+ T = trans[2][9] = settr(90,2,0,0,0,"DO", 1, 2, 0);
+ T = T->nxt = settr(90,2,3,0,0,"DO", 1, 2, 0);
+ T->nxt = settr(90,2,7,0,0,"DO", 1, 2, 0);
+ trans[2][3] = settr(84,2,9,26,26,"((i<(8/2)))", 1, 2, 0); /* m: 4 -> 9,0 */
+ reached2[4] = 1;
+ trans[2][4] = settr(0,0,0,0,0,"assert((buffer_use[((read_off+i)%8)]==0))",0,0,0);
+ trans[2][5] = settr(0,0,0,0,0,"buffer_use[((read_off+i)%8)] = 1",0,0,0);
+ trans[2][6] = settr(0,0,0,0,0,"i = (i+1)",0,0,0);
+ trans[2][7] = settr(88,2,11,27,27,"((i>=(8/2)))", 1, 2, 0); /* m: 8 -> 11,0 */
+ reached2[8] = 1;
+ trans[2][8] = settr(89,2,11,1,0,"goto :b3", 1, 2, 0);
+ trans[2][11] = settr(92,0,23,1,0,"break", 1, 2, 0);
+ T = trans[ 2][23] = settr(104,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(104,2,13,0,0,"ATOMIC", 1, 2, 0);
+ trans[2][13] = /* c */ settr(94,2,19,25,25,"i = 0", 1, 2, 0);
+ trans[2][20] = settr(101,2,19,1,0,".(goto)", 1, 2, 0);
+ T = trans[2][19] = settr(100,2,0,0,0,"DO", 1, 2, 0);
+ T = T->nxt = settr(100,2,14,0,0,"DO", 1, 2, 0);
+ T->nxt = settr(100,2,17,0,0,"DO", 1, 2, 0);
+ trans[2][14] = settr(95,2,19,28,28,"((i<(8/2)))", 1, 2, 0); /* m: 15 -> 19,0 */
+ reached2[15] = 1;
+ trans[2][15] = settr(0,0,0,0,0,"buffer_use[((read_off+i)%8)] = 0",0,0,0);
+ trans[2][16] = settr(0,0,0,0,0,"i = (i+1)",0,0,0);
+ trans[2][17] = settr(98,2,21,29,29,"((i>=(8/2)))", 1, 2, 0);
+ trans[2][18] = settr(99,2,21,1,0,"goto :b4", 1, 2, 0);
+ trans[2][21] = settr(102,2,22,1,0,"break", 1, 2, 0);
+ trans[2][22] = settr(103,0,26,30,30,"read_off = (read_off+(8/2))", 1, 2, 0);
+ trans[2][24] = settr(105,0,29,31,0,"((read_off>=(4-events_lost)))", 1, 2, 0);
+ trans[2][25] = settr(106,0,29,1,0,"goto :b2", 0, 2, 0);
+ trans[2][28] = settr(109,0,29,1,0,"break", 0, 2, 0);
+ trans[2][29] = settr(110,0,0,32,32,"-end-", 0, 3500, 0);
+
+ /* proctype 1: tracer */
+
+ trans[1] = (Trans **) emalloc(52*sizeof(Trans *));
+
+ T = trans[ 1][3] = settr(33,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(33,2,1,0,0,"ATOMIC", 1, 2, 0);
+ trans[1][1] = settr(31,4,10,33,33,"prev_off = write_off", 1, 2, 0); /* m: 2 -> 0,10 */
+ reached1[2] = 1;
+ trans[1][2] = settr(0,0,0,0,0,"new_off = (prev_off+size)",0,0,0);
+ T = trans[ 1][10] = settr(40,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(40,2,8,0,0,"ATOMIC", 1, 2, 0);
+ T = trans[1][8] = settr(38,2,0,0,0,"IF", 1, 2, 0);
+ T = T->nxt = settr(38,2,4,0,0,"IF", 1, 2, 0);
+ T->nxt = settr(38,2,6,0,0,"IF", 1, 2, 0);
+ trans[1][4] = settr(34,2,48,34,34,"((((new_off-read_off)>8)&&((new_off-read_off)<(255/2))))", 1, 2, 0);
+ trans[1][5] = settr(35,2,48,1,0,"goto lost", 1, 2, 0);
+ trans[1][9] = settr(39,0,27,1,0,".(goto)", 1, 2, 0);
+ trans[1][6] = settr(36,2,7,2,0,"else", 1, 2, 0);
+ trans[1][7] = settr(37,4,27,35,35,"(1)", 1, 2, 0); /* m: 9 -> 27,0 */
+ reached1[9] = 1;
+ T = trans[ 1][27] = settr(57,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(57,2,15,0,0,"ATOMIC", 1, 2, 0);
+ T = trans[1][15] = settr(45,2,0,0,0,"IF", 1, 2, 0);
+ T = T->nxt = settr(45,2,11,0,0,"IF", 1, 2, 0);
+ T->nxt = settr(45,2,13,0,0,"IF", 1, 2, 0);
+ trans[1][11] = settr(41,4,3,36,36,"((prev_off!=write_off))", 1, 2, 0); /* m: 12 -> 3,0 */
+ reached1[12] = 1;
+ trans[1][12] = settr(42,0,3,1,0,"goto cmpxchg_loop", 1, 2, 0);
+ trans[1][16] = settr(46,2,17,1,0,".(goto)", 1, 2, 0); /* m: 17 -> 0,24 */
+ reached1[17] = 1;
+ trans[1][13] = settr(43,2,14,2,0,"else", 1, 2, 0);
+ trans[1][14] = settr(44,2,24,37,37,"write_off = new_off", 1, 2, 0); /* m: 17 -> 0,24 */
+ reached1[17] = 1;
+ trans[1][17] = settr(47,2,24,38,38,"i = 0", 1, 2, 0);
+ trans[1][25] = settr(55,2,24,1,0,".(goto)", 1, 2, 0);
+ T = trans[1][24] = settr(54,2,0,0,0,"DO", 1, 2, 0);
+ T = T->nxt = settr(54,2,18,0,0,"DO", 1, 2, 0);
+ T->nxt = settr(54,2,22,0,0,"DO", 1, 2, 0);
+ trans[1][18] = settr(48,2,24,39,39,"((i<size))", 1, 2, 0); /* m: 19 -> 24,0 */
+ reached1[19] = 1;
+ trans[1][19] = settr(0,0,0,0,0,"assert((buffer_use[((prev_off+i)%8)]==0))",0,0,0);
+ trans[1][20] = settr(0,0,0,0,0,"buffer_use[((prev_off+i)%8)] = 1",0,0,0);
+ trans[1][21] = settr(0,0,0,0,0,"i = (i+1)",0,0,0);
+ trans[1][22] = settr(52,2,26,40,40,"((i>=size))", 1, 2, 0); /* m: 23 -> 26,0 */
+ reached1[23] = 1;
+ trans[1][23] = settr(53,2,26,1,0,"goto :b0", 1, 2, 0);
+ trans[1][26] = settr(56,0,46,1,0,"break", 1, 2, 0);
+ T = trans[ 1][46] = settr(76,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(76,2,28,0,0,"ATOMIC", 1, 2, 0);
+ trans[1][28] = settr(58,2,34,41,41,"i = 0", 1, 2, 0);
+ trans[1][35] = settr(65,2,34,1,0,".(goto)", 1, 2, 0);
+ T = trans[1][34] = settr(64,2,0,0,0,"DO", 1, 2, 0);
+ T = T->nxt = settr(64,2,29,0,0,"DO", 1, 2, 0);
+ T->nxt = settr(64,2,32,0,0,"DO", 1, 2, 0);
+ trans[1][29] = settr(59,2,34,42,42,"((i<size))", 1, 2, 0); /* m: 30 -> 34,0 */
+ reached1[30] = 1;
+ trans[1][30] = settr(0,0,0,0,0,"buffer_use[((prev_off+i)%8)] = 0",0,0,0);
+ trans[1][31] = settr(0,0,0,0,0,"i = (i+1)",0,0,0);
+ trans[1][32] = settr(62,2,44,43,43,"((i>=size))", 1, 2, 0); /* m: 37 -> 44,0 */
+ reached1[37] = 1;
+ trans[1][33] = settr(63,2,37,1,0,"goto :b1", 1, 2, 0); /* m: 37 -> 0,44 */
+ reached1[37] = 1;
+ trans[1][36] = settr(66,2,37,1,0,"break", 1, 2, 0);
+ trans[1][37] = settr(67,2,44,44,44,"tmp_commit = (commit_count[((prev_off%8)/(8/2))]+size)", 1, 2, 0); /* m: 38 -> 0,44 */
+ reached1[38] = 1;
+ trans[1][38] = settr(0,0,0,0,0,"_commit_sum = ((_commit_sum-commit_count[((prev_off%8)/(8/2))])+tmp_commit)",0,0,0);
+ trans[1][39] = settr(0,0,0,0,0,"commit_count[((prev_off%8)/(8/2))] = tmp_commit",0,0,0);
+ T = trans[1][44] = settr(74,2,0,0,0,"IF", 1, 2, 0);
+ T = T->nxt = settr(74,2,40,0,0,"IF", 1, 2, 0);
+ T->nxt = settr(74,2,42,0,0,"IF", 1, 2, 0);
+ trans[1][40] = settr(70,4,50,45,45,"((((((prev_off/8)*8)/2)+(8/2))-tmp_commit))", 1, 2, 0); /* m: 41 -> 50,0 */
+ reached1[41] = 1;
+ trans[1][41] = settr(0,0,0,0,0,"deliver = 1",0,0,0);
+ trans[1][45] = settr(75,0,50,46,46,".(goto)", 1, 2, 0);
+ trans[1][42] = settr(72,2,43,2,0,"else", 1, 2, 0);
+ trans[1][43] = settr(73,4,50,47,47,"(1)", 1, 2, 0); /* m: 45 -> 50,0 */
+ reached1[45] = 1;
+ T = trans[ 1][50] = settr(80,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(80,2,47,0,0,"ATOMIC", 1, 2, 0);
+ trans[1][47] = settr(77,2,49,1,0,"goto end", 1, 2, 0);
+ trans[1][48] = settr(78,2,49,48,48,"events_lost = (events_lost+1)", 1, 2, 0);
+ trans[1][49] = settr(79,0,51,49,49,"refcount = (refcount-1)", 1, 2, 0);
+ trans[1][51] = settr(81,0,0,50,50,"-end-", 0, 3500, 0);
+
+ /* proctype 0: switcher */
+
+ trans[0] = (Trans **) emalloc(32*sizeof(Trans *));
+
+ T = trans[ 0][11] = settr(10,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(10,2,1,0,0,"ATOMIC", 1, 2, 0);
+ trans[0][1] = settr(0,2,9,51,51,"prev_off = write_off", 1, 2, 0); /* m: 2 -> 0,9 */
+ reached0[2] = 1;
+ trans[0][2] = settr(0,0,0,0,0,"size = ((8/2)-(prev_off%(8/2)))",0,0,0);
+ trans[0][3] = settr(0,0,0,0,0,"new_off = (prev_off+size)",0,0,0);
+ T = trans[0][9] = settr(8,2,0,0,0,"IF", 1, 2, 0);
+ T = T->nxt = settr(8,2,4,0,0,"IF", 1, 2, 0);
+ T->nxt = settr(8,2,7,0,0,"IF", 1, 2, 0);
+ trans[0][4] = settr(3,4,30,52,52,"(((((new_off-read_off)>8)&&((new_off-read_off)<(255/2)))||(size==(8/2))))", 1, 2, 0); /* m: 5 -> 30,0 */
+ reached0[5] = 1;
+ trans[0][5] = settr(0,0,0,0,0,"refcount = (refcount-1)",0,0,0);
+ trans[0][6] = settr(5,0,30,1,0,"goto not_needed", 1, 2, 0);
+ trans[0][10] = settr(9,0,18,1,0,".(goto)", 1, 2, 0);
+ trans[0][7] = settr(6,2,8,2,0,"else", 1, 2, 0);
+ trans[0][8] = settr(7,4,18,53,53,"(1)", 1, 2, 0); /* m: 10 -> 18,0 */
+ reached0[10] = 1;
+ T = trans[ 0][18] = settr(17,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(17,2,16,0,0,"ATOMIC", 1, 2, 0);
+ T = trans[0][16] = settr(15,2,0,0,0,"IF", 1, 2, 0);
+ T = T->nxt = settr(15,2,12,0,0,"IF", 1, 2, 0);
+ T->nxt = settr(15,2,14,0,0,"IF", 1, 2, 0);
+ trans[0][12] = settr(11,4,11,54,54,"((prev_off!=write_off))", 1, 2, 0); /* m: 13 -> 11,0 */
+ reached0[13] = 1;
+ trans[0][13] = settr(12,0,11,1,0,"goto cmpxchg_loop", 1, 2, 0);
+ trans[0][17] = settr(16,0,29,55,55,".(goto)", 1, 2, 0);
+ trans[0][14] = settr(13,2,15,2,0,"else", 1, 2, 0);
+ trans[0][15] = settr(14,4,29,56,56,"write_off = new_off", 1, 2, 0); /* m: 17 -> 0,29 */
+ reached0[17] = 1;
+ T = trans[ 0][29] = settr(28,2,0,0,0,"ATOMIC", 1, 2, 0);
+ T->nxt = settr(28,2,19,0,0,"ATOMIC", 1, 2, 0);
+ trans[0][19] = settr(18,2,26,57,57,"tmp_commit = (commit_count[((prev_off%8)/(8/2))]+size)", 1, 2, 0); /* m: 20 -> 0,26 */
+ reached0[20] = 1;
+ trans[0][20] = settr(0,0,0,0,0,"_commit_sum = ((_commit_sum-commit_count[((prev_off%8)/(8/2))])+tmp_commit)",0,0,0);
+ trans[0][21] = settr(0,0,0,0,0,"commit_count[((prev_off%8)/(8/2))] = tmp_commit",0,0,0);
+ T = trans[0][26] = settr(25,2,0,0,0,"IF", 1, 2, 0);
+ T = T->nxt = settr(25,2,22,0,0,"IF", 1, 2, 0);
+ T->nxt = settr(25,2,24,0,0,"IF", 1, 2, 0);
+ trans[0][22] = settr(21,4,30,58,58,"((((((prev_off/8)*8)/2)+(8/2))-tmp_commit))", 1, 2, 0); /* m: 23 -> 30,0 */
+ reached0[23] = 1;
+ trans[0][23] = settr(0,0,0,0,0,"deliver = 1",0,0,0);
+ trans[0][27] = settr(26,4,30,59,59,".(goto)", 1, 2, 0); /* m: 28 -> 0,30 */
+ reached0[28] = 1;
+ trans[0][24] = settr(23,2,25,2,0,"else", 1, 2, 0);
+ trans[0][25] = settr(24,4,30,60,60,"(1)", 1, 2, 0); /* m: 27 -> 30,0 */
+ reached0[27] = 1;
+ trans[0][28] = settr(0,0,0,0,0,"refcount = (refcount-1)",0,0,0);
+ trans[0][30] = settr(29,0,31,1,0,"(1)", 0, 2, 0);
+ trans[0][31] = settr(30,0,0,61,61,"-end-", 0, 3500, 0);
+ /* np_ demon: */
+ trans[_NP_] = (Trans **) emalloc(2*sizeof(Trans *));
+ T = trans[_NP_][0] = settr(9997,0,1,_T5,0,"(np_)", 1,2,0);
+ T->nxt = settr(9998,0,0,_T2,0,"(1)", 0,2,0);
+ T = trans[_NP_][1] = settr(9999,0,1,_T5,0,"(np_)", 1,2,0);
+}
+
+Trans *
+settr( int t_id, int a, int b, int c, int d,
+ char *t, int g, int tpe0, int tpe1)
+{ Trans *tmp = (Trans *) emalloc(sizeof(Trans));
+
+ tmp->atom = a&(6|32); /* only (2|8|32) have meaning */
+ if (!g) tmp->atom |= 8; /* no global references */
+ tmp->st = b;
+ tmp->tpe[0] = tpe0;
+ tmp->tpe[1] = tpe1;
+ tmp->tp = t;
+ tmp->t_id = t_id;
+ tmp->forw = c;
+ tmp->back = d;
+ return tmp;
+}
+
+Trans *
+cpytr(Trans *a)
+{ Trans *tmp = (Trans *) emalloc(sizeof(Trans));
+
+ int i;
+ tmp->atom = a->atom;
+ tmp->st = a->st;
+#ifdef HAS_UNLESS
+ tmp->e_trans = a->e_trans;
+ for (i = 0; i < HAS_UNLESS; i++)
+ tmp->escp[i] = a->escp[i];
+#endif
+ tmp->tpe[0] = a->tpe[0];
+ tmp->tpe[1] = a->tpe[1];
+ for (i = 0; i < 6; i++)
+ { tmp->qu[i] = a->qu[i];
+ tmp->ty[i] = a->ty[i];
+ }
+ tmp->tp = (char *) emalloc(strlen(a->tp)+1);
+ strcpy(tmp->tp, a->tp);
+ tmp->t_id = a->t_id;
+ tmp->forw = a->forw;
+ tmp->back = a->back;
+ return tmp;
+}
+
+#ifndef NOREDUCE
+int
+srinc_set(int n)
+{ if (n <= 2) return LOCAL;
+ if (n <= 2+ DELTA) return Q_FULL_F; /* 's' or nfull */
+ if (n <= 2+2*DELTA) return Q_EMPT_F; /* 'r' or nempty */
+ if (n <= 2+3*DELTA) return Q_EMPT_T; /* empty */
+ if (n <= 2+4*DELTA) return Q_FULL_T; /* full */
+ if (n == 5*DELTA) return GLOBAL;
+ if (n == 6*DELTA) return TIMEOUT_F;
+ if (n == 7*DELTA) return ALPHA_F;
+ Uerror("cannot happen srinc_class");
+ return BAD;
+}
+int
+srunc(int n, int m)
+{ switch(m) {
+ case Q_FULL_F: return n-2;
+ case Q_EMPT_F: return n-2-DELTA;
+ case Q_EMPT_T: return n-2-2*DELTA;
+ case Q_FULL_T: return n-2-3*DELTA;
+ case ALPHA_F:
+ case TIMEOUT_F: return 257; /* non-zero, and > MAXQ */
+ }
+ Uerror("cannot happen srunc");
+ return 0;
+}
+#endif
+int cnt;
+#ifdef HAS_UNLESS
+int
+isthere(Trans *a, int b)
+{ Trans *t;
+ for (t = a; t; t = t->nxt)
+ if (t->t_id == b)
+ return 1;
+ return 0;
+}
+#endif
+#ifndef NOREDUCE
+int
+mark_safety(Trans *t) /* for conditional safety */
+{ int g = 0, i, j, k;
+
+ if (!t) return 0;
+ if (t->qu[0])
+ return (t->qu[1])?2:1; /* marked */
+
+ for (i = 0; i < 2; i++)
+ { j = srinc_set(t->tpe[i]);
+ if (j >= GLOBAL && j != ALPHA_F)
+ return -1;
+ if (j != LOCAL)
+ { k = srunc(t->tpe[i], j);
+ if (g == 0
+ || t->qu[0] != k
+ || t->ty[0] != j)
+ { t->qu[g] = k;
+ t->ty[g] = j;
+ g++;
+ } } }
+ return g;
+}
+#endif
+void
+retrans(int n, int m, int is, short srcln[], uchar reach[], uchar lstate[])
+ /* process n, with m states, is=initial state */
+{ Trans *T0, *T1, *T2, *T3;
+ int i, k;
+#ifndef NOREDUCE
+ int g, h, j, aa;
+#endif
+#ifdef HAS_UNLESS
+ int p;
+#endif
+ if (state_tables >= 4)
+ { printf("STEP 1 proctype %s\n",
+ procname[n]);
+ for (i = 1; i < m; i++)
+ for (T0 = trans[n][i]; T0; T0 = T0->nxt)
+ crack(n, i, T0, srcln);
+ return;
+ }
+ do {
+ for (i = 1, cnt = 0; i < m; i++)
+ { T2 = trans[n][i];
+ T1 = T2?T2->nxt:(Trans *)0;
+/* prescan: */ for (T0 = T1; T0; T0 = T0->nxt)
+/* choice in choice */ { if (T0->st && trans[n][T0->st]
+ && trans[n][T0->st]->nxt)
+ break;
+ }
+#if 0
+ if (T0)
+ printf("\tstate %d / %d: choice in choice\n",
+ i, T0->st);
+#endif
+ if (T0)
+ for (T0 = T1; T0; T0 = T0->nxt)
+ { T3 = trans[n][T0->st];
+ if (!T3->nxt)
+ { T2->nxt = cpytr(T0);
+ T2 = T2->nxt;
+ imed(T2, T0->st, n, i);
+ continue;
+ }
+ do { T3 = T3->nxt;
+ T2->nxt = cpytr(T3);
+ T2 = T2->nxt;
+ imed(T2, T0->st, n, i);
+ } while (T3->nxt);
+ cnt++;
+ }
+ }
+ } while (cnt);
+ if (state_tables >= 3)
+ { printf("STEP 2 proctype %s\n",
+ procname[n]);
+ for (i = 1; i < m; i++)
+ for (T0 = trans[n][i]; T0; T0 = T0->nxt)
+ crack(n, i, T0, srcln);
+ return;
+ }
+ for (i = 1; i < m; i++)
+ { if (trans[n][i] && trans[n][i]->nxt) /* optimize */
+ { T1 = trans[n][i]->nxt;
+#if 0
+ printf("\t\tpull %d (%d) to %d\n",
+ T1->st, T1->forw, i);
+#endif
+ if (!trans[n][T1->st]) continue;
+ T0 = cpytr(trans[n][T1->st]);
+ trans[n][i] = T0;
+ reach[T1->st] = 1;
+ imed(T0, T1->st, n, i);
+ for (T1 = T1->nxt; T1; T1 = T1->nxt)
+ {
+#if 0
+ printf("\t\tpull %d (%d) to %d\n",
+ T1->st, T1->forw, i);
+#endif
+ if (!trans[n][T1->st]) continue;
+ T0->nxt = cpytr(trans[n][T1->st]);
+ T0 = T0->nxt;
+ reach[T1->st] = 1;
+ imed(T0, T1->st, n, i);
+ } } }
+ if (state_tables >= 2)
+ { printf("STEP 3 proctype %s\n",
+ procname[n]);
+ for (i = 1; i < m; i++)
+ for (T0 = trans[n][i]; T0; T0 = T0->nxt)
+ crack(n, i, T0, srcln);
+ return;
+ }
+#ifdef HAS_UNLESS
+ for (i = 1; i < m; i++)
+ { if (!trans[n][i]) continue;
+ /* check for each state i if an
+ * escape to some state p is defined
+ * if so, copy and mark p's transitions
+ * and prepend them to the transition-
+ * list of state i
+ */
+ if (!like_java) /* the default */
+ { for (T0 = trans[n][i]; T0; T0 = T0->nxt)
+ for (k = HAS_UNLESS-1; k >= 0; k--)
+ { if (p = T0->escp[k])
+ for (T1 = trans[n][p]; T1; T1 = T1->nxt)
+ { if (isthere(trans[n][i], T1->t_id))
+ continue;
+ T2 = cpytr(T1);
+ T2->e_trans = p;
+ T2->nxt = trans[n][i];
+ trans[n][i] = T2;
+ } }
+ } else /* outermost unless checked first */
+ { Trans *T4;
+ T4 = T3 = (Trans *) 0;
+ for (T0 = trans[n][i]; T0; T0 = T0->nxt)
+ for (k = HAS_UNLESS-1; k >= 0; k--)
+ { if (p = T0->escp[k])
+ for (T1 = trans[n][p]; T1; T1 = T1->nxt)
+ { if (isthere(trans[n][i], T1->t_id))
+ continue;
+ T2 = cpytr(T1);
+ T2->nxt = (Trans *) 0;
+ T2->e_trans = p;
+ if (T3) T3->nxt = T2;
+ else T4 = T2;
+ T3 = T2;
+ } }
+ if (T4)
+ { T3->nxt = trans[n][i];
+ trans[n][i] = T4;
+ }
+ }
+ }
+#endif
+#ifndef NOREDUCE
+ for (i = 1; i < m; i++)
+ { if (a_cycles)
+ { /* moves through these states are visible */
+ #if PROG_LAB>0 && defined(HAS_NP)
+ if (progstate[n][i])
+ goto degrade;
+ for (T1 = trans[n][i]; T1; T1 = T1->nxt)
+ if (progstate[n][T1->st])
+ goto degrade;
+ #endif
+ if (accpstate[n][i] || visstate[n][i])
+ goto degrade;
+ for (T1 = trans[n][i]; T1; T1 = T1->nxt)
+ if (accpstate[n][T1->st])
+ goto degrade;
+ }
+ T1 = trans[n][i];
+ if (!T1) continue;
+ g = mark_safety(T1); /* V3.3.1 */
+ if (g < 0) goto degrade; /* global */
+ /* check if mixing of guards preserves reduction */
+ if (T1->nxt)
+ { k = 0;
+ for (T0 = T1; T0; T0 = T0->nxt)
+ { if (!(T0->atom&8))
+ goto degrade;
+ for (aa = 0; aa < 2; aa++)
+ { j = srinc_set(T0->tpe[aa]);
+ if (j >= GLOBAL && j != ALPHA_F)
+ goto degrade;
+ if (T0->tpe[aa]
+ && T0->tpe[aa]
+ != T1->tpe[0])
+ k = 1;
+ } }
+ /* g = 0; V3.3.1 */
+ if (k) /* non-uniform selection */
+ for (T0 = T1; T0; T0 = T0->nxt)
+ for (aa = 0; aa < 2; aa++)
+ { j = srinc_set(T0->tpe[aa]);
+ if (j != LOCAL)
+ { k = srunc(T0->tpe[aa], j);
+ for (h = 0; h < 6; h++)
+ if (T1->qu[h] == k
+ && T1->ty[h] == j)
+ break;
+ if (h >= 6)
+ { T1->qu[g%6] = k;
+ T1->ty[g%6] = j;
+ g++;
+ } } }
+ if (g > 6)
+ { T1->qu[0] = 0; /* turn it off */
+ printf("pan: warning, line %d, ",
+ srcln[i]);
+ printf("too many stmnt types (%d)",
+ g);
+ printf(" in selection\n");
+ goto degrade;
+ }
+ }
+ /* mark all options global if >=1 is global */
+ for (T1 = trans[n][i]; T1; T1 = T1->nxt)
+ if (!(T1->atom&8)) break;
+ if (T1)
+degrade: for (T1 = trans[n][i]; T1; T1 = T1->nxt)
+ T1->atom &= ~8; /* mark as unsafe */
+ /* can only mix 'r's or 's's if on same chan */
+ /* and not mixed with other local operations */
+ T1 = trans[n][i];
+ if (!T1 || T1->qu[0]) continue;
+ j = T1->tpe[0];
+ if (T1->nxt && T1->atom&8)
+ { if (j == 5*DELTA)
+ { printf("warning: line %d ", srcln[i]);
+ printf("mixed condition ");
+ printf("(defeats reduction)\n");
+ goto degrade;
+ }
+ for (T0 = T1; T0; T0 = T0->nxt)
+ for (aa = 0; aa < 2; aa++)
+ if (T0->tpe[aa] && T0->tpe[aa] != j)
+ { printf("warning: line %d ", srcln[i]);
+ printf("[%d-%d] mixed %stion ",
+ T0->tpe[aa], j,
+ (j==5*DELTA)?"condi":"selec");
+ printf("(defeats reduction)\n");
+ printf(" '%s' <-> '%s'\n",
+ T1->tp, T0->tp);
+ goto degrade;
+ } }
+ }
+#endif
+ for (i = 1; i < m; i++)
+ { T2 = trans[n][i];
+ if (!T2
+ || T2->nxt
+ || strncmp(T2->tp, ".(goto)", 7)
+ || !stopstate[n][i])
+ continue;
+ stopstate[n][T2->st] = 1;
+ }
+ if (state_tables)
+ { printf("proctype ");
+ if (!strcmp(procname[n], ":init:"))
+ printf("init\n");
+ else
+ printf("%s\n", procname[n]);
+ for (i = 1; i < m; i++)
+ reach[i] = 1;
+ tagtable(n, m, is, srcln, reach);
+ } else
+ for (i = 1; i < m; i++)
+ { int nrelse;
+ if (strcmp(procname[n], ":never:") != 0)
+ { for (T0 = trans[n][i]; T0; T0 = T0->nxt)
+ { if (T0->st == i
+ && strcmp(T0->tp, "(1)") == 0)
+ { printf("error: proctype '%s' ",
+ procname[n]);
+ printf("line %d, state %d: has un",
+ srcln[i], i);
+ printf("conditional self-loop\n");
+ pan_exit(1);
+ } } }
+ nrelse = 0;
+ for (T0 = trans[n][i]; T0; T0 = T0->nxt)
+ { if (strcmp(T0->tp, "else") == 0)
+ nrelse++;
+ }
+ if (nrelse > 1)
+ { printf("error: proctype '%s' state",
+ procname[n]);
+ printf(" %d, inherits %d", i, nrelse);
+ printf(" 'else' stmnts\n");
+ pan_exit(1);
+ } }
+ if (!state_tables && strcmp(procname[n], ":never:") == 0)
+ { int h = 0;
+ for (i = 1; i < m; i++)
+ for (T0 = trans[n][i]; T0; T0 = T0->nxt)
+ if (T0->forw > h) h = T0->forw;
+ h++;
+ frm_st0 = (short *) emalloc(h * sizeof(short));
+ for (i = 1; i < m; i++)
+ for (T0 = trans[n][i]; T0; T0 = T0->nxt)
+ frm_st0[T0->forw] = i;
+ }
+#ifndef LOOPSTATE
+ if (state_tables)
+#endif
+ do_dfs(n, m, is, srcln, reach, lstate);
+#ifdef T_REVERSE
+ /* process n, with m states, is=initial state -- reverse list */
+ if (!state_tables && strcmp(procname[n], ":never:") != 0)
+ { for (i = 1; i < m; i++)
+ { Trans *T4 = (Trans *) 0;
+ T1 = (Trans *) 0;
+ T2 = (Trans *) 0;
+ T3 = (Trans *) 0;
+ for (T0 = trans[n][i]; T0; T0 = T4)
+ { T4 = T0->nxt;
+ if (strcmp(T0->tp, "else") == 0)
+ { T3 = T0;
+ T0->nxt = (Trans *) 0;
+ } else
+ { T0->nxt = T1;
+ if (!T1) { T2 = T0; }
+ T1 = T0;
+ } }
+ if (T2 && T3) { T2->nxt = T3; }
+ trans[n][i] = T1; /* reversed -- else at end */
+ } }
+#endif
+}
+void
+imed(Trans *T, int v, int n, int j) /* set intermediate state */
+{ progstate[n][T->st] |= progstate[n][v];
+ accpstate[n][T->st] |= accpstate[n][v];
+ stopstate[n][T->st] |= stopstate[n][v];
+ mapstate[n][j] = T->st;
+}
+void
+tagtable(int n, int m, int is, short srcln[], uchar reach[])
+{ Trans *z;
+
+ if (is >= m || !trans[n][is]
+ || is <= 0 || reach[is] == 0)
+ return;
+ reach[is] = 0;
+ if (state_tables)
+ for (z = trans[n][is]; z; z = z->nxt)
+ crack(n, is, z, srcln);
+ for (z = trans[n][is]; z; z = z->nxt)
+ {
+#ifdef HAS_UNLESS
+ int i, j;
+#endif
+ tagtable(n, m, z->st, srcln, reach);
+#ifdef HAS_UNLESS
+ for (i = 0; i < HAS_UNLESS; i++)
+ { j = trans[n][is]->escp[i];
+ if (!j) break;
+ tagtable(n, m, j, srcln, reach);
+ }
+#endif
+ }
+}
+void
+dfs_table(int n, int m, int is, short srcln[], uchar reach[], uchar lstate[])
+{ Trans *z;
+
+ if (is >= m || is <= 0 || !trans[n][is])
+ return;
+ if ((reach[is] & (4|8|16)) != 0)
+ { if ((reach[is] & (8|16)) == 16) /* on stack, not yet recorded */
+ { lstate[is] = 1;
+ reach[is] |= 8; /* recorded */
+ if (state_tables)
+ { printf("state %d line %d is a loopstate\n", is, srcln[is]);
+ } }
+ return;
+ }
+ reach[is] |= (4|16); /* visited | onstack */
+ for (z = trans[n][is]; z; z = z->nxt)
+ {
+#ifdef HAS_UNLESS
+ int i, j;
+#endif
+ dfs_table(n, m, z->st, srcln, reach, lstate);
+#ifdef HAS_UNLESS
+ for (i = 0; i < HAS_UNLESS; i++)
+ { j = trans[n][is]->escp[i];
+ if (!j) break;
+ dfs_table(n, m, j, srcln, reach, lstate);
+ }
+#endif
+ }
+ reach[is] &= ~16; /* no longer on stack */
+}
+void
+do_dfs(int n, int m, int is, short srcln[], uchar reach[], uchar lstate[])
+{ int i;
+ dfs_table(n, m, is, srcln, reach, lstate);
+ for (i = 0; i < m; i++)
+ reach[i] &= ~(4|8|16);
+}
+void
+crack(int n, int j, Trans *z, short srcln[])
+{ int i;
+
+ if (!z) return;
+ printf(" state %3d -(tr %3d)-> state %3d ",
+ j, z->forw, z->st);
+ printf("[id %3d tp %3d", z->t_id, z->tpe[0]);
+ if (z->tpe[1]) printf(",%d", z->tpe[1]);
+#ifdef HAS_UNLESS
+ if (z->e_trans)
+ printf(" org %3d", z->e_trans);
+ else if (state_tables >= 2)
+ for (i = 0; i < HAS_UNLESS; i++)
+ { if (!z->escp[i]) break;
+ printf(" esc %d", z->escp[i]);
+ }
+#endif
+ printf("]");
+ printf(" [%s%s%s%s%s] line %d => ",
+ z->atom&6?"A":z->atom&32?"D":"-",
+ accpstate[n][j]?"a" :"-",
+ stopstate[n][j]?"e" : "-",
+ progstate[n][j]?"p" : "-",
+ z->atom & 8 ?"L":"G",
+ srcln[j]);
+ for (i = 0; z->tp[i]; i++)
+ if (z->tp[i] == '\n')
+ printf("\\n");
+ else
+ putchar(z->tp[i]);
+ if (z->qu[0])
+ { printf("\t[");
+ for (i = 0; i < 6; i++)
+ if (z->qu[i])
+ printf("(%d,%d)",
+ z->qu[i], z->ty[i]);
+ printf("]");
+ }
+ printf("\n");
+ fflush(stdout);
+}
+
+#ifdef VAR_RANGES
+#define BYTESIZE 32 /* 2^8 : 2^3 = 256:8 = 32 */
+
+typedef struct Vr_Ptr {
+ char *nm;
+ uchar vals[BYTESIZE];
+ struct Vr_Ptr *nxt;
+} Vr_Ptr;
+Vr_Ptr *ranges = (Vr_Ptr *) 0;
+
+void
+logval(char *s, int v)
+{ Vr_Ptr *tmp;
+
+ if (v<0 || v > 255) return;
+ for (tmp = ranges; tmp; tmp = tmp->nxt)
+ if (!strcmp(tmp->nm, s))
+ goto found;
+ tmp = (Vr_Ptr *) emalloc(sizeof(Vr_Ptr));
+ tmp->nxt = ranges;
+ ranges = tmp;
+ tmp->nm = s;
+found:
+ tmp->vals[(v)/8] |= 1<<((v)%8);
+}
+
+void
+dumpval(uchar X[], int range)
+{ int w, x, i, j = -1;
+
+ for (w = i = 0; w < range; w++)
+ for (x = 0; x < 8; x++, i++)
+ {
+from: if ((X[w] & (1<<x)))
+ { printf("%d", i);
+ j = i;
+ goto upto;
+ } }
+ return;
+ for (w = 0; w < range; w++)
+ for (x = 0; x < 8; x++, i++)
+ {
+upto: if (!(X[w] & (1<<x)))
+ { if (i-1 == j)
+ printf(", ");
+ else
+ printf("-%d, ", i-1);
+ goto from;
+ } }
+ if (j >= 0 && j != 255)
+ printf("-255");
+}
+
+void
+dumpranges(void)
+{ Vr_Ptr *tmp;
+ printf("\nValues assigned within ");
+ printf("interval [0..255]:\n");
+ for (tmp = ranges; tmp; tmp = tmp->nxt)
+ { printf("\t%s\t: ", tmp->nm);
+ dumpval(tmp->vals, BYTESIZE);
+ printf("\n");
+ }
+}
+#endif
--- /dev/null
+make[1]: Entering directory `/home/compudj/repository/trunk/verif/nico-md-merge'
+rm -f pan* trail.out
+cat defines > pan.ltl
+spin -f "!(`cat read_write.ltl | grep -v ^//`)" >> pan.ltl
+spin -a -X -N pan.ltl model.spin
+Exit-Status 0
+gcc -w -o pan -D_POSIX_SOURCE -DMEMLIM=750 -DXUSAFE -DNOFAIR pan.c
+./pan -v -X -m100000 -w21 -a -c1
+warning: for p.o. reduction to be valid the never claim must be stutter-invariant
+(never claims generated from LTL formulae are stutter-invariant)
+depth 0: Claim reached state 5 (line 302)
+
+(Spin Version 5.1.6 -- 9 May 2008)
+ + Partial Order Reduction
+
+Full statespace search for:
+ never claim +
+ assertion violations + (if within scope of claim)
+ acceptance cycles + (fairness disabled)
+ invalid end states - (disabled by never claim)
+
+State-vector 92 byte, depth reached 178, errors: 0
+ 117886 states, stored
+ 210653 states, matched
+ 328539 transitions (= stored+matched)
+ 440774 atomic steps
+hash conflicts: 3201 (resolved)
+
+Stats on memory usage (in Megabytes):
+ 12.142 equivalent memory usage for states (stored*(State-vector + overhead))
+ 8.971 actual memory usage for states (compression: 73.88%)
+ state-vector as stored = 64 byte + 16 byte overhead
+ 8.000 memory used for hash table (-w21)
+ 3.052 memory used for DFS stack (-m100000)
+ 19.939 total actual memory usage
+
+unreached in proctype switcher
+ line 81, "pan.___", state 8, "(1)"
+ line 87, "pan.___", state 15, "write_off = new_off"
+ line 84, "pan.___", state 18, "((prev_off!=write_off))"
+ line 84, "pan.___", state 18, "else"
+ line 97, "pan.___", state 21, "commit_count[((prev_off%4)/(4/2))] = tmp_commit"
+ line 103, "pan.___", state 25, "(1)"
+ line 98, "pan.___", state 26, "((((((prev_off/4)*4)/2)+(4/2))-tmp_commit))"
+ line 98, "pan.___", state 26, "else"
+ line 91, "pan.___", state 29, "tmp_commit = (commit_count[((prev_off%4)/(4/2))]+size)"
+ (7 of 31 states)
+unreached in proctype tracer
+ line 177, "pan.___", state 48, "events_lost = (events_lost+1)"
+ (1 of 51 states)
+unreached in proctype reader
+ (0 of 29 states)
+unreached in proctype cleaner
+ (0 of 9 states)
+unreached in proctype :init:
+ line 284, "pan.___", state 35, "(run switcher())"
+ (1 of 43 states)
+unreached in proctype :never:
+ line 307, "pan.___", state 8, "-end-"
+ (1 of 8 states)
+
+pan: elapsed time 0.85 seconds
+pan: rate 138689.41 states/second
+pan: avg transition delay 2.5872e-06 usec
+make[1]: Leaving directory `/home/compudj/repository/trunk/verif/nico-md-merge'
--- /dev/null
+// The writer head must always be superior or equal to the reader head.
+// assert(write_off - read_off >= 0 && write_off - read_off < HALF_UCHAR);
+
+[] (rwoff1 && rwoff2)
--- /dev/null
+# makefile
+
+COPTIONS=-DSAFETY
+
+
+default:
+ make commit_sum | tee commit_sum.log
+ make read_write | tee read_write.log
+ make events_lost | tee events_lost.log
+ make no_events_lost | tee no_events_lost.log
+
+
+no_events_lost: clean no_events_lost_ltl run
+
+no_events_lost_ltl:
+ cat DEFINES > pan.ltl
+ spin -f "!(`cat no_events_lost.ltl | grep -v ^//`)" >> pan.ltl
+
+
+
+events_lost: clean events_lost_ltl run
+
+events_lost_ltl:
+ cat DEFINES > pan.ltl
+ spin -f "!(`cat events_lost.ltl`)" >> pan.ltl
+
+
+
+read_write: clean read_write_ltl run
+
+read_write_ltl:
+ cat DEFINES > pan.ltl
+ spin -f "!(`cat read_write.ltl`)" >> pan.ltl
+
+
+
+commit_sum: clean commit_sum_ltl run
+
+commit_sum_ltl:
+ cat DEFINES > pan.ltl
+ spin -f "!(`cat commit_sum.ltl`)" >> pan.ltl
+
+
+
+run: pan
+ ./pan -v -X -m100000 -w21 -a -c1
+
+pan: pan.c
+ gcc -w -o pan -D_POSIX_SOURCE -DMEMLIM=750 -DXUSAFE -DNOFAIR pan.c
+
+pan.c: pan.ltl model.spin
+ spin -a -X -N pan.ltl model.spin
+
+
+
+clean:
+ rm -f pan* trail.out
--- /dev/null
+[] (commit_sum_wr_off1 && commit_sum_wr_off2)
--- /dev/null
+#define rd_wr_wr_off1 (write_off - read_off >= 0)
+#define rd_wr_wr_off2 (write_off - read_off < HALF_UCHAR)
+
+#define commit_sum_wr_off1 (write_off - commit_sum >= 0)
+#define commit_sum_wr_off2 (write_off - commit_sum < HALF_UCHAR)
+
+#define buffer_large_enough (NUMPROCS + NUMSWITCH <= BUFSIZE)
+#define have_events_lost (events_lost != 0)
--- /dev/null
+(!buffer_large_enough) -> (<> have_events_lost)
--- /dev/null
+models/model_03.spin
\ No newline at end of file
--- /dev/null
+-2:5:-2
+-4:-4:-4
+1:0:164
+2:1:120
+3:1:121
+4:1:121
+5:1:124
+6:1:130
+7:1:130
+8:1:130
+9:1:130
+10:1:133
+11:1:138
+12:1:139
+13:1:141
+14:1:143
+15:1:141
+16:1:143
+17:1:141
+18:1:143
+19:1:141
+20:1:143
+21:1:145
+22:1:151
+23:1:153
+24:1:155
+25:1:159
+26:0:168
+27:8:0
+28:8:3
+29:0:168
+30:8:29
+31:0:168
+32:8:30
+33:0:168
+34:7:31
+35:0:168
+36:7:36
+37:7:37
+38:0:168
+39:7:43
+40:7:44
+41:7:48
+42:7:52
+43:7:56
+44:0:168
+45:7:58
+46:7:59
+47:7:62
+48:7:70
+49:0:168
+50:7:77
+51:7:79
+52:0:168
+53:7:81
+54:0:168
+55:6:31
+56:0:168
+57:6:36
+58:6:37
+59:0:168
+60:6:43
+61:6:44
+62:6:48
+63:6:52
+64:6:56
+65:0:168
+66:6:58
+67:6:59
+68:6:62
+69:6:72
+70:6:73
+71:0:168
+72:6:77
+73:6:79
+74:0:168
+75:6:81
+76:0:168
+77:5:31
+78:0:168
+79:5:36
+80:5:37
+81:0:168
+82:5:43
+83:5:44
+84:5:48
+85:5:52
+86:5:56
+87:0:168
+88:5:58
+89:5:59
+90:5:62
+91:5:70
+92:0:168
+93:5:77
+94:5:79
+95:0:168
+96:5:81
+97:0:168
+98:4:31
+99:0:168
+100:4:36
+101:4:37
+102:0:168
+103:4:43
+104:4:44
+105:4:48
+106:4:52
+107:4:56
+108:0:168
+109:4:58
+110:4:59
+111:4:62
+112:4:72
+113:4:73
+114:0:168
+115:4:77
+116:4:79
+117:0:168
+118:4:81
+119:0:168
+120:3:111
+121:3:113
+122:3:117
+123:0:168
+124:4:0
+125:4:3
+126:0:168
+127:4:29
+128:0:168
+129:4:30
+130:0:168
+131:3:119
+132:0:168
+133:2:82
+134:0:168
+135:2:83
+136:2:84
+137:2:84
+138:2:88
+139:2:92
+140:0:168
+141:2:94
+142:2:95
+143:2:95
+144:2:98
+145:2:102
+146:2:103
+147:0:168
+148:2:82
+149:0:168
+150:2:83
+151:2:84
+152:2:84
+153:2:88
+154:2:92
+155:0:168
+156:2:94
+157:2:95
+158:2:95
+159:2:98
+160:2:102
+161:2:103
+162:0:168
+163:2:105
+164:0:168
+165:2:110
+166:0:168
+167:1:161
+168:0:168
+169:1:163
+-1:-1:-1
+170:0:168
+171:0:168
--- /dev/null
+/* LTTng ltt-tracer.c atomic lockless buffering scheme Promela model v2
+ * Created for the Spin validator.
+ * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ * October 2008
+
+ * TODO : create test cases that will generate an overflow on the offset and
+ * counter type. Counter types smaller than a byte should be used.
+
+ * Promela only has unsigned char, no signed char.
+ * Because detection of difference < 0 depends on a signed type, but we want
+ * compactness, check also for the values being higher than half of the unsigned
+ * char range (and consider them negative). The model, by design, does not use
+ * offsets or counts higher than 127 because we would then have to use a larger
+ * type (short or int).
+ */
+#define HALF_UCHAR (255/2)
+
+/* NUMPROCS 4 : causes event loss with some reader timings.
+ * e.g. 3 events, 1 switch, 1 event (lost, buffer full), read 1 subbuffer
+ */
+#define NUMPROCS 4
+
+/* NUMPROCS 3 : does not cause event loss because buffers are big enough.
+ * #define NUMPROCS 3
+ * e.g. 3 events, 1 switch, read 1 subbuffer
+ */
+
+#define NUMSWITCH 1
+#define BUFSIZE 4
+#define NR_SUBBUFS 2
+#define SUBBUF_SIZE (BUFSIZE / NR_SUBBUFS)
+
+/* Writer counters
+*/
+byte write_off = 0;
+byte commit_count[NR_SUBBUFS];
+
+/* Reader counters
+*/
+byte read_off = 0;
+
+byte events_lost = 0;
+byte refcount = 0;
+
+bool deliver = 0;
+
+/* buffer slot in-use bit. Detects racy use (more than a single process
+ * accessing a slot at any given step).
+ */
+bool buffer_use[BUFSIZE];
+
+/* Proceed to a sub-subber switch is needed.
+ * Used in a periodical timer interrupt to fill and ship the current subbuffer
+ * to the reader so we can guarantee a steady flow. If a subbuffer is
+ * completely empty, do not switch.
+ * Also used as "finalize" operation to complete the last subbuffer after
+ * all writers have finished so the last subbuffer can be read by the reader.
+ */
+proctype switcher()
+{
+ byte prev_off, new_off, tmp_commit;
+ byte size;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ size = SUBBUF_SIZE - (prev_off % SUBBUF_SIZE);
+ new_off = prev_off + size;
+ if
+ :: (new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR)
+ || size == SUBBUF_SIZE ->
+ refcount = refcount - 1;
+ goto not_needed;
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ }
+
+ atomic {
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ refcount = refcount - 1;
+ }
+not_needed:
+ skip;
+}
+
+/* tracer
+ * Writes 1 byte of information in the buffer at the current
+ * "write_off" position and then increment the commit_count of the sub-buffer
+ * the information has been written to.
+ */
+proctype tracer()
+{
+ byte size = 1;
+ byte prev_off, new_off, tmp_commit;
+ byte i, j;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ new_off = prev_off + size;
+ }
+ atomic {
+ if
+ :: new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR ->
+ goto lost
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ i = 0;
+ do
+ :: i < size ->
+ assert(buffer_use[(prev_off + i) % BUFSIZE] == 0);
+ buffer_use[(prev_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= size -> break
+ od;
+ }
+
+ /* writing to buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < size ->
+ buffer_use[(prev_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= size -> break
+ od;
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ }
+ atomic {
+ goto end;
+lost:
+ events_lost++;
+end:
+ refcount = refcount - 1;
+ }
+}
+
+/* reader
+ * Read the information sub-buffer per sub-buffer when available.
+ *
+ * Reads the information as soon as it is ready, or may be delayed by
+ * an asynchronous delivery. Being modeled as a process insures all cases
+ * (scheduled very quickly or very late, causing event loss) are covered.
+ * Only one reader per buffer (normally ensured by a mutex). This is modeled
+ * by using a single reader process.
+ */
+proctype reader()
+{
+ byte i, j;
+
+ do
+ :: (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) > 0
+ && (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) < HALF_UCHAR
+ && (commit_count[(read_off % BUFSIZE) / SUBBUF_SIZE]
+ - SUBBUF_SIZE - (((read_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS)
+ == 0) ->
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ assert(buffer_use[(read_off + i) % BUFSIZE] == 0);
+ buffer_use[(read_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ }
+
+ /* reading from buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ buffer_use[(read_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ read_off = read_off + SUBBUF_SIZE;
+ }
+ :: read_off >= (NUMPROCS - events_lost) -> break;
+ od;
+}
+
+/* Waits for all tracer and switcher processes to finish before finalizing
+ * the buffer. Only after that will the reader be allowed to read the
+ * last subbuffer.
+ */
+proctype cleaner()
+{
+ atomic {
+ do
+ :: refcount == 0 ->
+ refcount = refcount + 1;
+ run switcher(); /* Finalize the last sub-buffer so it can be read. */
+ break;
+ od;
+ }
+}
+
+init {
+ byte i = 0;
+ byte j = 0;
+ byte sum = 0;
+ byte commit_sum = 0;
+
+ atomic {
+ i = 0;
+ do
+ :: i < NR_SUBBUFS ->
+ commit_count[i] = 0;
+ i++
+ :: i >= NR_SUBBUFS -> break
+ od;
+ i = 0;
+ do
+ :: i < BUFSIZE ->
+ buffer_use[i] = 0;
+ i++
+ :: i >= BUFSIZE -> break
+ od;
+ run reader();
+ run cleaner();
+ i = 0;
+ do
+ :: i < NUMPROCS ->
+ refcount = refcount + 1;
+ run tracer();
+ i++
+ :: i >= NUMPROCS -> break
+ od;
+ i = 0;
+ do
+ :: i < NUMSWITCH ->
+ refcount = refcount + 1;
+ run switcher();
+ i++
+ :: i >= NUMSWITCH -> break
+ od;
+ }
+
+ /* Assertions.
+ */
+ atomic {
+ /* The writer head must always be superior or equal to the reader head.
+ */
+ assert(write_off - read_off >= 0 && write_off - read_off < HALF_UCHAR);
+ j = 0;
+ commit_sum = 0;
+ do
+ :: j < NR_SUBBUFS ->
+ commit_sum = commit_sum + commit_count[j];
+ /* The commit count of a particular subbuffer must always be higher
+ * or equal to the retrieve_count of this subbuffer.
+ * assert(commit_count[j] - retrieve_count[j] >= 0 &&
+ * commit_count[j] - retrieve_count[j] < HALF_UCHAR);
+ */
+ j++
+ :: j >= NR_SUBBUFS -> break
+ od;
+ /* The sum of all subbuffer commit counts must always be lower or equal
+ * to the writer head, because space must be reserved before it is
+ * written to and then committed.
+ */
+ assert(write_off - commit_sum >= 0 && write_off - commit_sum < HALF_UCHAR);
+
+ /* If we have less writers than the buffer space available, we should
+ * not lose events
+ */
+ assert(NUMPROCS + NUMSWITCH > BUFSIZE || events_lost == 0);
+ }
+}
+
--- /dev/null
+/* LTTng ltt-tracer.c atomic lockless buffering scheme Promela model v2
+ * Created for the Spin validator.
+ * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ * October 2008
+
+ * TODO : create test cases that will generate an overflow on the offset and
+ * counter type. Counter types smaller than a byte should be used.
+
+ * Promela only has unsigned char, no signed char.
+ * Because detection of difference < 0 depends on a signed type, but we want
+ * compactness, check also for the values being higher than half of the unsigned
+ * char range (and consider them negative). The model, by design, does not use
+ * offsets or counts higher than 127 because we would then have to use a larger
+ * type (short or int).
+ */
+#define HALF_UCHAR (255/2)
+
+/* NUMPROCS 4 : causes event loss with some reader timings.
+ * e.g. 3 events, 1 switch, 1 event (lost, buffer full), read 1 subbuffer
+ */
+#define NUMPROCS 4
+
+/* NUMPROCS 3 : does not cause event loss because buffers are big enough.
+ * #define NUMPROCS 3
+ * e.g. 3 events, 1 switch, read 1 subbuffer
+ */
+
+#define NUMSWITCH 1
+#define BUFSIZE 4
+#define NR_SUBBUFS 2
+#define SUBBUF_SIZE (BUFSIZE / NR_SUBBUFS)
+
+/* Writer counters
+*/
+byte write_off = 0;
+byte commit_count[NR_SUBBUFS];
+
+/* Reader counters
+*/
+byte read_off = 0;
+
+byte events_lost = 0;
+byte refcount = 0;
+
+bool deliver = 0;
+
+/* buffer slot in-use bit. Detects racy use (more than a single process
+ * accessing a slot at any given step).
+ */
+bool buffer_use[BUFSIZE];
+
+/* Proceed to a sub-subber switch is needed.
+ * Used in a periodical timer interrupt to fill and ship the current subbuffer
+ * to the reader so we can guarantee a steady flow. If a subbuffer is
+ * completely empty, do not switch.
+ * Also used as "finalize" operation to complete the last subbuffer after
+ * all writers have finished so the last subbuffer can be read by the reader.
+ */
+proctype switcher()
+{
+ byte prev_off, new_off, tmp_commit;
+ byte size;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ size = SUBBUF_SIZE - (prev_off % SUBBUF_SIE);
+ new_off = prev_off + size;
+ if
+ :: (new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR)
+ || size == SUBBUF_SIZE ->
+ refcount = refcount - 1;
+ goto not_needed;
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ }
+
+ atomic {
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ refcount = refcount - 1;
+ }
+not_needed:
+ skip;
+}
+
+/* tracer
+ * Writes 1 byte of information in the buffer at the current
+ * "write_off" position and then increment the commit_count of the sub-buffer
+ * the information has been written to.
+ */
+proctype tracer()
+{
+ byte size = 1;
+ byte prev_off, new_off, tmp_commit;
+ byte i, j;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ new_off = prev_off + size;
+ }
+ atomic {
+ if
+ :: new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR ->
+ goto lost
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ i = 0;
+ do
+ :: i < size ->
+ assert(buffer_use[(prev_off + i) % BUFSIZE] == 0);
+ buffer_use[(prev_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= size -> break
+ od;
+ }
+
+ /* writing to buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < size ->
+ buffer_use[(prev_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= size -> break
+ od;
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ }
+ atomic {
+ goto end;
+lost:
+ events_lost++;
+end:
+ refcount = refcount - 1;
+ }
+}
+
+/* reader
+ * Read the information sub-buffer per sub-buffer when available.
+ *
+ * Reads the information as soon as it is ready, or may be delayed by
+ * an asynchronous delivery. Being modeled as a process insures all cases
+ * (scheduled very quickly or very late, causing event loss) are covered.
+ * Only one reader per buffer (normally ensured by a mutex). This is modeled
+ * by using a single reader process.
+ */
+proctype reader()
+{
+ byte i, j;
+
+ do
+ :: (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) > 0
+ && (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) < HALF_UCHAR
+ && (commit_count[(read_off % BUFSIZE) / SUBBUF_SIZE]
+ - SUBBUF_SIZE - (((read_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS)
+ == 0) ->
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ assert(buffer_use[(read_off + i) % BUFSIZE] == 0);
+ buffer_use[(read_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ }
+
+ /* reading from buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ buffer_use[(read_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ read_off = read_off + SUBBUF_SIZE;
+ }
+ :: read_off >= (NUMPROCS - events_lost) -> break;
+ od;
+}
+
+/* Waits for all tracer and switcher processes to finish before finalizing
+ * the buffer. Only after that will the reader be allowed to read the
+ * last subbuffer.
+ */
+proctype cleaner()
+{
+ atomic {
+ do
+ :: refcount == 0 ->
+ refcount = refcount + 1;
+ run switcher(); /* Finalize the last sub-buffer so it can be read. */
+ break;
+ od;
+ }
+}
+
+init {
+ byte i = 0;
+ byte j = 0;
+ byte sum = 0;
+ byte commit_sum = 0;
+
+ atomic {
+ i = 0;
+ do
+ :: i < NR_SUBBUFS ->
+ commit_count[i] = 0;
+ i++
+ :: i >= NR_SUBBUFS -> break
+ od;
+ i = 0;
+ do
+ :: i < BUFSIZE ->
+ buffer_use[i] = 0;
+ i++
+ :: i >= BUFSIZE -> break
+ od;
+ run reader();
+ run cleaner();
+ i = 0;
+ do
+ :: i < NUMPROCS ->
+ refcount = refcount + 1;
+ run tracer();
+ i++
+ :: i >= NUMPROCS -> break
+ od;
+ i = 0;
+ do
+ :: i < NUMSWITCH ->
+ refcount = refcount + 1;
+ run switcher();
+ i++
+ :: i >= NUMSWITCH -> break
+ od;
+ }
+
+ /* Assertions.
+ */
+ atomic {
+ /* The writer head must always be superior or equal to the reader head.
+ */
+ /*assert(write_off - read_off >= 0 && write_off - read_off < HALF_UCHAR);*/
+ j = 0;
+ commit_sum = 0;
+ do
+ :: j < NR_SUBBUFS ->
+ commit_sum = commit_sum + commit_count[j];
+ j++
+ :: j >= NR_SUBBUFS -> break
+ od;
+ /* The sum of all subbuffer commit counts must always be lower or equal
+ * to the writer head, because space must be reserved before it is
+ * written to and then committed.
+ */
+ assert(write_off - commit_sum >= 0 && write_off - commit_sum < HALF_UCHAR);
+
+ /* If we have less writers than the buffer space available, we should
+ * not loose events
+ */
+ assert(NUMPROCS + NUMSWITCH > BUFSIZE || events_lost == 0);
+ }
+}
+
--- /dev/null
+/* LTTng ltt-tracer.c atomic lockless buffering scheme Promela model v2
+ * Created for the Spin validator.
+ * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ * October 2008
+
+ * TODO : create test cases that will generate an overflow on the offset and
+ * counter type. Counter types smaller than a byte should be used.
+
+ * Promela only has unsigned char, no signed char.
+ * Because detection of difference < 0 depends on a signed type, but we want
+ * compactness, check also for the values being higher than half of the unsigned
+ * char range (and consider them negative). The model, by design, does not use
+ * offsets or counts higher than 127 because we would then have to use a larger
+ * type (short or int).
+ */
+#define HALF_UCHAR (255/2)
+
+/* NUMPROCS 4 : causes event loss with some reader timings.
+ * e.g. 3 events, 1 switch, 1 event (lost, buffer full), read 1 subbuffer
+ */
+#define NUMPROCS 4
+
+/* NUMPROCS 3 : does not cause event loss because buffers are big enough.
+ * #define NUMPROCS 3
+ * e.g. 3 events, 1 switch, read 1 subbuffer
+ */
+
+#define NUMSWITCH 1
+#define BUFSIZE 4
+#define NR_SUBBUFS 2
+#define SUBBUF_SIZE (BUFSIZE / NR_SUBBUFS)
+
+/* <formal_verif> */
+byte commit_sum = 0;
+/* </formal_verif> */
+
+/* Writer counters
+*/
+byte write_off = 0;
+byte commit_count[NR_SUBBUFS];
+
+/* Reader counters
+*/
+byte read_off = 0;
+
+byte events_lost = 0;
+byte refcount = 0;
+
+bool deliver = 0;
+
+/* buffer slot in-use bit. Detects racy use (more than a single process
+ * accessing a slot at any given step).
+ */
+bool buffer_use[BUFSIZE];
+
+/* Proceed to a sub-subber switch is needed.
+ * Used in a periodical timer interrupt to fill and ship the current subbuffer
+ * to the reader so we can guarantee a steady flow. If a subbuffer is
+ * completely empty, do not switch.
+ * Also used as "finalize" operation to complete the last subbuffer after
+ * all writers have finished so the last subbuffer can be read by the reader.
+ */
+proctype switcher()
+{
+ byte prev_off, new_off, tmp_commit;
+ byte size;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ size = SUBBUF_SIZE - (prev_off % SUBBUF_SIZE);
+ new_off = prev_off + size;
+ if
+ :: (new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR)
+ || size == SUBBUF_SIZE ->
+ refcount = refcount - 1;
+ goto not_needed;
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ }
+
+ atomic {
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ /* <formal_verif> */
+ commit_sum = commit_sum - commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE]
+ + tmp_commit;
+ /* </formal_verif> */
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ refcount = refcount - 1;
+ }
+not_needed:
+ skip;
+}
+
+/* tracer
+ * Writes 1 byte of information in the buffer at the current
+ * "write_off" position and then increment the commit_count of the sub-buffer
+ * the information has been written to.
+ */
+proctype tracer()
+{
+ byte size = 1;
+ byte prev_off, new_off, tmp_commit;
+ byte i, j;
+
+cmpxchg_loop:
+ atomic {
+ prev_off = write_off;
+ new_off = prev_off + size;
+ }
+ atomic {
+ if
+ :: new_off - read_off > BUFSIZE && new_off - read_off < HALF_UCHAR ->
+ goto lost
+ :: else -> skip
+ fi;
+ }
+ atomic {
+ if
+ :: prev_off != write_off -> goto cmpxchg_loop
+ :: else -> write_off = new_off;
+ fi;
+ i = 0;
+ do
+ :: i < size ->
+ assert(buffer_use[(prev_off + i) % BUFSIZE] == 0);
+ buffer_use[(prev_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= size -> break
+ od;
+ }
+
+ /* writing to buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < size ->
+ buffer_use[(prev_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= size -> break
+ od;
+ tmp_commit = commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] + size;
+ commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE] = tmp_commit;
+ /* <formal_verif> */
+ commit_sum = commit_sum - commit_count[(prev_off % BUFSIZE) / SUBBUF_SIZE]
+ + tmp_commit;
+ /* </formal_verif> */
+ if
+ :: (((prev_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS) + SUBBUF_SIZE -
+ tmp_commit
+ -> deliver = 1
+ :: else
+ -> skip
+ fi;
+ }
+ atomic {
+ goto end;
+lost:
+ events_lost++;
+end:
+ refcount = refcount - 1;
+ }
+}
+
+/* reader
+ * Read the information sub-buffer per sub-buffer when available.
+ *
+ * Reads the information as soon as it is ready, or may be delayed by
+ * an asynchronous delivery. Being modeled as a process insures all cases
+ * (scheduled very quickly or very late, causing event loss) are covered.
+ * Only one reader per buffer (normally ensured by a mutex). This is modeled
+ * by using a single reader process.
+ */
+proctype reader()
+{
+ byte i, j;
+
+ do
+ :: (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) > 0
+ && (write_off / SUBBUF_SIZE) - (read_off / SUBBUF_SIZE) < HALF_UCHAR
+ && (commit_count[(read_off % BUFSIZE) / SUBBUF_SIZE]
+ - SUBBUF_SIZE - (((read_off / BUFSIZE) * BUFSIZE) / NR_SUBBUFS)
+ == 0) ->
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ assert(buffer_use[(read_off + i) % BUFSIZE] == 0);
+ buffer_use[(read_off + i) % BUFSIZE] = 1;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ }
+
+ /* reading from buffer...
+ */
+
+ atomic {
+ i = 0;
+ do
+ :: i < SUBBUF_SIZE ->
+ buffer_use[(read_off + i) % BUFSIZE] = 0;
+ i++
+ :: i >= SUBBUF_SIZE -> break
+ od;
+ read_off = read_off + SUBBUF_SIZE;
+ }
+ :: read_off >= (NUMPROCS - events_lost) -> break;
+ od;
+}
+
+/* Waits for all tracer and switcher processes to finish before finalizing
+ * the buffer. Only after that will the reader be allowed to read the
+ * last subbuffer.
+ */
+proctype cleaner()
+{
+ atomic {
+ do
+ :: refcount == 0 ->
+ refcount = refcount + 1;
+ run switcher(); /* Finalize the last sub-buffer so it can be read. */
+ break;
+ od;
+ }
+}
+
+init {
+ byte i = 0;
+ byte j = 0;
+ byte sum = 0;
+
+ atomic {
+ i = 0;
+ do
+ :: i < NR_SUBBUFS ->
+ commit_count[i] = 0;
+ i++
+ :: i >= NR_SUBBUFS -> break
+ od;
+ i = 0;
+ do
+ :: i < BUFSIZE ->
+ buffer_use[i] = 0;
+ i++
+ :: i >= BUFSIZE -> break
+ od;
+ run reader();
+ run cleaner();
+ i = 0;
+ do
+ :: i < NUMPROCS ->
+ refcount = refcount + 1;
+ run tracer();
+ i++
+ :: i >= NUMPROCS -> break
+ od;
+ i = 0;
+ do
+ :: i < NUMSWITCH ->
+ refcount = refcount + 1;
+ run switcher();
+ i++
+ :: i >= NUMSWITCH -> break
+ od;
+ }
+
+ /* Assertions.
+ */
+ atomic {
+ /* The writer head must always be superior or equal to the reader head.
+ */
+
+ /* assert(write_off - read_off >= 0 && write_off - read_off < HALF_UCHAR);
+ */
+
+ /*
+ j = 0;
+ commit_sum = 0;
+ do
+ :: j < NR_SUBBUFS ->
+ commit_sum = commit_sum + commit_count[j];
+ j++
+ :: j >= NR_SUBBUFS -> break
+ od;
+ */
+
+ /* The sum of all subbuffer commit counts must always be lower or equal
+ * to the writer head, because space must be reserved before it is
+ * written to and then committed.
+ */
+ /*
+ assert(write_off - commit_sum >= 0 && write_off - commit_sum < HALF_UCHAR);
+ */
+ /* If we have less writers than the buffer space available, we should
+ * not loose events
+ */
+ assert(NUMPROCS + NUMSWITCH > BUFSIZE || events_lost == 0);
+ }
+}
+
--- /dev/null
+buffer_large_enough -> ([](!have_events_lost))
--- /dev/null
+[] (rd_wr_wr_off1 && rd_wr_wr_off2)