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