lib9p

Go 9P library.
Log | Files | Refs | LICENSE

req.go (2407B)


      1 package lib9p
      2 
      3 import (
      4 	"sync"
      5 )
      6 
      7 // request represents each requests.
      8 type request struct {
      9 	tag uint16
     10 	// Ifcall is incomming 9P message
     11 	ifcall Msg
     12 	// Ofcall is response message to Ifcall.
     13 	ofcall Msg
     14 	fid    *fid
     15 	afid   *fid
     16 	// Oldreq is set with Tflush message.
     17 	oldreq *request
     18 	// Pool is the pool this request belongs to.
     19 	pool *reqPool
     20 	// Done is used by time consuming goroutines to check whether the request
     21 	// is flushed.
     22 	done chan struct{}
     23 	// listenErr is any error encountered while waiting for new 9P message.
     24 	listenErr error
     25 	// speakErrChan is used to report any error encountered while sending
     26 	// the response message.
     27 	// TODO: is this channel closed in all senarios?
     28 	speakErrChan chan error
     29 	// err is any error encountered while processing the request.
     30 	err error
     31 }
     32 
     33 // flush cancels the request by calling r.cancel.
     34 // It also delete the request from its pool.
     35 func (r *request) flush() {
     36 	// TODO: need mutex?
     37 	close(r.done)
     38 	r.pool.delete(r.tag)
     39 }
     40 
     41 // reqPool is the pool of Reqs the server is dealing with.
     42 type reqPool struct {
     43 	m map[uint16]*request
     44 	*sync.Mutex
     45 }
     46 
     47 // newReqPool allocats a reqPool.
     48 func newReqPool() *reqPool {
     49 	return &reqPool{
     50 		make(map[uint16]*request),
     51 		new(sync.Mutex),
     52 	}
     53 }
     54 
     55 // Add allocates a request with the specified tag in reqPool rp.
     56 // It returns (nil, ErrDupTag) if there is already a request with the specified tag,
     57 // exept that if the tag is NOTAG, it deletes all the request in the map and
     58 // allocats an req with that tag.
     59 func (rp *reqPool) add(tag uint16) (*request, error) {
     60 	return reqPoolAdd(rp, tag)
     61 }
     62 
     63 var reqPoolAdd = func(rp *reqPool, tag uint16) (*request, error) {
     64 	rp.Lock()
     65 	defer rp.Unlock()
     66 	if tag == NOTAG {
     67 		for _, r := range rp.m {
     68 			close(r.done)
     69 		}
     70 		rp.m = make(map[uint16]*request)
     71 	}
     72 	if _, ok := rp.m[tag]; ok {
     73 		return nil, ErrDupTag
     74 	}
     75 	req := &request{
     76 		pool:         rp,
     77 		done:         make(chan struct{}),
     78 		speakErrChan: make(chan error),
     79 	}
     80 	rp.m[tag] = req
     81 	return req, nil
     82 }
     83 
     84 // lookup looks for the request in the pool with tag.
     85 // If found, it returns the found request and true, otherwise
     86 // it returns nil and false.
     87 func (rp *reqPool) lookup(tag uint16) (*request, bool) {
     88 	rp.Lock()
     89 	defer rp.Unlock()
     90 	r, ok := rp.m[tag]
     91 	return r, ok
     92 }
     93 
     94 // delete delets the request with tag from the pool.
     95 func (rp *reqPool) delete(tag uint16) {
     96 	rp.Lock()
     97 	defer rp.Unlock()
     98 	delete(rp.m, tag)
     99 }