Skip to content

Commit 02e3577

Browse files
committed
Safe callback mechanism to give dependent packages a normal racket environment.
1 parent 4ca7b2f commit 02e3577

3 files changed

Lines changed: 89 additions & 0 deletions

File tree

‎Makefile.rkt‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#lang racket
2+
3+
(require racket-makefile
4+
package-zipper
5+
)
6+
7+
8+
(target all
9+
(displayln "use (make clean) or (make package)")
10+
)
11+
12+
(target clean
13+
(for-each (λ (f) (displayln f) (rm-f f)) (list-files "libgit2" #px"([.]bak|~)$" #:recursive #t))
14+
(for-each (λ (d) (displayln d) (rm-rf d)) (list-dirs "libgit2" #px"(compiled|doc)$" #:recursive #t))
15+
(for-each (λ (f) (displayln f) (rm-f f)) (list-files "libgit2/scribblings" #px"[.](css|js|html)$"))
16+
)
17+
18+
(target package
19+
(deps clean)
20+
(zip-package))
21+

‎libgit2/include/remote.rkt‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#lang racket
22

33
(require ffi/unsafe
4+
ffi/unsafe/os-async-channel
45
(only-in "net.rkt"
56
_git_direction
67
_git_remote_head)
@@ -29,6 +30,24 @@
2930
GIT_REMOTE_COMPLETION_INDEXING
3031
GIT_REMOTE_COMPLETION_ERROR)))
3132

33+
;; Blocking remote callouts allow other Racket threads to run while libgit2 is
34+
;; doing network/pack work. Racket requires callbacks entered from such a
35+
;; callout to have a non-#f #:async-apply. Queue callback thunks to an ordinary
36+
;; Racket thread so callback bodies may safely perform normal Racket work.
37+
(define remote-callback-channel (make-os-async-channel))
38+
39+
(define remote-callback-dispatch-thread
40+
(thread
41+
(lambda ()
42+
(let loop ()
43+
(define thunk (sync remote-callback-channel))
44+
(thunk)
45+
(loop)))))
46+
47+
(define (remote-callback-async-apply thunk)
48+
;; os-async-channel-put is valid in atomic mode and from an OS thread.
49+
(os-async-channel-put remote-callback-channel thunk))
50+
3251
;; libgit2 can retain all callbacks in this structure for the lifetime of a
3352
;; remote transport. Use an explicit #:keep hook so the generated callback
3453
;; values can be tied to the git_remote lifetime instead of only to the
@@ -43,6 +62,7 @@
4362

4463
(define _git_remote_credential_acquire_cb
4564
(_fun #:keep keep-current-callback!
65+
#:async-apply remote-callback-async-apply
4666
(_cpointer _git_credential) _string _string _uint _pointer -> _int))
4767

4868
(define _git_remote_certificate_check_cb
@@ -51,6 +71,7 @@
5171

5272
(define _git_remote_transfer_progress_cb
5373
(_fun #:keep keep-current-callback!
74+
#:async-apply remote-callback-async-apply
5475
_git_transfer_progress-pointer _pointer -> _int))
5576

5677
(define _git_remote_update_tips_cb
@@ -59,10 +80,12 @@
5980

6081
(define _git_remote_pack_progress_cb
6182
(_fun #:keep keep-current-callback!
83+
#:async-apply remote-callback-async-apply
6284
_int _uint32 _uint32 _pointer -> _int))
6385

6486
(define _git_push_transfer_progress
6587
(_fun #:keep keep-current-callback!
88+
#:async-apply remote-callback-async-apply
6689
_uint _uint _size _pointer -> _int))
6790

6891
(define-cstruct _git_push_update
@@ -395,6 +418,18 @@
395418
_string
396419
-> _int))
397420

421+
;; Blocking variant for callers that need other Racket threads to remain
422+
;; schedulable while libgit2 fetches. Callbacks used with this variant must
423+
;; have a non-#f #:async-apply.
424+
(define-libgit2 git_remote_fetch/blocking
425+
(_fun #:blocking? #t
426+
_git_remote
427+
(_or-null _git_strarray-pointer)
428+
_git_fetch_opts-pointer/null
429+
_string
430+
-> (_git_error_code/check))
431+
#:c-id git_remote_fetch)
432+
398433
(define-libgit2 git_remote_get_fetch_refspecs
399434
(_fun [lst : (_git_strarray-pointer/alloc)]
400435
_git_remote
@@ -454,6 +489,15 @@
454489
_git_push_opts-pointer/null
455490
-> _int))
456491

492+
;; Blocking variant; see git_remote_fetch/blocking.
493+
(define-libgit2 git_remote_push/blocking
494+
(_fun #:blocking? #t
495+
_git_remote
496+
(_or-null _git_strarray-pointer)
497+
_git_push_opts-pointer/null
498+
-> (_git_error_code/check))
499+
#:c-id git_remote_push)
500+
457501
(define-libgit2 git_remote_pushurl
458502
(_fun _git_remote -> _string))
459503

@@ -529,6 +573,12 @@
529573
(retain-owner-callbacks-for-remote! remote opts)
530574
(raw remote refspecs opts reflog-message))))
531575

576+
(let ([raw git_remote_fetch/blocking])
577+
(set! git_remote_fetch/blocking
578+
(lambda (remote refspecs opts reflog-message)
579+
(retain-owner-callbacks-for-remote! remote opts)
580+
(raw remote refspecs opts reflog-message))))
581+
532582
(let ([raw git_remote_prune])
533583
(set! git_remote_prune
534584
(lambda (remote callbacks)
@@ -541,6 +591,12 @@
541591
(retain-owner-callbacks-for-remote! remote opts)
542592
(raw remote refspecs opts))))
543593

594+
(let ([raw git_remote_push/blocking])
595+
(set! git_remote_push/blocking
596+
(lambda (remote refspecs opts)
597+
(retain-owner-callbacks-for-remote! remote opts)
598+
(raw remote refspecs opts))))
599+
544600
(let ([raw git_remote_update_tips])
545601
(set! git_remote_update_tips
546602
(lambda (remote callbacks update-fetchhead download-tags reflog-message)

‎libgit2/test/test-remote-signatures.rkt‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,18 @@
4646
(lambda ()
4747
(git_remote_fetch remote #f #f #f)))
4848

49+
;; Blocking variants use the same C entry points but allow a caller to
50+
;; execute them in a parallel Racket thread while callbacks are safely
51+
;; dispatched through #:async-apply.
52+
(check-exn
53+
exn:fail?
54+
(lambda ()
55+
(git_remote_fetch/blocking remote #f #f #f)))
56+
(check-exn
57+
exn:fail?
58+
(lambda ()
59+
(git_remote_push/blocking remote #f #f)))
60+
4961
;; Fetch refspec output is owned by the caller and must be consumed just
5062
;; like the push-refspec output.
5163
(check-equal?

0 commit comments

Comments
 (0)