Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Mutex, Atom, Channel and Exhaustable Channel in stdlib/synch #1909

Open
wants to merge 52 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
5ca9772
stick to style
glyh Apr 6, 2024
a10aae3
reduce test delay, write more comprehensive test note
glyh Apr 6, 2024
b04d385
don't close a pipe twice
glyh Apr 6, 2024
22abdc3
fix syntax erro
glyh Apr 6, 2024
8aa830f
should error with double destroy
glyh Apr 6, 2024
dfb8819
fix: source synch.ysh
glyh Apr 6, 2024
07135a8
fix: try should wrap inner functions
glyh Apr 6, 2024
e52c1cd
fix testcase
glyh Apr 6, 2024
0f4640e
fix typos
glyh Apr 6, 2024
de8f0ae
implement channel
glyh Apr 7, 2024
008daad
note on blocking
glyh Apr 7, 2024
b203299
A shorter name for channel functions
glyh Apr 7, 2024
9297780
remove redundant space
glyh Apr 7, 2024
5484379
implement functions to test whether fd is opened
glyh Apr 7, 2024
bc8f63c
abstract out mutex from channel
glyh Apr 7, 2024
3b07921
fix func signature
glyh Apr 7, 2024
3d4576f
implement rwlock, backed by flock
glyh Apr 7, 2024
3543afe
add vim folds
glyh Apr 7, 2024
2dfb7ef
implement exhaustive channel
glyh Apr 7, 2024
6035fbe
remove redundant file
glyh Apr 7, 2024
aa6bc25
add rwlock test
glyh Apr 7, 2024
3566aa6
add test case for exh-channel
glyh Apr 7, 2024
99d5337
remove redundant promotion
glyh Apr 7, 2024
841c071
implement inc & dec in math
glyh Apr 7, 2024
6f79596
try to fix exhaustive channel
glyh Apr 7, 2024
655168b
note on proc obj
glyh Apr 7, 2024
5f4fa08
fix: read/write RW-Lock
glyh Apr 7, 2024
441babe
fix some syntax error
glyh Apr 7, 2024
68e903c
should use lockfile instead of lock fd to read the file
glyh Apr 7, 2024
7142fb2
add test for rwlock read&write
glyh Apr 7, 2024
259c1b3
typo
glyh Apr 7, 2024
bd5a8f6
fix exhaustable channel and underlying rwlock
glyh Apr 7, 2024
715e595
rename swap-f to swap-fn for rwlock
glyh Apr 7, 2024
665fe66
ensure lock is held when read/write/unlock
glyh Apr 7, 2024
08263af
correctly handle rw-lock permission
glyh Apr 7, 2024
29af63e
fix rw-lock destroy
glyh Apr 7, 2024
6505993
should destroy lock after use
glyh Apr 7, 2024
379297e
fix destroy logic
glyh Apr 7, 2024
16364b3
add some notes
glyh Apr 7, 2024
85eb607
more notes
glyh Apr 8, 2024
04e8877
prefers j8 instead of json for lossless information
glyh Apr 8, 2024
99b0ec7
more note
glyh Apr 9, 2024
d2882ae
refactor out stdlib/descriptor
glyh Apr 9, 2024
7fb7423
rename: stdlib/synch -> stdlib/sync
glyh Apr 9, 2024
fcd78e7
factor out stdlib/pipe
glyh Apr 9, 2024
c11fa8d
also factors pipemethods outof exhaustable channel
glyh Apr 9, 2024
e29fe23
add shebang and markers in stdlib/pipe
glyh Apr 9, 2024
05c898b
rename RWLock to Atom
glyh Apr 9, 2024
c421e44
implement blocked piping
glyh Apr 9, 2024
c334329
rename zero-delim-num-* to delim-num-*
glyh Apr 9, 2024
eb29383
implement blocked pipe
glyh Apr 9, 2024
b73ac92
pass interface as dict
glyh Apr 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 204 additions & 0 deletions spec/ysh-stdlib-sync.test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
# spec/ysh-stdlib-sync

## our_shell: ysh

#### fifo pipe double closes
source --builtin draft-sync.ysh

fifo-fd-new (&fd)
try {
fifo-fd-destroy (fd)
}
echo $_status
fifo-fd-destroy (fd)
## status: 1
## STDOUT:
0
## END

#### semaphore syncrhonizing async jobs
source --builtin draft-sync.ysh

sema-new (1, &s)
fork {
sleep 0.2
sema-down (s)
echo 1
}
fork {
sleep 0.4
sema-down (s)
echo 2
}
fork {
sleep 0.6
sema-down (s)
echo 3
}
sleep 0.8
echo 4
sema-up (s)
sleep 0.2
echo 5
sema-up (s)
sema-destroy (s)
## STDOUT:
1
4
2
5
3
## END

#### semaphore init with 3, async up once and multiple down
source --builtin draft-sync.ysh

sema-new (3, &s)
fork {
sleep 0.2
sema-up (s)
}
sema-down (s)
sema-down (s)
sema-down (s)
sema-down (s)
echo yes
## STDOUT:
yes
## END

