infra
/
goutils
Archived
1
0
Fork 0

added initial commit

This commit is contained in:
Sangbum Kim 2018-04-09 11:45:06 +09:00
commit e0bebbbb06
6 changed files with 323 additions and 0 deletions

120
.gitignore vendored Normal file
View File

@ -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

59
main.go Normal file
View File

@ -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))
}

43
runtime/reflect.go Normal file
View File

@ -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
}

55
runtime/runtime.go Normal file
View File

@ -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
}

1
runtime/stub.s Normal file
View File

@ -0,0 +1 @@
// make compiler happy

45
sync/reentrant_lock.go Normal file
View File

@ -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()
}