added initial commit
This commit is contained in:
commit
e0bebbbb06
|
@ -0,0 +1,120 @@
|
||||||
|
|
||||||
|
# Created by https://www.gitignore.io/api/intellij,go,linux,osx,windows
|
||||||
|
|
||||||
|
### Intellij ###
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
.idea
|
||||||
|
*.iml
|
||||||
|
|
||||||
|
## File-based project format:
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
## Plugin-specific files:
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
|
||||||
|
### Go ###
|
||||||
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Folders
|
||||||
|
_obj
|
||||||
|
_test
|
||||||
|
|
||||||
|
# Architecture specific extensions/prefixes
|
||||||
|
*.[568vq]
|
||||||
|
[568vq].out
|
||||||
|
|
||||||
|
*.cgo1.go
|
||||||
|
*.cgo2.c
|
||||||
|
_cgo_defun.c
|
||||||
|
_cgo_gotypes.go
|
||||||
|
_cgo_export.*
|
||||||
|
|
||||||
|
_testmain.go
|
||||||
|
|
||||||
|
*.exe
|
||||||
|
*.test
|
||||||
|
*.prof
|
||||||
|
|
||||||
|
|
||||||
|
### Linux ###
|
||||||
|
*~
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||||
|
.fuse_hidden*
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Linux trash folder which might appear on any partition or disk
|
||||||
|
.Trash-*
|
||||||
|
|
||||||
|
|
||||||
|
### OSX ###
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
|
||||||
|
### Windows ###
|
||||||
|
# Windows image file caches
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
Desktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
|
@ -0,0 +1,59 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
mys "amuz.es/src/infra/goutils/sync"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
"math/rand"
|
||||||
|
)
|
||||||
|
|
||||||
|
type philosopher struct {
|
||||||
|
eating bool
|
||||||
|
left *philosopher
|
||||||
|
right *philosopher
|
||||||
|
//table
|
||||||
|
}
|
||||||
|
|
||||||
|
var current []int
|
||||||
|
|
||||||
|
func anotherRoutine(cond *sync.Cond, j int) {
|
||||||
|
vb := time.Duration(rand.Intn(10)+1000) * time.Millisecond
|
||||||
|
time.Sleep(vb)
|
||||||
|
cond.L.Lock()
|
||||||
|
defer cond.L.Unlock()
|
||||||
|
cond.Wait()
|
||||||
|
current = append(current, j)
|
||||||
|
}
|
||||||
|
func monitor(cond *sync.Cond, i int, doneChan chan<- struct{}) {
|
||||||
|
defer close(doneChan)
|
||||||
|
j := 0
|
||||||
|
for {
|
||||||
|
cond.L.Lock()
|
||||||
|
if j == len(current) {
|
||||||
|
cond.Signal()
|
||||||
|
} else {
|
||||||
|
j++
|
||||||
|
//fmt.Printf("%d\n", current[j-1:j])
|
||||||
|
fmt.Printf("%d\n", j)
|
||||||
|
//fmt.Println(current)
|
||||||
|
}
|
||||||
|
cond.L.Unlock()
|
||||||
|
if i == j {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func main() {
|
||||||
|
i := 10000
|
||||||
|
doneChan := make(chan struct{})
|
||||||
|
cond := sync.NewCond(&mys.ReentrantMutex{})
|
||||||
|
go monitor(cond, i, doneChan)
|
||||||
|
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
go anotherRoutine(cond, j)
|
||||||
|
}
|
||||||
|
|
||||||
|
<-doneChan
|
||||||
|
fmt.Printf("done %d\n", len(current))
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
"reflect"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:linkname typesByString reflect.typesByString
|
||||||
|
//go:nosplit
|
||||||
|
func typesByString(s string) []unsafe.Pointer
|
||||||
|
|
||||||
|
/*
|
||||||
|
TypeByString tries to find a reflect.Type corresponding to the type specified by
|
||||||
|
s.
|
||||||
|
It calls the unexported `reflect.typesByString` to do so. It will fail if
|
||||||
|
the type can't be found or if more than one type with the given name exist.
|
||||||
|
This relies on the following assumptions:
|
||||||
|
* The signature of `reflect.typesByString` must not change
|
||||||
|
* The value returned by `reflect.TypeOf(0)` is a `*reflect.rtype`
|
||||||
|
* The `reflect.Value` struct contains a `ptr` field of type `unsafe.Pointer`
|
||||||
|
*/
|
||||||
|
func TypeByString(s string) (reflect.Type, error) {
|
||||||
|
types := typesByString(s)
|
||||||
|
|
||||||
|
if len(types) == 0 {
|
||||||
|
return nil, fmt.Errorf("Type '%s' not found", s)
|
||||||
|
}
|
||||||
|
if len(types) > 1 {
|
||||||
|
return nil, fmt.Errorf("Type '%s' is ambiguous", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
t := types[0]
|
||||||
|
|
||||||
|
pRtypeType := reflect.ValueOf(reflect.TypeOf(0)).Type()
|
||||||
|
rtype := reflect.New(pRtypeType).Elem()
|
||||||
|
|
||||||
|
ptr := unsafe.Pointer(reflect.ValueOf(rtype).FieldByName("ptr").Pointer())
|
||||||
|
*(*unsafe.Pointer)(ptr) = t
|
||||||
|
|
||||||
|
typ := rtype.Interface().(reflect.Type)
|
||||||
|
return typ, nil
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
offsetGoid uintptr
|
||||||
|
offsetSched uintptr
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
pg, err := TypeByString("*runtime.g")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if pg.Kind() != reflect.Ptr {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g := pg.Elem()
|
||||||
|
if g.Kind() != reflect.Struct {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
goid, ok := g.FieldByName("goid")
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sched, ok := g.FieldByName("sched")
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
offsetGoid = goid.Offset
|
||||||
|
offsetSched = sched.Offset
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname mcall runtime.mcall
|
||||||
|
//go:nosplit
|
||||||
|
func mcall(func(uintptr))
|
||||||
|
|
||||||
|
//go:linkname gogo runtime.gogo
|
||||||
|
//go:nosplit
|
||||||
|
func gogo(uintptr)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func GOID() (goid int64) {
|
||||||
|
mcall(func(g uintptr) {
|
||||||
|
id := unsafe.Pointer(g + offsetGoid)
|
||||||
|
goid = *(*int64)(id)
|
||||||
|
sched := g + offsetSched
|
||||||
|
gogo(sched)
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
// make compiler happy
|
|
@ -0,0 +1,45 @@
|
||||||
|
package sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"amuz.es/src/infra/goutils/runtime"
|
||||||
|
"sync/atomic"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ReentrantMutex struct {
|
||||||
|
lock sync.Mutex
|
||||||
|
owner int64 // current lock owner
|
||||||
|
recursion int64 //current recursion level
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ReentrantMutex) Lock() {
|
||||||
|
caller := runtime.GOID()
|
||||||
|
// fast path
|
||||||
|
if atomic.LoadInt64(&r.owner) == caller {
|
||||||
|
r.recursion++
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.lock.Lock()
|
||||||
|
// we are now inside the lock
|
||||||
|
atomic.StoreInt64(&r.owner, caller)
|
||||||
|
r.recursion = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ReentrantMutex) Unlock() {
|
||||||
|
caller := runtime.GOID()
|
||||||
|
if atomic.LoadInt64(&r.owner) != caller {
|
||||||
|
panic(fmt.Sprintf("you are not the owner(%d): %d!", r.owner, caller))
|
||||||
|
}
|
||||||
|
|
||||||
|
r.recursion--
|
||||||
|
// fast path
|
||||||
|
if r.recursion != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// we are going to release the lock
|
||||||
|
atomic.StoreInt64(&r.owner, 0)
|
||||||
|
r.lock.Unlock()
|
||||||
|
}
|
Reference in New Issue