#### channel reads and writes
source --builtin draft-sync.ysh

channel-new (&ch)

for i in (0..4) {
fork {
for j in (0..4) {
echo $j | channel-in (ch)
}
}
}

var sum = 0
for i in (0..16) {
var cur = $(channel-out (ch)) => int()
setvar sum += cur
}

echo $sum
channel-destroy (ch)
## STDOUT:
24
## END

#### channel but backed by blocked pipe
source --builtin draft-sync.ysh

channel-new (&ch, __pipe_methods_blocked_netstring(4))

var sent = "I-am-a-pretty-damn-long-string-that-need-to-be-blocked"

fork {
write -n -- "$sent" | channel-in (ch)
}

var received = $(channel-out (ch))
echo $[received === sent]
## STDOUT:
true
## END

#### RWLock multiple shared lock and free, one exclusive lock
source --builtin draft-sync.ysh

atom-new (&lk)

fork {
atom-lock-shared (lk)
echo 1
sleep 0.3
atom-unlock (lk)
}
for _ in (0..3) {
fork {
sleep 0.1
atom-lock-shared (lk)
echo 2
sleep 0.2
atom-unlock (lk)
}
}
sleep 0.1
atom-lock-exclusive (lk)
echo 3
atom-unlock (lk)
atom-destroy (lk)
## STDOUT:
1
2
2
2
3
## END

#### Reading and writing atom
source --builtin draft-sync.ysh

atom-new (&l)
fork {
atom-lock-exclusive (l)
write -n 'w' | atom-write-in (l)
atom-unlock (l)
}
sleep 0.1

for _ in (0..3) {
fork {
atom-lock-shared (l)
atom-read-out (l)
sleep 0.2
atom-read-out (l)
atom-unlock (l)
}
}
sleep 0.1
write -n y
wait
atom-destroy (l)
write
## STDOUT:
wwwywww
## END

#### Produce many value and exhaust the channel, and then reuse it
source --builtin draft-sync.ysh

exh-channel-new (&ch)

for i in (0..4) {
fork {
for j in (0..4) {
echo $j | exh-channel-in (ch)
}
}
}

sleep 0.5
exh-channel-exhaust (ch, &out)
var sum = 0
for i in (out) {
setvar sum += i
}
echo $sum
# Reuses the channel
fork {
echo "yes!" | exh-channel-in (ch)
}
exh-channel-out (ch)
echo
exh-channel-destroy (ch)
## STDOUT:
24
yes!
## END
56 changes: 0 additions & 56 deletions spec/ysh-stdlib-synch.test.sh

This file was deleted.

89 changes: 89 additions & 0 deletions stdlib/draft-descriptor.ysh
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/usr/bin/env ysh
# vim:foldmethod=marker

module stdlib/descriptor || return 0

# General utilities for file descriptors {{{

# NOTE: we need a proper exception system.
func getFdFile(fd) {
var fd_file
try {
setvar fd_file = $(readlink "/proc/$BASHPID/fd/$fd")
}
if (_status === 0) {
return (fd_file)
} else {
{
echo "File descriptor $fd is not opened by process $BASHPID!"
} >&2
exit 1
}
}

func getFdInfo(fd) {
var fd_info = "/proc/$BASHPID/fdinfo/$fd"
if test -f $fd_info {
return ($(cat $fd_info))
} else {
{
echo "File descriptor $fd is not opened by process $BASHPID!"
} >&2
exit 1
}
}

func getFdFlag(fd) {
var fd_info = getFdInfo(fd)
if (fd_info ~ / 'flags:' \t <capture digit+> /) {
return (_match(1))
} else {
{
echo "Can't find flags in for file descriptor $fd of process $BASHPID, here's the content:"
echo $fd_info
} >&2
exit 1
}
}

# O_RDONLY (00), O_WRONLY (01) & O_RDWR (02)
func isFdRead(fd) {
# HACK: this take one octal number direct from the number string,
# since currently there's no way to convert number bits in std.
var fd_flag = getFdFlag(fd)
return (fd_flag[-1] === "0" or fd_flag[-1] === "2" )
}

func isFdWrite (fd) {
var fd_flag = getFdFlag(fd)
return (fd_flag[-1] === "1" or fd_flag[-1] === "2")
}

# More strict than the standard version
proc fd-destroy-and-rm-file(fd) {
var fd_file = getFdFile(fd)
# NOTE: bash treat >&- and <&- the same, not sure for ysh's case
# REFERENCE: https://unix.stackexchange.com/questions/131801/closing-a-file-descriptor-vs
exec {fd}>&-
rm $fd_file
}

# }}}
# FIFO File Descriptors {{{

proc fifo-fd-new(; out_fd) {
# WARN: this section should be critical but for now it's not
# A solution may be retry on fail.
#====================
var fifo = $(mktemp -u)
mkfifo $fifo
#====================
exec {fd}<>$fifo
call out_fd->setValue(fd)
}

proc fifo-fd-destroy (; fd) {
fd-destroy-and-rm-file $fd
}

# }}}
Loading
Loading