Skip to content

Commit

Permalink
Implementation of Readers-writer lock (Concurrent::RWLock) | WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
64kramsystem committed Oct 30, 2017
1 parent d0fd185 commit 3fb0a39
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 7 deletions.
167 changes: 167 additions & 0 deletions vm/concurrent_rw_lock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package vm

import (
"sync"

"github.com/goby-lang/goby/vm/errors"
)

// ConcurrentRWLockObject is a Readers-Writer Lock (readers can concurrently put a lock, while a
// writer requires exclusive access).
//
// The implementation internally uses Go's `sync.RWLock` type.
//
// ```ruby
// require 'concurrent/rw_lock'
// lock = Concurrent::RWLock.new
// lock.with_read_lock do
// # critical section
// end
// lock.with_write_lock do
// # critical section
// end
// ```
//
type ConcurrentRWLockObject struct {
*baseObj
mutex sync.RWMutex
}

// Class methods --------------------------------------------------------
func builtinConcurrentRWLockClassMethods() []*BuiltinMethodObject {
return []*BuiltinMethodObject{
{
Name: "new",
Fn: func(receiver Object, sourceLine int) builtinMethodBody {
return func(t *thread, args []Object, blockFrame *normalCallFrame) Object {
if len(args) != 0 {
return t.vm.initErrorObject(errors.ArgumentError, sourceLine, "Expect 0 arguments, got %d", len(args))
}

return t.vm.initConcurrentRWLockObject()
}
},
},
}
}

// Instance methods -----------------------------------------------------
func builtinConcurrentRWLockInstanceMethods() []*BuiltinMethodObject {
return []*BuiltinMethodObject{
{
// Executes the block with a read lock.
// The lock is freed upon exiting the block.
//
// ```Ruby
// lock = Concurrent::RWLock.new
// lock.with_read_lock do
// # critical section
// end
//
// @return [Object] the yielded value of the block.
// ```
Name: "with_read_lock",
Fn: func(receiver Object, sourceLine int) builtinMethodBody {
return func(t *thread, args []Object, blockFrame *normalCallFrame) Object {
if blockFrame == nil {
return t.vm.initErrorObject(errors.InternalError, sourceLine, errors.CantYieldWithoutBlockFormat)
}

if len(args) != 0 {
t.callFrameStack.pop()

return t.vm.initErrorObject(errors.ArgumentError, sourceLine, "Expected 0 arguments. got: %d", len(args))
}

lockObject := receiver.(*ConcurrentRWLockObject)

lockObject.mutex.RLock();

blockReturnValue := t.builtinMethodYield(blockFrame).Target

lockObject.mutex.RUnlock();

return blockReturnValue
}
},
},
{
// Executes the block with a write lock.
// The lock is freed upon exiting the block.
//
// ```Ruby
// lock = Concurrent::RWLock.new
// lock.with_write_lock do
// # critical section
// end
//
// @return [Object] the yielded value of the block.
// ```
Name: "with_write_lock",
Fn: func(receiver Object, sourceLine int) builtinMethodBody {
return func(t *thread, args []Object, blockFrame *normalCallFrame) Object {
if blockFrame == nil {
return t.vm.initErrorObject(errors.InternalError, sourceLine, errors.CantYieldWithoutBlockFormat)
}

if len(args) != 0 {
t.callFrameStack.pop()

return t.vm.initErrorObject(errors.ArgumentError, sourceLine, "Expected 0 arguments. got: %d", len(args))
}

lockObject := receiver.(*ConcurrentRWLockObject)

lockObject.mutex.Lock();

blockReturnValue := t.builtinMethodYield(blockFrame).Target

lockObject.mutex.Unlock();

return blockReturnValue
}
},
},
}
}

// Internal functions ===================================================

// Functions for initialization -----------------------------------------

func (vm *VM) initConcurrentRWLockObject() *ConcurrentRWLockObject {
concurrentModule := vm.loadConstant("Concurrent", true)
lockClass := concurrentModule.getClassConstant("RWLock")

return &ConcurrentRWLockObject{
baseObj: &baseObj{class: lockClass},
mutex: sync.RWMutex{},
}
}

func initConcurrentRWLockClass(vm *VM) {
concurrentModule := vm.loadConstant("Concurrent", true)
lockClass := vm.initializeClass("RWLock", false)

lockClass.setBuiltinMethods(builtinConcurrentRWLockInstanceMethods(), false)
lockClass.setBuiltinMethods(builtinConcurrentRWLockClassMethods(), true)

concurrentModule.setClassConstant(lockClass)
}

// Polymorphic helper functions -----------------------------------------

// Value returns the object
func (lock *ConcurrentRWLockObject) Value() interface{} {
return lock.mutex
}

// toString returns the object's name as the string format
func (lock *ConcurrentRWLockObject) toString() string {
return "<Instance of: " + lock.class.Name + ">"
}

// toJSON just delegates to toString
func (lock *ConcurrentRWLockObject) toJSON() string {
return lock.toString()
}
15 changes: 8 additions & 7 deletions vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,14 @@ type filename = string
type errorMessage = string

var standardLibraries = map[string]func(*VM){
"net/http": initHTTPClass,
"net/simple_server": initSimpleServerClass,
"uri": initURIClass,
"db": initDBClass,
"plugin": initPluginClass,
"json": initJSONClass,
"concurrent/hash": initConcurrentHashClass,
"net/http": initHTTPClass,
"net/simple_server": initSimpleServerClass,
"uri": initURIClass,
"db": initDBClass,
"plugin": initPluginClass,
"json": initJSONClass,
"concurrent/hash": initConcurrentHashClass,
"concurrent/rw_lock": initConcurrentRWLockClass,
}

// VM represents a stack based virtual machine.
Expand Down

0 comments on commit 3fb0a39

Please sign in to comment.