9fans.net/go@v0.0.7/cmd/acme/logf.go (about)

     1  // #include <u.h>
     2  // #include <libc.h>
     3  // #include <draw.h>
     4  // #include <thread.h>
     5  // #include <cursor.h>
     6  // #include <mouse.h>
     7  // #include <keyboard.h>
     8  // #include <frame.h>
     9  // #include <fcall.h>
    10  // #include <plumb.h>
    11  // #include <libsec.h>
    12  // #include "dat.h"
    13  // #include "fns.h"
    14  
    15  // State for global log file.
    16  
    17  package main
    18  
    19  import (
    20  	"fmt"
    21  	"sync"
    22  
    23  	"9fans.net/go/cmd/acme/internal/wind"
    24  	"9fans.net/go/plan9"
    25  )
    26  
    27  type Log struct {
    28  	lk    sync.Mutex
    29  	r     sync.Cond
    30  	start int64
    31  	ev    []string
    32  	f     []*Fid
    33  	read  []*Xfid
    34  }
    35  
    36  var eventlog Log
    37  
    38  func init() {
    39  	// Using eventlog.lk with a sync.Cond means we have
    40  	// to reacquire big after sync.Wait has locked eventlog.lk.
    41  	// Therefore every acquisition of eventlog.lk must drop big
    42  	// before eventlog.lk.Lock and then reacquire it afterward,
    43  	// or else the two different lock orders will deadlock.
    44  	eventlog.r.L = &eventlog.lk
    45  }
    46  
    47  func xfidlogopen(x *Xfid) {
    48  	bigUnlock()
    49  	eventlog.lk.Lock()
    50  	bigLock()
    51  	eventlog.f = append(eventlog.f, x.f)
    52  	x.f.logoff = eventlog.start + int64(len(eventlog.ev))
    53  	eventlog.lk.Unlock()
    54  }
    55  
    56  func xfidlogclose(x *Xfid) {
    57  	bigUnlock()
    58  	eventlog.lk.Lock()
    59  	bigLock()
    60  	for i := 0; i < len(eventlog.f); i++ {
    61  		if eventlog.f[i] == x.f {
    62  			eventlog.f[i] = eventlog.f[len(eventlog.f)-1]
    63  			eventlog.f = eventlog.f[:len(eventlog.f)-1]
    64  			break
    65  		}
    66  	}
    67  	eventlog.lk.Unlock()
    68  }
    69  
    70  func xfidlogread(x *Xfid) {
    71  	bigUnlock()
    72  	eventlog.lk.Lock()
    73  	bigLock()
    74  	eventlog.read = append(eventlog.read, x)
    75  
    76  	x.flushed = false
    77  	for x.f.logoff >= eventlog.start+int64(len(eventlog.ev)) && !x.flushed {
    78  		bigUnlock()
    79  		eventlog.r.Wait()
    80  		bigLock()
    81  	}
    82  	var i int
    83  
    84  	for i = 0; i < len(eventlog.read); i++ {
    85  		if eventlog.read[i] == x {
    86  			eventlog.read[i] = eventlog.read[len(eventlog.read)-1]
    87  			eventlog.read = eventlog.read[:len(eventlog.read)-1]
    88  			break
    89  		}
    90  	}
    91  
    92  	if x.flushed {
    93  		eventlog.lk.Unlock()
    94  		return
    95  	}
    96  
    97  	i = int(x.f.logoff - eventlog.start)
    98  	p := eventlog.ev[i]
    99  	x.f.logoff++
   100  	eventlog.lk.Unlock()
   101  
   102  	var fc plan9.Fcall
   103  	fc.Data = []byte(p)
   104  	fc.Count = uint32(len(fc.Data))
   105  	respond(x, &fc, "")
   106  }
   107  
   108  func xfidlogflush(x *Xfid) {
   109  	bigUnlock()
   110  	eventlog.lk.Lock()
   111  	bigLock()
   112  	for i := 0; i < len(eventlog.read); i++ {
   113  		rx := eventlog.read[i]
   114  		if rx.fcall.Tag == x.fcall.Oldtag {
   115  			rx.flushed = true
   116  			eventlog.r.Broadcast()
   117  		}
   118  	}
   119  	eventlog.lk.Unlock()
   120  }
   121  
   122  /*
   123   * add a log entry for op on w.
   124   * expected calls:
   125   *
   126   * op == "new" for each new window
   127   *	- caller of coladd or makenewwindow responsible for calling
   128   *		xfidlog after setting window name
   129   *	- exception: zerox
   130   *
   131   * op == "zerox" for new window created via zerox
   132   *	- called from zeroxx
   133   *
   134   * op == "get" for Get executed on window
   135   *	- called from get
   136   *
   137   * op == "put" for Put executed on window
   138   *	- called from put
   139   *
   140   * op == "del" for deleted window
   141   *	- called from winclose
   142   */
   143  func xfidlog(w *wind.Window, op string) {
   144  	bigUnlock()
   145  	eventlog.lk.Lock()
   146  	bigLock()
   147  	if len(eventlog.ev) >= cap(eventlog.ev) {
   148  		// Remove and free any entries that all readers have read.
   149  		min := eventlog.start + int64(len(eventlog.ev))
   150  		for i := 0; i < len(eventlog.f); i++ {
   151  			if min > eventlog.f[i].logoff {
   152  				min = eventlog.f[i].logoff
   153  			}
   154  		}
   155  		if min > eventlog.start {
   156  			n := int(min - eventlog.start)
   157  			copy(eventlog.ev, eventlog.ev[n:])
   158  			eventlog.ev = eventlog.ev[:len(eventlog.ev)-n]
   159  			eventlog.start += int64(n)
   160  		}
   161  
   162  		// Otherwise grow (in append below).
   163  	}
   164  
   165  	f := w.Body.File
   166  	name := string(f.Name())
   167  	eventlog.ev = append(eventlog.ev, fmt.Sprintf("%d %s %s\n", w.ID, op, name))
   168  	eventlog.r.Broadcast()
   169  	eventlog.lk.Unlock()
   170  }