1 /* PTTRACE.C (c) Copyright Greg Smith, 2003-2010 */
2 /* pthreads trace debugger */
3
4 /*-------------------------------------------------------------------*/
5 /* Trace threading calls */
6 /*-------------------------------------------------------------------*/
7
8 #include "hstdinc.h"
9
10 #define _PTTRACE_C_
11 #define _HUTIL_DLL_
12
13 #include "hercules.h"
14
15 #ifdef OPTION_PTTRACE
16
17 PTT_TRACE *pttrace; /* Pthreads trace table */
18 int pttracex; /* Pthreads trace index */
19 int pttracen; /* Pthreads trace entries */
20 LOCK pttlock; /* Pthreads trace lock */
21 int pttnolock; /* 1=no PTT locking */
22 int pttnotod; /* 1=don't call gettimeofday */
23 int pttnowrap; /* 1=don't wrap */
24 int pttto; /* timeout in seconds */
25 TID ptttotid; /* timeout thread id */
26 LOCK ptttolock; /* timeout thread lock */
27 COND ptttocond; /* timeout thread condition */
28
ptt_trace_init(int n,int init)29 DLL_EXPORT void ptt_trace_init (int n, int init)
30 {
31 if (n > 0)
32 pttrace = calloc (n, PTT_TRACE_SIZE);
33 else
34 pttrace = NULL;
35
36 if (pttrace)
37 pttracen = n;
38 else
39 pttracen = 0;
40
41 pttracex = 0;
42
43 if (init)
44 {
45 #if defined(OPTION_FTHREADS)
46 fthread_mutex_init (&pttlock, NULL);
47 #else
48 pthread_mutex_init (&pttlock, NULL);
49 #endif
50 pttnolock = 0;
51 pttnotod = 0;
52 pttnowrap = 0;
53 pttto = 0;
54 ptttotid = 0;
55 #if defined(OPTION_FTHREADS)
56 fthread_mutex_init (&ptttolock, NULL);
57 fthread_cond_init (&ptttocond);
58 #else
59 pthread_mutex_init (&ptttolock, NULL);
60 pthread_cond_init (&ptttocond, NULL);
61 #endif
62 }
63 }
64
ptt_cmd(int argc,char * argv[],char * cmdline)65 DLL_EXPORT int ptt_cmd(int argc, char *argv[], char* cmdline)
66 {
67 int rc = 0;
68 int n, to = -1;
69 char c;
70
71 UNREFERENCED(cmdline);
72
73 if (argc > 1)
74 {
75 /* process arguments; last arg can be trace table size */
76 for (--argc, argv++; argc; --argc, ++argv)
77 {
78 if (strcasecmp("opts", argv[0]) == 0)
79 continue;
80 else if (strcasecmp("error", argv[0]) == 0)
81 {
82 pttclass |= PTT_CL_ERR;
83 continue;
84 }
85 else if (strcasecmp("noerror", argv[0]) == 0)
86 {
87 pttclass &= ~PTT_CL_ERR;
88 continue;
89 }
90 else if (strcasecmp("control", argv[0]) == 0)
91 {
92 pttclass |= PTT_CL_INF;
93 continue;
94 }
95 else if (strcasecmp("nocontrol", argv[0]) == 0)
96 {
97 pttclass &= ~PTT_CL_INF;
98 continue;
99 }
100 else if (strcasecmp("prog", argv[0]) == 0)
101 {
102 pttclass |= PTT_CL_PGM;
103 continue;
104 }
105 else if (strcasecmp("noprog", argv[0]) == 0)
106 {
107 pttclass &= ~PTT_CL_PGM;
108 continue;
109 }
110 else if (strcasecmp("inter", argv[0]) == 0)
111 {
112 pttclass |= PTT_CL_CSF;
113 continue;
114 }
115 else if (strcasecmp("nointer", argv[0]) == 0)
116 {
117 pttclass &= ~PTT_CL_CSF;
118 continue;
119 }
120 else if (strcasecmp("sie", argv[0]) == 0)
121 {
122 pttclass |= PTT_CL_SIE;
123 continue;
124 }
125 else if (strcasecmp("nosie", argv[0]) == 0)
126 {
127 pttclass &= ~PTT_CL_SIE;
128 continue;
129 }
130 else if (strcasecmp("signal", argv[0]) == 0)
131 {
132 pttclass |= PTT_CL_SIG;
133 continue;
134 }
135 else if (strcasecmp("nosignal", argv[0]) == 0)
136 {
137 pttclass &= ~PTT_CL_SIG;
138 continue;
139 }
140 else if (strcasecmp("io", argv[0]) == 0)
141 {
142 pttclass |= PTT_CL_IO;
143 continue;
144 }
145 else if (strcasecmp("noio", argv[0]) == 0)
146 {
147 pttclass &= ~PTT_CL_IO;
148 continue;
149 }
150 else if (strcasecmp("timer", argv[0]) == 0)
151 {
152 pttclass |= PTT_CL_TMR;
153 continue;
154 }
155 else if (strcasecmp("notimer", argv[0]) == 0)
156 {
157 pttclass &= ~PTT_CL_TMR;
158 continue;
159 }
160 else if (strcasecmp("logger", argv[0]) == 0)
161 {
162 pttclass |= PTT_CL_LOG;
163 continue;
164 }
165 else if (strcasecmp("nologger", argv[0]) == 0)
166 {
167 pttclass &= ~PTT_CL_LOG;
168 continue;
169 }
170 else if (strcasecmp("nothreads", argv[0]) == 0)
171 {
172 pttclass &= ~PTT_CL_THR;
173 continue;
174 }
175 else if (strcasecmp("threads", argv[0]) == 0)
176 {
177 pttclass |= PTT_CL_THR;
178 continue;
179 }
180 else if (strcasecmp("nolock", argv[0]) == 0)
181 {
182 pttnolock = 1;
183 continue;
184 }
185 else if (strcasecmp("lock", argv[0]) == 0)
186 {
187 pttnolock = 0;
188 continue;
189 }
190 else if (strcasecmp("notod", argv[0]) == 0)
191 {
192 pttnotod = 1;
193 continue;
194 }
195 else if (strcasecmp("tod", argv[0]) == 0)
196 {
197 pttnotod = 0;
198 continue;
199 }
200 else if (strcasecmp("nowrap", argv[0]) == 0)
201 {
202 pttnowrap = 1;
203 continue;
204 }
205 else if (strcasecmp("wrap", argv[0]) == 0)
206 {
207 pttnowrap = 0;
208 continue;
209 }
210 else if (strncasecmp("to=", argv[0], 3) == 0 && strlen(argv[0]) > 3
211 && (sscanf(&argv[0][3], "%d%c", &to, &c) == 1 && to >= 0))
212 {
213 pttto = to;
214 continue;
215 }
216 else if (argc == 1 && sscanf(argv[0], "%d%c", &n, &c) == 1 && n >= 0)
217 {
218 OBTAIN_PTTLOCK;
219 if (pttracen == 0)
220 {
221 if (pttrace != NULL)
222 {
223 RELEASE_PTTLOCK;
224 logmsg( _("HHCPT002E Trace is busy\n"));
225 return -1;
226 }
227 }
228 else if (pttrace)
229 {
230 pttracen = 0;
231 RELEASE_PTTLOCK;
232 usleep(1000);
233 OBTAIN_PTTLOCK;
234 free (pttrace);
235 pttrace = NULL;
236 }
237 ptt_trace_init (n, 0);
238 RELEASE_PTTLOCK;
239 }
240 else
241 {
242 logmsg( _("HHCPT001E Invalid value: %s\n"), argv[0]);
243 rc = -1;
244 break;
245 }
246 } /* for each ptt argument */
247
248 /* wakeup timeout thread if to= specified */
249 if (to >= 0 && ptttotid)
250 {
251 obtain_lock (&ptttolock);
252 ptttotid = 0;
253 signal_condition (&ptttocond);
254 release_lock (&ptttolock);
255 }
256
257 /* start timeout thread if positive to= specified */
258 if (to > 0)
259 {
260 obtain_lock (&ptttolock);
261 ptttotid = 0;
262 create_thread (&ptttotid, NULL, ptt_timeout, NULL, "ptt_timeout");
263 release_lock (&ptttolock);
264 }
265 }
266 else
267 {
268 if (pttracen)
269 rc = ptt_pthread_print();
270
271 logmsg( _("HHCPT003I ptt %s%s%s%s%s%s%s%s%s%s%s %s %s to=%d %d\n"),
272 (pttclass & PTT_CL_INF) ? "control " : "",
273 (pttclass & PTT_CL_ERR) ? "error " : "",
274 (pttclass & PTT_CL_PGM) ? "prog " : "",
275 (pttclass & PTT_CL_CSF) ? "inter " : "",
276 (pttclass & PTT_CL_SIE) ? "sie " : "",
277 (pttclass & PTT_CL_SIG) ? "signal " : "",
278 (pttclass & PTT_CL_IO) ? "io " : "",
279 (pttclass & PTT_CL_TMR) ? "timer " : "",
280 (pttclass & PTT_CL_THR) ? "threads " : "",
281 (pttclass & PTT_CL_LOG) ? "logger " : "",
282 pttnolock ? "nolock" : "lock",
283 pttnotod ? "notod" : "tod",
284 pttnowrap ? "nowrap" : "wrap",
285 pttto,
286 pttracen);
287 }
288
289 return rc;
290 }
291
292 /* thread to print trace after timeout */
ptt_timeout()293 void *ptt_timeout()
294 {
295 struct timeval now;
296 struct timespec tm;
297
298 obtain_lock (&ptttolock);
299 gettimeofday (&now, NULL);
300 tm.tv_sec = now.tv_sec + pttto;
301 tm.tv_nsec = now.tv_usec * 1000;
302 timed_wait_condition (&ptttocond, &ptttolock, &tm);
303 if (thread_id() == ptttotid)
304 {
305 ptt_pthread_print();
306 pttto = 0;
307 ptttotid = 0;
308 }
309 release_lock (&ptttolock);
310 return NULL;
311 }
312
313 #ifndef OPTION_FTHREADS
ptt_pthread_mutex_init(LOCK * mutex,pthread_mutexattr_t * attr,char * loc)314 DLL_EXPORT int ptt_pthread_mutex_init(LOCK *mutex, pthread_mutexattr_t *attr, char *loc)
315 {
316 PTTRACE ("lock init", mutex, attr, loc, PTT_MAGIC);
317 return pthread_mutex_init(mutex, attr);
318 }
319
ptt_pthread_mutex_lock(LOCK * mutex,char * loc)320 DLL_EXPORT int ptt_pthread_mutex_lock(LOCK *mutex, char *loc)
321 {
322 int result;
323
324 PTTRACE ("lock before", mutex, NULL, loc, PTT_MAGIC);
325 result = pthread_mutex_lock(mutex);
326 PTTRACE ("lock after", mutex, NULL, loc, result);
327 return result;
328 }
329
ptt_pthread_mutex_trylock(LOCK * mutex,char * loc)330 DLL_EXPORT int ptt_pthread_mutex_trylock(LOCK *mutex, char *loc)
331 {
332 int result;
333
334 PTTRACE ("try before", mutex, NULL, loc, PTT_MAGIC);
335 result = pthread_mutex_trylock(mutex);
336 PTTRACE ("try after", mutex, NULL, loc, result);
337 return result;
338 }
339
ptt_pthread_mutex_unlock(LOCK * mutex,char * loc)340 DLL_EXPORT int ptt_pthread_mutex_unlock(LOCK *mutex, char *loc)
341 {
342 int result;
343
344 result = pthread_mutex_unlock(mutex);
345 PTTRACE ("unlock", mutex, NULL, loc, result);
346 return result;
347 }
348
ptt_pthread_cond_init(COND * cond,pthread_condattr_t * attr,char * loc)349 DLL_EXPORT int ptt_pthread_cond_init(COND *cond, pthread_condattr_t *attr, char *loc)
350 {
351 PTTRACE ("cond init", NULL, cond, loc, PTT_MAGIC);
352 return pthread_cond_init(cond, attr);
353 }
354
ptt_pthread_cond_signal(COND * cond,char * loc)355 DLL_EXPORT int ptt_pthread_cond_signal(COND *cond, char *loc)
356 {
357 int result;
358
359 result = pthread_cond_signal(cond);
360 PTTRACE ("signal", NULL, cond, loc, result);
361 return result;
362 }
363
ptt_pthread_cond_broadcast(COND * cond,char * loc)364 DLL_EXPORT int ptt_pthread_cond_broadcast(COND *cond, char *loc)
365 {
366 int result;
367
368 result = pthread_cond_broadcast(cond);
369 PTTRACE ("broadcast", NULL, cond, loc, result);
370 return result;
371 }
372
ptt_pthread_cond_wait(COND * cond,LOCK * mutex,char * loc)373 DLL_EXPORT int ptt_pthread_cond_wait(COND *cond, LOCK *mutex, char *loc)
374 {
375 int result;
376
377 PTTRACE ("wait before", mutex, cond, loc, PTT_MAGIC);
378 result = pthread_cond_wait(cond, mutex);
379 PTTRACE ("wait after", mutex, cond, loc, result);
380 return result;
381 }
382
ptt_pthread_cond_timedwait(COND * cond,LOCK * mutex,const struct timespec * time,char * loc)383 DLL_EXPORT int ptt_pthread_cond_timedwait(COND *cond, LOCK *mutex,
384 const struct timespec *time, char *loc)
385 {
386 int result;
387
388 PTTRACE ("tw before", mutex, cond, loc, PTT_MAGIC);
389 result = pthread_cond_timedwait(cond, mutex, time);
390 PTTRACE ("tw after", mutex, cond, loc, result);
391 return result;
392 }
393
ptt_pthread_create(pthread_t * tid,ATTR * attr,void * (* start)(),void * arg,char * nm,char * loc)394 DLL_EXPORT int ptt_pthread_create(pthread_t *tid, ATTR *attr,
395 void *(*start)(), void *arg, char *nm, char *loc)
396 {
397 int result;
398 UNREFERENCED(nm);
399
400 result = pthread_create(tid, attr, start, arg);
401 PTTRACE ("create", (void *)*tid, NULL, loc, result);
402 return result;
403 }
404
ptt_pthread_join(pthread_t tid,void ** value,char * loc)405 DLL_EXPORT int ptt_pthread_join(pthread_t tid, void **value, char *loc)
406 {
407 int result;
408
409 PTTRACE ("join before", (void *)tid, value ? *value : NULL, loc, PTT_MAGIC);
410 result = pthread_join(tid,value);
411 PTTRACE ("join after", (void *)tid, value ? *value : NULL, loc, result);
412 return result;
413 }
414
ptt_pthread_detach(pthread_t tid,char * loc)415 DLL_EXPORT int ptt_pthread_detach(pthread_t tid, char *loc)
416 {
417 int result;
418
419 PTTRACE ("dtch before", (void *)tid, NULL, loc, PTT_MAGIC);
420 result = pthread_detach(tid);
421 PTTRACE ("dtch after", (void *)tid, NULL, loc, result);
422 return result;
423 }
424
ptt_pthread_kill(pthread_t tid,int sig,char * loc)425 DLL_EXPORT int ptt_pthread_kill(pthread_t tid, int sig, char *loc)
426 {
427 PTTRACE ("kill", (void *)tid, (void *)(long)sig, loc, PTT_MAGIC);
428 return pthread_kill(tid, sig);
429 }
430 #else /* OPTION_FTHREADS */
ptt_pthread_mutex_init(LOCK * mutex,void * attr,char * loc)431 DLL_EXPORT int ptt_pthread_mutex_init(LOCK *mutex, void *attr, char *loc)
432 {
433 PTTRACE ("lock init", mutex, attr, loc, PTT_MAGIC);
434 return fthread_mutex_init(mutex,attr);
435 }
436
ptt_pthread_mutex_lock(LOCK * mutex,char * loc)437 DLL_EXPORT int ptt_pthread_mutex_lock(LOCK *mutex, char *loc)
438 {
439 int result;
440
441 PTTRACE ("lock before", mutex, NULL, loc, PTT_MAGIC);
442 result = fthread_mutex_lock(mutex);
443 PTTRACE ("lock after", mutex, NULL, loc, result);
444 return result;
445 }
446
ptt_pthread_mutex_trylock(LOCK * mutex,char * loc)447 DLL_EXPORT int ptt_pthread_mutex_trylock(LOCK *mutex, char *loc)
448 {
449 int result;
450
451 PTTRACE ("try before", mutex, NULL, loc, PTT_MAGIC);
452 result = fthread_mutex_trylock(mutex);
453 PTTRACE ("try after", mutex, NULL, loc, result);
454 return result;
455 }
456
ptt_pthread_mutex_unlock(LOCK * mutex,char * loc)457 DLL_EXPORT int ptt_pthread_mutex_unlock(LOCK *mutex, char *loc)
458 {
459 int result;
460
461 result = fthread_mutex_unlock(mutex);
462 PTTRACE ("unlock", mutex, NULL, loc, result);
463 return result;
464 }
465
ptt_pthread_cond_init(COND * cond,void * attr,char * loc)466 DLL_EXPORT int ptt_pthread_cond_init(COND *cond, void *attr, char *loc)
467 {
468 UNREFERENCED(attr);
469 PTTRACE ("cond init", NULL, cond, loc, PTT_MAGIC);
470 return fthread_cond_init(cond);
471 }
472
ptt_pthread_cond_signal(COND * cond,char * loc)473 DLL_EXPORT int ptt_pthread_cond_signal(COND *cond, char *loc)
474 {
475 int result;
476
477 result = fthread_cond_signal(cond);
478 PTTRACE ("signal", NULL, cond, loc, result);
479 return result;
480 }
481
ptt_pthread_cond_broadcast(COND * cond,char * loc)482 DLL_EXPORT int ptt_pthread_cond_broadcast(COND *cond, char *loc)
483 {
484 int result;
485
486 result = fthread_cond_broadcast(cond);
487 PTTRACE ("broadcast", NULL, cond, loc, result);
488 return result;
489 }
490
ptt_pthread_cond_wait(COND * cond,LOCK * mutex,char * loc)491 DLL_EXPORT int ptt_pthread_cond_wait(COND *cond, LOCK *mutex, char *loc)
492 {
493 int result;
494
495 PTTRACE ("wait before", mutex, cond, loc, PTT_MAGIC);
496 result = fthread_cond_wait(cond, mutex);
497 PTTRACE ("wait after", mutex, cond, loc, result);
498 return result;
499 }
500
ptt_pthread_cond_timedwait(COND * cond,LOCK * mutex,struct timespec * time,char * loc)501 DLL_EXPORT int ptt_pthread_cond_timedwait(COND *cond, LOCK *mutex,
502 struct timespec *time, char *loc)
503 {
504 int result;
505
506 PTTRACE ("tw before", mutex, cond, loc, PTT_MAGIC);
507 result = fthread_cond_timedwait(cond, mutex, time);
508 PTTRACE ("tw after", mutex, cond, loc, result);
509 return result;
510 }
511
ptt_pthread_create(fthread_t * tid,ATTR * attr,PFT_THREAD_FUNC start,void * arg,char * nm,char * loc)512 DLL_EXPORT int ptt_pthread_create(fthread_t *tid, ATTR *attr,
513 PFT_THREAD_FUNC start, void *arg, char *nm, char *loc)
514 {
515 int result;
516
517 result = fthread_create(tid, attr, start, arg, nm);
518 PTTRACE ("create", (void *)(uintptr_t)(*tid), NULL, loc, result);
519 return result;
520 }
521
ptt_pthread_join(fthread_t tid,void ** value,char * loc)522 DLL_EXPORT int ptt_pthread_join(fthread_t tid, void **value, char *loc)
523 {
524 int result;
525
526 PTTRACE ("join before", (void *)(uintptr_t)tid, value ? *value : NULL, loc, PTT_MAGIC);
527 result = fthread_join(tid,value);
528 PTTRACE ("join after", (void *)(uintptr_t)tid, value ? *value : NULL, loc, result);
529 return result;
530 }
531
ptt_pthread_detach(fthread_t tid,char * loc)532 DLL_EXPORT int ptt_pthread_detach(fthread_t tid, char *loc)
533 {
534 int result;
535
536 PTTRACE ("dtch before", (void *)(uintptr_t)tid, NULL, loc, PTT_MAGIC);
537 result = fthread_detach(tid);
538 PTTRACE ("dtch after", (void *)(uintptr_t)tid, NULL, loc, result);
539 return result;
540 }
541
ptt_pthread_kill(fthread_t tid,int sig,char * loc)542 DLL_EXPORT int ptt_pthread_kill(fthread_t tid, int sig, char *loc)
543 {
544 PTTRACE ("kill", (void *)(uintptr_t)tid, (void *)(uintptr_t)sig, loc, PTT_MAGIC);
545 return fthread_kill(tid, sig);
546 }
547 #endif
548
ptt_pthread_trace(int class,char * type,void * data1,void * data2,char * loc,int result)549 DLL_EXPORT void ptt_pthread_trace (int class, char * type, void *data1, void *data2,
550 char *loc, int result)
551 {
552 int i, n;
553
554 if (pttrace == NULL || pttracen == 0 || !(pttclass & class) ) return;
555
556 /*
557 ** Fish debug: it appears MSVC sometimes sets the __FILE__ macro
558 ** to a full path filename (rather than just the filename only)
559 ** under certain circumstances. (I think maybe it's only for .h
560 ** files since vstore.h is the one that's messing up). Therefore
561 ** for MSVC we need to convert it to just the filename. ((sigh))
562 */
563 #if defined( _MSVC_ ) // fish debug; appears to be vstore.h
564 // maybe all *.h files are this way??
565 {
566 char* p = strrchr( loc, '\\' );
567 if (!p) p = strrchr( loc, '/' );
568 if (p)
569 loc = p+1;
570 }
571 #endif
572
573 /*
574 * Messages from timer.c, clock.c and/or logger.c are not usually
575 * that interesting and take up table space. Check the flags to
576 * see if we want to trace them.
577 */
578 if (!strncasecmp(loc, "timer.c:", 8) && !(pttclass & PTT_CL_TMR)) return;
579 if (!strncasecmp(loc, "clock.c:", 8) && !(pttclass & PTT_CL_TMR)) return;
580 if (!strncasecmp(loc, "logger.c:", 9) && !(pttclass & PTT_CL_LOG)) return;
581
582 /* check for `nowrap' */
583 if (pttnowrap && pttracex + 1 >= pttracen) return;
584
585 OBTAIN_PTTLOCK;
586 if (pttrace == NULL || (n = pttracen) == 0)
587 {
588 RELEASE_PTTLOCK;
589 return;
590 }
591 i = pttracex++;
592 if (pttracex >= n) pttracex = 0;
593 RELEASE_PTTLOCK;
594 pttrace[i].tid = thread_id();
595 pttrace[i].class = class;
596 pttrace[i].type = type;
597 pttrace[i].data1 = data1;
598 pttrace[i].data2 = data2;
599 pttrace[i].loc = loc;
600 if (pttnotod == 0)
601 gettimeofday(&pttrace[i].tv,NULL);
602 pttrace[i].result = result;
603 }
604
ptt_pthread_print()605 DLL_EXPORT int ptt_pthread_print ()
606 {
607 int i, n, count = 0;
608 char result[32]; // (result is 'int'; if 64-bits, 19 digits or more!)
609 char tbuf[256];
610 time_t tt;
611 const char dot = '.';
612
613 if (pttrace == NULL || pttracen == 0) return count;
614 OBTAIN_PTTLOCK;
615 n = pttracen;
616 pttracen = 0;
617 RELEASE_PTTLOCK;
618
619 i = pttracex;
620 do
621 {
622 if (pttrace[i].tid)
623 {
624 tt = pttrace[i].tv.tv_sec; strcpy(tbuf, ctime(&tt)); tbuf[19] = '\0';
625
626 if (pttrace[i].result == PTT_MAGIC && (pttrace[i].class & PTT_CL_THR))
627 result[0] = '\0';
628 else
629 if((pttrace[i].class & ~PTT_CL_THR))
630 sprintf(result, "%8.8x", pttrace[i].result);
631 else
632 sprintf(result, "%d", pttrace[i].result);
633
634 logmsg
635 (
636 "%8.8"I32_FMT"x " // Thread id (low 32 bits)
637 "%-12.12s " // Trace type (string; 12 chars)
638 PTR_FMTx" " // Data value 1
639 PTR_FMTx" " // Data value 2
640 "%-18.18s " // File name
641 "%s%c%6.6ld " // Time of day (HH:MM:SS.usecs)
642 "%s\n" // Numeric result (or empty string)
643
644 ,(U32)(uintptr_t)(pttrace[i].tid) // Thread id (low 32 bits)
645 ,pttrace[i].type // Trace type (string; 12 chars)
646 ,(uintptr_t)pttrace[i].data1 // Data value 1
647 ,(uintptr_t)pttrace[i].data2 // Data value 2
648 ,pttrace[i].loc // File name
649 ,tbuf + 11 // Time of day (HH:MM:SS)
650 ,dot // Time of day (decimal point)
651 ,pttrace[i].tv.tv_usec // Time of day (microseconds)
652 ,result // Numeric result (or empty string)
653 );
654 count++;
655 }
656 if (++i >= n) i = 0;
657 } while (i != pttracex);
658 memset (pttrace, 0, PTT_TRACE_SIZE * n);
659 pttracex = 0;
660 pttracen = n;
661 return count;
662 }
663
664 #endif
665