// Remove removes the exported value with handle id from the table, if present. // If present, a check is performed that importer is the same one, registered // with the table. If not, an error is returned. func (exp *expTabl) Remove(id circuit.HandleID, importer n.Addr) { if importer == nil { panic("cannot remove perm handles from exp") } exp.lk.Lock() defer exp.lk.Unlock() exph, present := exp.id[id] if !present { return } if importer.WorkerID() != exph.Importer.WorkerID() { panic("releasing importer different than original") } delete(exp.id, id) impTabl, present := exp.nonperm[exph.Importer.WorkerID()] if !present { panic("missing importer map") } delete(impTabl, exph.Value.Interface()) if len(impTabl) == 0 { delete(exp.nonperm, exph.Importer.WorkerID()) } }
func (exp *expTabl) RemoveImporter(importer n.Addr) { if importer == nil { panic("nil importer") } exp.lk.Lock() defer exp.lk.Unlock() impTabl, present := exp.nonperm[importer.WorkerID()] if !present { return } delete(exp.nonperm, importer.WorkerID()) for _, exph := range impTabl { delete(exp.id, exph.ID) } runtime.GC() }
func (d *Dialer) Dial(addr n.Addr) (conn n.Conn, err error) { d.Lock() defer d.Unlock() // workerID := addr.WorkerID() s, present := d.open[workerID] if !present { // Make new session to worker if one not present s = d.sub.DialSession(addr.(*Addr).TCP, func() { d.scrub(addr.WorkerID()) }) if err = d.auth(addr, s.Dial()); err != nil { s.Close() return nil, err } d.open[workerID] = s go d.watch(workerID, s) // Watch for idleness and close } return NewConn(s.Dial(), addr.(*Addr)), nil }
// exportPtr returns *permPtrMsg if importer is nil, and *ptrMsg otherwise. func (r *Runtime) exportPtr(v interface{}, importer n.Addr) interface{} { // Add exported value to export table exph := r.exp.Add(v, importer) // log.Printf("exporting %T with handle %s for importer %v", v, exph.ID.String(), importer) if importer == nil { return &permPtrMsg{ID: exph.ID, TypeID: exph.Type.ID} } // Monitor the importer for liveness. // DropPtr the handles upon importer death. r.lk.Lock() defer r.lk.Unlock() _, ok := r.live[importer.WorkerID()] if !ok { r.live[importer.WorkerID()] = struct{}{} // The anonymous function creates a "lifeline" connection to the worker importing v. // When this conncetion is broken, v is released. go func() { // Defer removal of v's handle from the export table to the end of this function defer func() { r.lk.Lock() delete(r.live, importer.WorkerID()) r.lk.Unlock() // DropPtr/forget all exported handles r.exp.RemoveImporter(importer) }() conn, err := r.t.Dial(importer) if err != nil { // log.Println("problem dialing lifeline to", importer.String(), err.Error()) return } defer conn.Close() if conn.Write(&dontReplyMsg{}) != nil { log.Println("problem writing on lifeline to", importer.String(), err.Error()) return } // Read returns when the remote dies and // runs the conn into an error conn.Read() }() } return &ptrMsg{ID: exph.ID, TypeID: exph.Type.ID} }
func (exp *expTabl) Add(receiver interface{}, importer n.Addr) *expHandle { if receiver == nil { panic("bug: nil receiver in export") } exp.lk.Lock() defer exp.lk.Unlock() // Is receiver already exported in the respective perm/nonperm fashion? var impHere bool var impTabl map[interface{}]*expHandle if importer != nil { // Non-permanent case impTabl, impHere = exp.nonperm[importer.WorkerID()] if impHere { exph, present := impTabl[receiver] if present { return exph } } } else { // Permanent case if exph, present := exp.perm[receiver]; present { return exph } } // Build exported handle object //fmt.Printf("recv (%#T): %#v\n", receiver, receiver) typ := exp.tt.TypeOf(receiver) if typ.Type != reflect.TypeOf(receiver) { panic("bug: wrong type") } exph := &expHandle{ ID: circuit.ChooseHandleID(), Importer: importer, Value: reflect.ValueOf(receiver), Type: typ, } // Insert in handle map if _, present := exp.id[exph.ID]; present { panic("handle id collision") } exp.id[exph.ID] = exph // Insert in value map if importer != nil { // Non-permanent case if !impHere { impTabl = make(map[interface{}]*expHandle) exp.nonperm[importer.WorkerID()] = impTabl } impTabl[receiver] = exph } else { // Permanent case exp.perm[receiver] = exph } return exph }