rendezvous.scm 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. ;; Rendezvous combinators
  2. ;; There's considerable potential for more abstraction in the protocol
  3. ;; for primitive rendezvous. --Mike
  4. (define-record-type prim-rv :prim-rv
  5. (really-make-prim-rv wrap-proc poll-thunk)
  6. prim-rv?
  7. (wrap-proc prim-rv-wrap-proc)
  8. ;; This is a thunk which checks whether the rendezvous is currently
  9. ;; enabled or not; if it is, the thunk must return an ENABLED
  10. ;; record, if it isn't, a BLOCKED record. It must perform only
  11. ;; provisional operations.
  12. (poll-thunk prim-rv-poll-thunk))
  13. (define (make-prim-rv poll-thunk)
  14. (really-make-prim-rv identity poll-thunk))
  15. (define-record-type prim-rv :enabled
  16. (make-enabled priority do-proc)
  17. enabled?
  18. (priority enabled-priority)
  19. ;; DO-PROC takes as its argument a queue of thread cells where it's
  20. ;; supposed to enqueue threads to be woken up upon commit. It must
  21. ;; perform only provisional operations.
  22. (do-proc enabled-do-proc))
  23. (define-record-type blocked :blocked
  24. (make-blocked proc)
  25. blocked?
  26. ;; PROC is a procedure with three arguments:
  27. ;; a TRANS-ID, a CLEANUP-PROC, and a WRAP-PROC.
  28. ;; TRANS-ID is the transaction ID of the blocked thread. The
  29. ;; TRANS-ID should be fed, when it's woken up, a pair consisting of
  30. ;; a return value and a wrap-proc procedure.
  31. ;; CLEANUP-PROC is a procedure which takes a thread queue as an
  32. ;; argument; it can enqueue thread cells whose threads it wants
  33. ;; woken up. This procedure is called from an operation which
  34. ;; enables this rendezvous. It must perform only provisional state
  35. ;; mutations.
  36. ;; WRAP-PROC is the complete, composed-together chain of WRAP
  37. ;; procedures of the event.
  38. (proc blocked-proc))
  39. (define-record-type base :base
  40. (really-make-base prim-rvs)
  41. base?
  42. (prim-rvs base-prim-rvs))
  43. (define (make-base poll-thunk)
  44. (really-make-base (list (make-prim-rv poll-thunk))))
  45. (define-record-type choose :choose
  46. (make-choose rvs)
  47. choose?
  48. (rvs choose-rvs))
  49. (define-record-type guard :guard
  50. (make-guard thunk)
  51. guard?
  52. (thunk guard-thunk))
  53. (define-record-type with-nack :with-nack
  54. (make-nack proc)
  55. nack?
  56. (proc nack-proc))
  57. ;; Condition variables for internal use
  58. ;; These are essentially for placeholder-like rendezvous, only they
  59. ;; don't communicate a value.
  60. (define-synchronized-record-type cvar :cvar
  61. (really-make-cvar state)
  62. cvar?
  63. ;; this can be one of the two below:
  64. (state cvar-state set-cvar-state!))
  65. (define-synchronized-record-type cvar-unset-state :cvar-unset-state
  66. (make-cvar-unset-state blocked)
  67. cvar-unset-state?
  68. ;; this is a list of :CVAR-ITEM
  69. (blocked cvar-unset-state-blocked set-cvar-unset-state-blocked!))
  70. (define-record-type cvar-item :cvar-item
  71. (make-cvar-item trans-id cleanup-proc wrap-proc)
  72. cvar-item?
  73. (trans-id cvar-item-trans-id)
  74. (cleanup-proc cvar-item-cleanup-proc)
  75. (wrap-proc cvar-item-wrap-proc))
  76. (define-synchronized-record-type cvar-set-state :cvar-set-state
  77. (make-cvar-set-state priority)
  78. cvar-set-state?
  79. (priority cvar-set-state-priority set-cvar-set-state-priority!))
  80. (define (make-cvar)
  81. (really-make-cvar (make-cvar-unset-state '())))
  82. ;; Note that this happens during synchronization which is why the
  83. ;; QUEUE argument is there.
  84. (define (cvar-set! cvar queue)
  85. (let ((state (cvar-state cvar)))
  86. (cond
  87. ((cvar-unset-state? state)
  88. (for-each (lambda (cvar-item)
  89. (let ((trans-id (cvar-item-trans-id cvar-item)))
  90. (if (not (trans-id-cancelled? trans-id))
  91. (begin
  92. ((cvar-item-cleanup-proc cvar-item) queue)
  93. (trans-id-set-value! trans-id
  94. (cons (unspecific)
  95. (cvar-item-wrap-proc cvar-item)))
  96. (enqueue! queue (trans-id-thread-cell trans-id))))))
  97. (cvar-unset-state-blocked state))
  98. (set-cvar-state! cvar (make-cvar-set-state 1)))
  99. (else
  100. (error "cvar already set")))))
  101. (define (cvar-get-rv cvar)
  102. (make-base
  103. (lambda ()
  104. (let ((state (cvar-state cvar)))
  105. (cond
  106. ((cvar-set-state? state)
  107. (let ((priority (cvar-set-state-priority state)))
  108. (set-cvar-set-state-priority! state (+ 1 priority))
  109. (make-enabled priority
  110. (lambda (queue)
  111. (set-cvar-set-state-priority! state 1)
  112. (unspecific)))))
  113. (else
  114. (make-blocked
  115. (lambda (trans-id cleanup-proc wrap-proc)
  116. (set-cvar-unset-state-blocked!
  117. state
  118. (cons (make-cvar-item trans-id cleanup-proc wrap-proc)
  119. (cvar-unset-state-blocked state)))))))))))
  120. (define (always-rv value)
  121. (make-base
  122. (lambda ()
  123. (make-enabled -1
  124. (lambda (queue)
  125. value)))))
  126. (define never-rv (really-make-base '()))
  127. (define (guard thunk)
  128. (make-guard thunk))
  129. (define (with-nack proc)
  130. (make-nack proc))
  131. (define (gather-prim-rvs rev-rvs prim-rvs)
  132. (cond
  133. ((null? rev-rvs) (really-make-base prim-rvs))
  134. ((not (base? (car rev-rvs)))
  135. (if (null? prim-rvs)
  136. (gather rev-rvs '())
  137. (gather rev-rvs (list (really-make-base prim-rvs)))))
  138. ;; (car rev-rvs) is base
  139. (else
  140. (gather-prim-rvs (cdr rev-rvs)
  141. (append (base-prim-rvs (car rev-rvs))
  142. prim-rvs)))))
  143. (define (gather rev-rvs rvs)
  144. (cond
  145. ((not (null? rev-rvs))
  146. (let ((rv (car rev-rvs)))
  147. (cond
  148. ((choose? rv)
  149. (gather (cdr rev-rvs) (append (choose-rvs rv) rvs)))
  150. ((and (base? rv)
  151. (not (null? rvs))
  152. (base? (car rvs)))
  153. (gather (cdr rev-rvs)
  154. (cons (really-make-base (append (base-prim-rvs rv)
  155. (base-prim-rvs (car rvs))))
  156. (cdr rvs))))
  157. (else
  158. (gather (cdr rev-rvs) (cons rv rvs))))))
  159. ((null? (cdr rvs)) (car rvs))
  160. (else (make-choose rvs))))
  161. (define (choose . rvs)
  162. (gather-prim-rvs (reverse rvs) '()))
  163. (define (compose f g)
  164. (lambda (x)
  165. (f (g x))))
  166. (define (wrap-prim-rv prim-rv wrap-proc)
  167. (really-make-prim-rv (compose wrap-proc
  168. (prim-rv-wrap-proc prim-rv))
  169. (prim-rv-poll-thunk prim-rv)))
  170. (define (wrap rv wrap-proc)
  171. (cond
  172. ((base? rv)
  173. (really-make-base (map (lambda (prim-rv)
  174. (wrap-prim-rv prim-rv wrap-proc))
  175. (base-prim-rvs rv))))
  176. ((choose? rv)
  177. (make-choose (map (lambda (rv)
  178. (wrap rv wrap-proc))
  179. (choose-rvs rv))))
  180. ((guard? rv)
  181. (make-guard (lambda ()
  182. (wrap ((guard-thunk rv)) wrap-proc))))
  183. ((nack? rv)
  184. (make-nack (lambda (nack-rv)
  185. (wrap ((nack-proc rv) nack-rv) wrap-proc))))))
  186. (define-record-type base-group :base-group
  187. (really-make-base-group prim-rvs)
  188. base-group?
  189. (prim-rvs base-group-prim-rvs))
  190. (define-record-discloser :base-group
  191. (lambda (base-group)
  192. (cons 'base-group
  193. (base-group-prim-rvs base-group))))
  194. (define-record-type choose-group :choose-group
  195. (make-choose-group groups)
  196. choose-group?
  197. (groups choose-group-groups))
  198. (define-record-discloser :choose-group
  199. (lambda (choose-group)
  200. (cons 'choose-group
  201. (choose-group-groups choose-group))))
  202. (define-record-type nack-group :nack-group
  203. (make-nack-group cvar group)
  204. nack-group?
  205. (cvar nack-group-cvar)
  206. (group nack-group-group))
  207. (define-record-discloser :nack-group
  208. (lambda (nack-group)
  209. (list 'nack-group
  210. (nack-group-group nack-group))))
  211. (define (force-rv rv)
  212. (cond
  213. ((base? rv)
  214. (really-make-base-group (base-prim-rvs rv)))
  215. (else
  216. (really-force-rv rv))))
  217. (define (force-prim-rvs rvs prim-rvs)
  218. (if (null? rvs)
  219. (really-make-base-group prim-rvs)
  220. (let* ((rv (car rvs))
  221. (group (really-force-rv rv)))
  222. (cond
  223. ((base-group? group)
  224. (force-prim-rvs (cdr rvs)
  225. (append (base-group-prim-rvs group)
  226. prim-rvs)))
  227. ((choose-group? group)
  228. (force-rvs (cdr rvs)
  229. (append (choose-group-groups group)
  230. (list (really-make-base-group prim-rvs)))))
  231. (else
  232. (force-rvs (cdr rvs)
  233. (list group (really-make-base-group prim-rvs))))))))
  234. (define (force-rvs rvs groups)
  235. (cond
  236. ((not (null? rvs))
  237. (let* ((rv (car rvs))
  238. (group (really-force-rv rv)))
  239. (cond
  240. ((and (base-group? group)
  241. (not (null? groups))
  242. (base-group? (car groups)))
  243. (force-rvs (cdr rvs)
  244. (cons (really-make-base-group
  245. (append (base-group-prim-rvs group)
  246. (base-group-prim-rvs (car groups))))
  247. (cdr groups))))
  248. ((choose-group? group)
  249. (force-rvs (cdr rvs)
  250. (append (choose-group-groups group)
  251. groups)))
  252. (else
  253. (force-rvs (cdr rvs) (cons group groups))))))
  254. ((null? (cdr groups))
  255. (car groups))
  256. (else
  257. (make-choose-group groups))))
  258. ;; this corresponds to force' in Reppy's implementation
  259. (define (really-force-rv rv)
  260. (cond
  261. ((guard? rv)
  262. (really-force-rv ((guard-thunk rv))))
  263. ((nack? rv)
  264. (let ((cvar (make-cvar)))
  265. (make-nack-group cvar
  266. (really-force-rv
  267. ((nack-proc rv)
  268. (cvar-get-rv cvar))))))
  269. ((base? rv)
  270. (really-make-base-group (base-prim-rvs rv)))
  271. ((choose? rv)
  272. (force-prim-rvs (choose-rvs rv) '()))
  273. (else
  274. (call-error "not a rendezvous" rv))))
  275. (define (sync-prim-rv prim-rv)
  276. (let ((poll-thunk (prim-rv-poll-thunk prim-rv))
  277. (wrap-proc (prim-rv-wrap-proc prim-rv)))
  278. (let ((old (current-proposal)))
  279. (let lose ()
  280. (set-current-proposal! (make-proposal))
  281. (let ((status ((prim-rv-poll-thunk prim-rv))))
  282. (cond
  283. ((enabled? status)
  284. (let* ((queue (make-queue))
  285. (value ((enabled-do-proc status) queue)))
  286. (if (maybe-commit-and-make-ready queue)
  287. (begin
  288. (set-current-proposal! old)
  289. (wrap-proc value))
  290. (lose))))
  291. ((blocked? status)
  292. (let ((trans-id (make-trans-id)))
  293. ((blocked-proc status) trans-id values wrap-proc)
  294. (cond
  295. ((maybe-commit-and-trans-id-value trans-id)
  296. => (lambda (pair)
  297. (set-current-proposal! old)
  298. ((cdr pair) (car pair))))
  299. (else
  300. (lose)))))))))))
  301. (define (select-do-proc priority+do-list n)
  302. (cond
  303. ((null? (cdr priority+do-list))
  304. (cdar priority+do-list))
  305. (else
  306. (let ((priority
  307. (lambda (p)
  308. (if (= p -1)
  309. n
  310. p))))
  311. (let max ((rest priority+do-list)
  312. (maximum 0)
  313. (k 0) ; (length do-procs)
  314. (do-list '())) ; #### list of pairs do-proc * wrap-proc
  315. (cond
  316. ((not (null? rest))
  317. (let* ((pair (car rest))
  318. (p (priority (car pair)))
  319. (stuff (cdr pair)))
  320. (cond
  321. ((> p maximum)
  322. (max (cdr rest) p 1 (list stuff)))
  323. ((= p maximum)
  324. (max (cdr rest) maximum (+ 1 k) (cons stuff do-list)))
  325. (else
  326. (max (cdr rest) maximum k do-list)))))
  327. ((null? (cdr do-list))
  328. (car do-list))
  329. (else
  330. ;; List.nth(doFns, random k)
  331. (car do-list))))))))
  332. (define (block)
  333. (with-new-proposal (lose)
  334. (maybe-commit-and-block (make-cell (current-thread)))))
  335. (define (sync-prim-rvs prim-rvs)
  336. (cond
  337. ((null? prim-rvs)
  338. (block))
  339. ((null? (cdr prim-rvs)) (sync-prim-rv (car prim-rvs)))
  340. (else
  341. (let ((old (current-proposal)))
  342. (let lose ()
  343. (define (find-enabled prim-rvs block-procs wrap-procs)
  344. (if (null? prim-rvs)
  345. (let ((trans-id (make-trans-id)))
  346. (for-each (lambda (block-proc wrap-proc)
  347. (block-proc trans-id values wrap-proc))
  348. block-procs wrap-procs)
  349. (cond
  350. ((maybe-commit-and-trans-id-value trans-id)
  351. => (lambda (pair)
  352. (set-current-proposal! old)
  353. ((cdr pair) (car pair))))
  354. (else
  355. (lose))))
  356. (let* ((prim-rv (car prim-rvs))
  357. (poll-thunk (prim-rv-poll-thunk prim-rv))
  358. (wrap-proc (prim-rv-wrap-proc prim-rv))
  359. (status (poll-thunk)))
  360. (cond
  361. ((enabled? status)
  362. (handle-enabled (cdr prim-rvs)
  363. (list
  364. (cons (enabled-priority status)
  365. (cons (enabled-do-proc status)
  366. wrap-proc)))
  367. 1))
  368. ((blocked? status)
  369. (find-enabled (cdr prim-rvs)
  370. (cons (blocked-proc status)
  371. block-procs)
  372. (cons wrap-proc wrap-procs)))))))
  373. (define (handle-enabled prim-rvs priority+do-list priority)
  374. (if (null? prim-rvs)
  375. (let* ((stuff (select-do-proc priority+do-list priority))
  376. (do-proc (car stuff))
  377. (wrap-proc (cdr stuff))
  378. (queue (make-queue))
  379. (value (do-proc queue)))
  380. (if (maybe-commit-and-make-ready queue)
  381. (begin
  382. (set-current-proposal! old)
  383. (wrap-proc value))
  384. (lose)))
  385. (let* ((prim-rv (car prim-rvs))
  386. (poll-thunk (prim-rv-poll-thunk prim-rv))
  387. (wrap-proc (prim-rv-wrap-proc prim-rv))
  388. (status (poll-thunk)))
  389. (cond
  390. ((enabled? status)
  391. (handle-enabled (cdr prim-rvs)
  392. (cons (cons (enabled-priority status)
  393. (cons (enabled-do-proc status)
  394. wrap-proc))
  395. priority+do-list)
  396. (+ 1 priority)))
  397. (else
  398. (handle-enabled (cdr prim-rvs)
  399. priority+do-list
  400. priority))))))
  401. (set-current-proposal! (make-proposal))
  402. (find-enabled prim-rvs '() '()))))))
  403. (define (sync rv)
  404. (let ((group (force-rv rv)))
  405. (cond
  406. ((base-group? group)
  407. (sync-prim-rvs (base-group-prim-rvs group)))
  408. (else
  409. (sync-group group)))))
  410. (define-record-type ack-flag :ack-flag
  411. (really-make-ack-flag acked?)
  412. ack-flag?
  413. (acked? flag-acked? set-flag-acked?!))
  414. (define (make-ack-flag)
  415. (really-make-ack-flag #f))
  416. (define (ack-flag! ack-flag)
  417. (set-flag-acked?! ack-flag #t))
  418. (define-record-type flag-set :flag-set
  419. (make-flag-set cvar ack-flags)
  420. flag-set?
  421. (cvar flag-set-cvar)
  422. (ack-flags flag-set-ack-flags))
  423. (define (check-cvars! flag-sets queue)
  424. (for-each (lambda (flag-set)
  425. (check-cvar! flag-set queue))
  426. flag-sets))
  427. (define (check-cvar! flag-set queue)
  428. (let loop ((ack-flags (flag-set-ack-flags flag-set)))
  429. (cond
  430. ((null? ack-flags)
  431. (cvar-set! (flag-set-cvar flag-set) queue))
  432. ((flag-acked? (car ack-flags))
  433. (values))
  434. (else
  435. (loop (cdr ack-flags))))))
  436. ;; this corresponds to syncOnGrp from Reppy's code
  437. (define (sync-group group)
  438. (call-with-values
  439. (lambda () (collect-group group))
  440. really-sync-group))
  441. ;; This is analogous to SYNC-PRIM-RVS
  442. (define (really-sync-group prim-rv+ack-flag-list flag-sets)
  443. (let ((old (current-proposal)))
  444. (let lose ()
  445. (define (find-enabled prim-rv+ack-flag-list
  446. block-proc+ack-flag-list
  447. wrap-procs)
  448. (if (null? prim-rv+ack-flag-list)
  449. (let ((trans-id (make-trans-id)))
  450. (for-each (lambda (block-proc+ack-flag wrap-proc)
  451. (let ((block-proc (car block-proc+ack-flag))
  452. (ack-flag (cdr block-proc+ack-flag)))
  453. (block-proc trans-id
  454. (lambda (queue)
  455. (ack-flag! ack-flag)
  456. (check-cvars! flag-sets queue))
  457. wrap-proc)))
  458. block-proc+ack-flag-list wrap-procs)
  459. (cond
  460. ((maybe-commit-and-trans-id-value trans-id)
  461. => (lambda (pair)
  462. (set-current-proposal! old)
  463. ((cdr pair) (car pair))))
  464. (else
  465. (lose))))
  466. (let* ((prim-rv (caar prim-rv+ack-flag-list))
  467. (ack-flag (cdar prim-rv+ack-flag-list))
  468. (poll-thunk (prim-rv-poll-thunk prim-rv))
  469. (wrap-proc (prim-rv-wrap-proc prim-rv))
  470. (status (poll-thunk)))
  471. (cond
  472. ((enabled? status)
  473. (handle-enabled (cdr prim-rv+ack-flag-list)
  474. (list
  475. (cons (enabled-priority status)
  476. (cons (cons (enabled-do-proc status) ack-flag)
  477. wrap-proc)))
  478. 1))
  479. ((blocked? status)
  480. (find-enabled (cdr prim-rv+ack-flag-list)
  481. (cons (cons (blocked-proc status) ack-flag)
  482. block-proc+ack-flag-list)
  483. (cons wrap-proc wrap-procs)))))))
  484. (define (handle-enabled prim-rv+ack-flag-list priority+do-list priority)
  485. (if (null? prim-rv+ack-flag-list)
  486. (let* ((stuff (select-do-proc priority+do-list priority))
  487. (more-stuff (car stuff))
  488. (do-proc (car more-stuff))
  489. (ack-flag (cdr more-stuff))
  490. (wrap-proc (cdr stuff))
  491. (queue (make-queue)))
  492. (ack-flag! ack-flag)
  493. (check-cvars! flag-sets queue)
  494. (let ((value (do-proc queue)))
  495. (if (maybe-commit-and-make-ready queue)
  496. (begin
  497. (set-current-proposal! old)
  498. (wrap-proc value))
  499. (lose))))
  500. (let* ((prim-rv+ack-flag (car prim-rv+ack-flag-list))
  501. (prim-rv (car prim-rv+ack-flag))
  502. (ack-flag (cdr prim-rv+ack-flag))
  503. (poll-thunk (prim-rv-poll-thunk prim-rv))
  504. (wrap-proc (prim-rv-wrap-proc prim-rv))
  505. (status (poll-thunk)))
  506. (cond
  507. ((enabled? status)
  508. (handle-enabled (cdr prim-rv+ack-flag-list)
  509. (cons (cons (enabled-priority status)
  510. (cons (cons (enabled-do-proc status) ack-flag)
  511. wrap-proc))
  512. priority+do-list)
  513. (+ 1 priority)))
  514. (else
  515. (handle-enabled (cdr prim-rv+ack-flag-list)
  516. priority+do-list
  517. priority))))))
  518. (set-current-proposal! (make-proposal))
  519. (find-enabled prim-rv+ack-flag-list '() '()))))
  520. (define (collect-group group)
  521. (cond
  522. ((choose-group? group)
  523. (gather-choose-group group))
  524. (else
  525. (gather-wrapped group '() '()))))
  526. (define (gather-choose-group group)
  527. (let ((ack-flag (make-ack-flag)))
  528. (let gather ((group group)
  529. (prim-rv+ack-flag-list '())
  530. (flag-sets '()))
  531. (cond
  532. ((base-group? group)
  533. (let append ((prim-rvs (base-group-prim-rvs group))
  534. (prim-rv+ack-flag-list prim-rv+ack-flag-list))
  535. (if (null? prim-rvs)
  536. (values prim-rv+ack-flag-list flag-sets)
  537. (append (cdr prim-rvs)
  538. (cons (cons (car prim-rvs) ack-flag)
  539. prim-rv+ack-flag-list)))))
  540. ((choose-group? group)
  541. ;; fold-left
  542. (let loop ((groups (choose-group-groups group))
  543. (prim-rv+ack-flag-list prim-rv+ack-flag-list)
  544. (flag-sets flag-sets))
  545. (if (null? groups)
  546. (values prim-rv+ack-flag-list flag-sets)
  547. (call-with-values
  548. (lambda ()
  549. (gather (car groups)
  550. prim-rv+ack-flag-list
  551. flag-sets))
  552. (lambda (prim-rv+ack-flag-list flag-sets)
  553. (loop (cdr groups)
  554. prim-rv+ack-flag-list
  555. flag-sets))))))
  556. ((nack-group? group)
  557. (gather-wrapped group prim-rv+ack-flag-list flag-sets))))))
  558. (define (gather-wrapped group prim-rv+ack-flag-list flag-sets)
  559. (call-with-values
  560. (lambda ()
  561. (let gather ((group group)
  562. (prim-rv+ack-flag-list prim-rv+ack-flag-list)
  563. (all-flags '())
  564. (flag-sets flag-sets))
  565. (cond
  566. ((base-group? group)
  567. (let append ((prim-rvs (base-group-prim-rvs group))
  568. (prim-rv+ack-flag-list prim-rv+ack-flag-list)
  569. (all-flags all-flags))
  570. (if (null? prim-rvs)
  571. (values prim-rv+ack-flag-list
  572. all-flags
  573. flag-sets)
  574. (let ((ack-flag (make-ack-flag)))
  575. (append (cdr prim-rvs)
  576. (cons (cons (car prim-rvs) ack-flag)
  577. prim-rv+ack-flag-list)
  578. (cons ack-flag all-flags))))))
  579. ((choose-group? group)
  580. ;; fold-left
  581. (let loop ((groups (choose-group-groups group))
  582. (prim-rv+ack-flag-list prim-rv+ack-flag-list)
  583. (all-flags all-flags)
  584. (flag-sets flag-sets))
  585. (if (null? groups)
  586. (values prim-rv+ack-flag-list
  587. all-flags
  588. flag-sets)
  589. (call-with-values
  590. (lambda ()
  591. (gather (car groups)
  592. prim-rv+ack-flag-list
  593. all-flags
  594. flag-sets))
  595. (lambda (prim-rv+ack-flag-list all-flags flag-sets)
  596. (loop (cdr groups)
  597. prim-rv+ack-flag-list all-flags flag-sets))))))
  598. ((nack-group? group)
  599. (call-with-values
  600. (lambda ()
  601. (gather (nack-group-group group)
  602. prim-rv+ack-flag-list
  603. '()
  604. flag-sets))
  605. (lambda (prim-rv+ack-flag-list all-flags-new flag-sets)
  606. (values prim-rv+ack-flag-list
  607. (append all-flags-new all-flags)
  608. (cons (make-flag-set (nack-group-cvar group)
  609. all-flags-new)
  610. flag-sets))))))))
  611. (lambda (prim-rv+ack-flag-list all-flags flag-sets)
  612. (values prim-rv+ack-flag-list flag-sets))))
  613. (define (select . rvs)
  614. (sync (apply choose rvs)))