cleanup-licensing-and-transarc-references-20030309
[openafs.git] / src / WINNT / client_osi / osilog.c
1 /* 
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /* Copyright (C) 1994 Cazamar Systems, Inc. */
11
12 #include <afs/param.h>
13 #include <afs/stds.h>
14
15 #ifndef DJGPP
16 #include <windows.h>
17 #include <rpc.h>
18 #endif /* !DJGPP */
19 #include <malloc.h>
20 #include "osi.h"
21 #ifndef DJGPP
22 #include "dbrpc.h"
23 #endif /* !DJGPP */
24 #include <stdio.h>
25 #include <assert.h>
26
27 /* the size; overrideable */
28 long osi_logSize = OSI_LOG_DEFAULTSIZE;
29
30 static osi_once_t osi_logOnce;
31
32 osi_log_t *osi_allLogsp;        /* all logs known; for use during panic */
33
34 unsigned long osi_logFreq;      /* 0, or frequency of high perf counter */
35 unsigned long osi_logTixToMicros;       /* mult. correction factor */
36
37 osi_fdOps_t osi_logFDOps = {
38         osi_LogFDCreate,
39 #ifndef DJGPP
40         osi_LogFDGetInfo,
41 #endif
42         osi_LogFDClose
43 };
44
45 /* create a new log, taking a name and a size in entries (not words) */
46 osi_log_t *osi_LogCreate(char *namep, long size)
47 {
48         osi_log_t *logp;
49         osi_fdType_t *typep;
50         char tbuffer[256];
51         LARGE_INTEGER bigFreq;
52         LARGE_INTEGER bigTemp;
53         LARGE_INTEGER bigJunk;
54         
55 #ifndef DJGPP
56         if (osi_Once(&osi_logOnce)) {
57                 QueryPerformanceFrequency(&bigFreq);
58                 if (bigFreq.LowPart == 0 && bigFreq.HighPart == 0)
59                         osi_logFreq = 0;
60                 else {
61                         /* turn frequency into ticks per 10 micros */
62                         bigTemp.LowPart = 100000;
63                         bigTemp.HighPart = 0;
64                         osi_logTixToMicros = 10;
65                         bigFreq = LargeIntegerDivide(bigFreq, bigTemp, &bigJunk);
66
67                         /* check if resolution is too fine or to gross for this to work */
68                         if (bigFreq.HighPart > 0 || bigFreq.LowPart < 8)
69                                 osi_logFreq = 0;        /* too big to represent as long */
70                         else
71                                 osi_logFreq = bigFreq.LowPart;
72                 }
73
74                 /* done with init */
75                 osi_EndOnce(&osi_logOnce);
76         }
77 #endif /* !DJGPP */
78
79         logp = malloc(sizeof(osi_log_t));
80         memset(logp, 0, sizeof(osi_log_t));
81         logp->namep = malloc(strlen(namep)+1);
82         strcpy(logp->namep, namep);
83         
84         osi_QAdd((osi_queue_t **) &osi_allLogsp, &logp->q);
85
86         /* compute size we'll use */
87         if (size == 0) size = osi_logSize;
88
89         /* handle init for this size */
90         logp->alloc = size;
91         logp->datap = malloc(size * sizeof(osi_logEntry_t));
92
93         /* init strings array */
94         logp->maxstringindex = size/10;
95         logp->stringindex = 0;
96         logp->stringsp = malloc((size/10) * OSI_LOG_STRINGSIZE);
97  
98         /* and sync */
99         thrd_InitCrit(&logp->cs);
100         
101         strcpy(tbuffer, "log:");
102         strcat(tbuffer, namep);
103         typep = osi_RegisterFDType(tbuffer, &osi_logFDOps, logp);
104 #ifndef DJGPP
105         if (typep) {
106                 /* add formatting info */
107                 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 0,
108                         "Thread ID", OSI_DBRPC_HEX);
109                 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONSTRING, 1,
110                         "Time (mics)", 0);
111         }
112 #endif
113         
114         return logp;
115 }
116
117 /* we just panic'd.  Turn off all logging adding special log record
118  * to all enabled logs.  Be careful not to wait for a lock.
119  */
120 void osi_LogPanic(char *filep, long lineNumber)
121 {
122         osi_log_t *tlp;
123
124         for(tlp = osi_allLogsp; tlp; tlp = (osi_log_t *) osi_QNext(&tlp->q)) {
125                 if (!tlp->enabled) continue;
126
127                 /* otherwise, proceed */
128                 if (filep)
129                         osi_LogAdd(tlp, "**PANIC** (file %s:%d)", (long) filep, lineNumber, 0, 0);
130                 else
131                         osi_LogAdd(tlp, "**PANIC**", 0, 0, 0, 0);
132                 
133                 /* should grab lock for this, but we're in panic, and better safe than
134                  * sorry.
135                  */
136                 tlp->enabled = 0;
137         }
138 }
139
140 /* reset the contents of a log */
141 void osi_LogReset(osi_log_t *logp)
142 {
143         if (logp) {
144                 thrd_EnterCrit(&logp->cs);
145                 logp->nused = 0;
146                 thrd_LeaveCrit(&logp->cs);
147         }
148 }
149
150 /* free a log */
151 void osi_LogFree(osi_log_t *logp)
152 {
153         if (!logp) return;
154
155         osi_QRemove((osi_queue_t **) &osi_allLogsp, &logp->q);
156
157         free(logp->namep);
158         free(logp->datap);
159         thrd_DeleteCrit(&logp->cs);
160         free(logp);
161 }
162
163 /* add an element to a log */
164 void osi_LogAdd(osi_log_t *logp, char *formatp, long p0, long p1, long p2, long p3)
165 {
166         osi_logEntry_t *lep;
167         long ix;
168         LARGE_INTEGER bigTime;
169
170         /* handle init races */
171         if (!logp) return;
172
173         /* do this w/o locking for speed; it is obviously harmless if we're off
174          * by a bit.
175          */
176         if (!logp->enabled) return;
177         
178         thrd_EnterCrit(&logp->cs);
179         if (logp->nused < logp->alloc) logp->nused++;
180         else {
181                 logp->first++;
182                 if (logp->first >= logp->alloc) logp->first -= logp->alloc;
183         }
184         ix = logp->first + logp->nused - 1;
185         if (ix >= logp->alloc) ix -= logp->alloc;
186
187         lep = logp->datap + ix; /* ptr arith */
188         lep->tid = thrd_Current();
189
190         /* get the time, using the high res timer if available */
191 #ifndef DJGPP
192         if (osi_logFreq) {
193                 QueryPerformanceCounter(&bigTime);
194                 lep->micros = (bigTime.LowPart / osi_logFreq) * osi_logTixToMicros;
195         }
196         else lep->micros = GetCurrentTime() * 1000;
197 #else
198         lep->micros = gettime_us();
199 #endif /* !DJGPP */                
200
201         lep->formatp = formatp;
202         lep->parms[0] = p0;
203         lep->parms[1] = p1;
204         lep->parms[2] = p2;
205         lep->parms[3] = p3;
206         thrd_LeaveCrit(&logp->cs);
207 }
208
209 void osi_LogPrint(osi_log_t *logp, FILE_HANDLE handle)
210 {
211         char wholemsg[1000], msg[1000];
212         int i, ix, ioCount;
213         osi_logEntry_t *lep;
214
215         if (!logp->enabled) return;
216
217         thrd_EnterCrit(&logp->cs);
218
219         for (ix = logp->first, i = 0;
220              i < logp->nused;
221              i++, ix++, (ix >= logp->alloc ? ix -= logp->alloc : 0)) {
222                 lep = logp->datap + ix;         /* pointer arithmetic */
223                 sprintf(msg, lep->formatp,
224                         lep->parms[0], lep->parms[1],
225                         lep->parms[2], lep->parms[3]);
226                 sprintf(wholemsg, "time %d.%06d, pid %d %s\n",
227                         lep->micros / 1000000,
228                         lep->micros % 1000000,
229                         lep->tid, msg);
230 #ifndef DJGPP
231                 if (!WriteFile(handle, wholemsg, strlen(wholemsg),
232                                 &ioCount, NULL))
233 #else /* DJGPP */
234                 if ((ioCount = fwrite(wholemsg, 1, strlen(wholemsg), handle)) == 0)
235 #endif /* !DJGPP */
236                         break;
237         }
238
239         thrd_LeaveCrit(&logp->cs);
240 }
241
242 char *osi_LogSaveString(osi_log_t *logp, char *s)
243 {
244         char *saveplace = logp->stringsp[logp->stringindex];
245
246         if (s == NULL) return NULL;
247
248         if (strlen(s) >= OSI_LOG_STRINGSIZE)
249                 sprintf(saveplace, "...%s",
250                         s + strlen(s) - (OSI_LOG_STRINGSIZE - 4));
251         else
252                 strcpy(saveplace, s);
253         logp->stringindex++;
254         if (logp->stringindex >= logp->maxstringindex)
255             logp->stringindex = 0;
256
257         return saveplace;
258 }
259
260 long osi_LogFDCreate(osi_fdType_t *typep, osi_fd_t **outpp)
261 {
262         osi_logFD_t *lfdp;
263         osi_log_t *logp;
264         
265         lfdp = malloc(sizeof(*lfdp));
266         logp = lfdp->logp = typep->rockp;       /* the log we were created for */
267         thrd_EnterCrit(&logp->cs);
268         lfdp->nused = logp->nused;
269         lfdp->first = logp->first;
270         lfdp->current = 0;
271         thrd_LeaveCrit(&logp->cs);
272
273         *outpp = &lfdp->fd;
274         return 0;
275 }
276
277 #ifndef DJGPP
278 long osi_LogFDGetInfo(osi_fd_t *ifd, osi_remGetInfoParms_t *outp)
279 {
280         osi_logFD_t *lfdp;
281         osi_log_t *logp;
282         osi_logEntry_t *lep;
283         char tbuffer[256];
284         long ix;
285         
286         lfdp = (osi_logFD_t *) ifd;
287         logp = lfdp->logp;
288         
289         /* see if we're done */
290         if (lfdp->current >= lfdp->nused) return OSI_DBRPC_EOF;
291         
292         /* grab lock */
293         thrd_EnterCrit(&logp->cs);
294
295         /* compute which one we want */
296         ix = lfdp->first + lfdp->current;
297         if (ix >= logp->alloc) ix -= logp->alloc;
298         lfdp->current++;
299         lep = logp->datap + ix; /* ptr arith to current index */
300
301         sprintf(tbuffer, lep->formatp, lep->parms[0], lep->parms[1],
302                 lep->parms[2], lep->parms[3]);
303
304         /* now copy out info */
305         strcpy(outp->sdata[0], tbuffer);
306         sprintf(tbuffer, "%5.6f", ((double)lep->micros)/1000000.0);
307         strcpy(outp->sdata[1], tbuffer);
308         outp->idata[0] = lep->tid;
309         outp->scount = 2;
310         outp->icount = 1;
311
312         thrd_LeaveCrit(&logp->cs);
313         return 0;
314 }
315 #endif /* !DJGPP */
316
317 long osi_LogFDClose(osi_fd_t *ifdp)
318 {
319         free(ifdp);
320         return 0;
321 }
322
323 void osi_LogEnable(osi_log_t *logp)
324 {
325         if (logp)
326                 logp->enabled = 1;
327 }
328
329 void osi_LogDisable(osi_log_t *logp)
330 {
331         if (logp)
332                 logp->enabled = 0;
333 }
334
335 #define REG_CLIENT_PARMS_KEY  "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters"
336 #define TRACE_OPTION_EVENT 1
337 #define ISLOGONTRACE(v) ( ((v) & TRACE_OPTION_EVENT)==TRACE_OPTION_EVENT)
338
339 DWORD osi_TraceOption=0;
340
341 void osi_InitTraceOption()
342 {
343         DWORD LSPtype, LSPsize;
344         HKEY NPKey;
345         (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY,
346                     0, KEY_QUERY_VALUE, &NPKey);
347         LSPsize=sizeof(osi_TraceOption);
348         RegQueryValueEx(NPKey, "TraceOption", NULL,
349                                 &LSPtype, (LPBYTE)&osi_TraceOption, &LSPsize);\r
350 }
351
352
353 #define MAXBUF_ 131
354 void osi_LogEvent0(char *a,char *b) 
355 {
356         HANDLE h; char *ptbuf[1],buf[MAXBUF_+1];
357         if (!ISLOGONTRACE(osi_TraceOption))
358                 return;
359         h = RegisterEventSource(NULL, a);
360         ptbuf[0] = b;
361         ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
362         DeregisterEventSource(h);
363 }
364
365
366 void osi_LogEvent(char *a,char *b,char *c,...) 
367 {
368         HANDLE h; char *ptbuf[1],buf[MAXBUF_+1];
369         va_list marker;
370         if (!ISLOGONTRACE(osi_TraceOption))
371                 return;
372         if (b)
373         {
374                 wsprintf(buf,a,b);
375                 h = RegisterEventSource(NULL, buf);
376         }
377         else
378                 h = RegisterEventSource(NULL, a);
379         va_start(marker,c);
380         _vsnprintf(buf,MAXBUF_,c,marker);
381         ptbuf[0] = buf;
382         ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);\
383         DeregisterEventSource(h);
384         va_end(marker);
385 }