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