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