godel / godel / godel.go

// Copyright 2011 Abhishek Kulkarni. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package godel

import (
	"time"
	"flag"
	"runtime"
	"fmt"
	"strconv"
)

/*
 Propagation networks propose a shift in the foundation of computation,
 by moving away from rigid, time-bound expression-evaluation computation
 paradigm to a more general-purpose propagation-oriented paradigm where
 information flow is multidirectional.

 Programs are written by architecting them as propagation networks, as
 computational modules that are arranged in parallel or in series, much
 like elements in an electric circuit.
*/

// Possible states (for cells and propagators)
const (
	Stopped = iota
	Running
	Idle
)

type States int

// Possible commands
const (
	Stop = iota
	AddContent
	Content
	Run
	Reset
)

type Msg struct {
	Cmd	    uint8
	Value	    interface{}
}

type GenericFn func(interface{}) interface{}

func idle() { time.Sleep(1e6) }

type PropagatorNetwork struct {
	Name        string
	Index       uint
	Quiet       chan bool
	Propagators []*Propagator
}

// create a new propagator network
func NewPropagatorNetwork(name string) *PropagatorNetwork {
	flag.Parse()
	setDebugLevel(*debugFlags)
	pn := &PropagatorNetwork{
		Name:        name,
		Index:       0,
		Quiet:       make(chan bool),
	}

	Debug(dbgPropagator, "== created propagator network %s\n", pn.Name)
	return pn
}

// add a new cell to a given propagator network
func (pn *PropagatorNetwork) NewCell(name string) *Cell {
	c := &Cell{
		Name:      name,
		Network:   pn,
		Value:	   nil,
		SChan:     make(chan Msg, 5),
		State:     Idle,
		Neighbors: make(map[string]*Propagator),
	}

	Debug(dbgCell, "** created cell %s in %s\n", c.Name, pn.Name)
	go c.Listen()
	return c
}

// add a new propagator to a given propagator network
func (pn *PropagatorNetwork) NewPropagator(name string, f GenericFn, ics, ocs interface{}) {
	p := &Propagator{
		Name:     name + "-" + strconv.Uitoa(pn.Index),
		Network:  pn,
		SChan:    make(chan Msg, 5),
		State:    Idle,
		Function: f,
	}

	if ics != nil {
		p.Inputs = ics.([]*Cell)
		for i := range p.Inputs {
			p.Inputs[i].NewNeighbor(p)
		}
	}

	if ocs != nil {
		p.Outputs = ocs.([]*Cell)
	}

	Debug(dbgPropagator, ">> created propagator %s in %s\n", p.Name, pn.Name)
	pn.Index++
	pn.Propagators = append(pn.Propagators, p)
	p.Run()
	go p.Listen()
}

func (pn *PropagatorNetwork) Reset() {
	for _, p := range pn.Propagators {
		for _, c := range p.Outputs {
			c.Reset()
		}
		for _, c := range p.Inputs {
			c.Reset()
		}
	}

	for _, p := range pn.Propagators {
		p.Run()
	}
}

// check if the propagator network is in a quiescent state or not
func (pn *PropagatorNetwork) Quiescent() chan bool {
	go func() {
	again:
		idle()
		for _, p := range pn.Propagators {
			if p.State == Running {
				// Wait for the network to be quiet
				idle()
				runtime.Gosched()
				goto again
			}
		}
		Debug(dbgPropagator, "== network %s is in a quiescent state\n", pn.Name)
		pn.Quiet <- true
	}()
	return pn.Quiet
}

// stop a propagator network
func (pn *PropagatorNetwork) Stop() {
	// Stop all propagators
	for _, p := range pn.Propagators {
		for _, c := range p.Outputs {
			c.Destroy()
		}
		p.Destroy()
	}

	Debug(dbgPropagator, "== stopping propagator network %s\n", pn.Name)
}

// stop a propagator network
func (pn *PropagatorNetwork) Panic(format string, a ...interface{}) {
	pn.Stop()
	panic(fmt.Sprintf(format, a...))
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.