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 }