prtrace.c (21720B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 /* 7 ** prtrace.c -- NSPR Trace Instrumentation 8 ** 9 ** Implement the API defined in prtrace.h 10 ** 11 ** 12 ** 13 */ 14 15 #include <string.h> 16 #include "primpl.h" 17 18 #define DEFAULT_TRACE_BUFSIZE (1024 * 1024) 19 #define DEFAULT_BUFFER_SEGMENTS 2 20 21 /* 22 ** Enumerate states in a RName structure 23 */ 24 typedef enum TraceState { Running = 1, Suspended = 2 } TraceState; 25 26 /* 27 ** Define QName structure 28 */ 29 typedef struct QName { 30 PRCList link; 31 PRCList rNameList; 32 char name[PRTRACE_NAME_MAX + 1]; 33 } QName; 34 35 /* 36 ** Define RName structure 37 */ 38 typedef struct RName { 39 PRCList link; 40 PRLock* lock; 41 QName* qName; 42 TraceState state; 43 char name[PRTRACE_NAME_MAX + 1]; 44 char desc[PRTRACE_DESC_MAX + 1]; 45 } RName; 46 47 /* 48 ** The Trace Facility database 49 ** 50 */ 51 static PRLogModuleInfo* lm; 52 53 static PRLock* traceLock; /* Facility Lock */ 54 static PRCList qNameList; /* anchor to all QName structures */ 55 static TraceState traceState = Running; 56 57 /* 58 ** in-memory trace buffer controls 59 */ 60 static PRTraceEntry* tBuf; /* pointer to buffer */ 61 static PRInt32 62 bufSize; /* size of buffer, in bytes, rounded up to sizeof(PRTraceEntry) */ 63 static volatile PRInt32 next; /* index to next PRTraceEntry */ 64 static PRInt32 last; /* index of highest numbered trace entry */ 65 66 /* 67 ** Real-time buffer capture controls 68 */ 69 static PRInt32 fetchLastSeen = 0; 70 static PRBool fetchLostData = PR_FALSE; 71 72 /* 73 ** Buffer write-to-file controls 74 */ 75 static PRLock* logLock; /* Sync lock */ 76 static PRCondVar* logCVar; /* Sync Condidtion Variable */ 77 /* 78 ** Inter-thread state communication. 79 ** Controling thread writes to logOrder under protection of logCVar 80 ** the logging thread reads logOrder and sets logState on Notify. 81 ** 82 ** logSegments, logCount, logLostData must be read and written under 83 ** protection of logLock, logCVar. 84 ** 85 */ 86 static enum LogState { 87 LogNotRunning, /* Initial state */ 88 LogReset, /* Causes logger to re-calc controls */ 89 LogActive, /* Logging in progress, set only by log thread */ 90 LogSuspend, /* Suspend Logging */ 91 LogResume, /* Resume Logging => LogActive */ 92 LogStop /* Stop the log thread */ 93 } logOrder, 94 logState, localState; /* controlling state variables */ 95 static PRInt32 logSegments; /* Number of buffer segments */ 96 static PRInt32 logEntries; /* number of Trace Entries in the buffer */ 97 static PRInt32 98 logEntriesPerSegment; /* number of PRTraceEntries per buffer segment */ 99 static PRInt32 logSegSize; /* size of buffer segment */ 100 static PRInt32 logCount; /* number of segments pending output */ 101 static PRInt32 logLostData; /* number of lost log buffer segments */ 102 103 /* 104 ** end Trace Database 105 ** 106 */ 107 108 /* 109 ** _PR_InitializeTrace() -- Initialize the trace facility 110 */ 111 static void NewTraceBuffer(PRInt32 size) { 112 /* 113 ** calculate the size of the buffer 114 ** round down so that each segment has the same number of 115 ** trace entries 116 */ 117 logSegments = DEFAULT_BUFFER_SEGMENTS; 118 logEntries = size / sizeof(PRTraceEntry); 119 logEntriesPerSegment = logEntries / logSegments; 120 logEntries = logSegments * logEntriesPerSegment; 121 bufSize = logEntries * sizeof(PRTraceEntry); 122 logSegSize = logEntriesPerSegment * sizeof(PRTraceEntry); 123 PR_ASSERT(bufSize != 0); 124 PR_LOG(lm, PR_LOG_ERROR, 125 ("NewTraceBuffer: logSegments: %ld, logEntries: %ld, " 126 "logEntriesPerSegment: %ld, logSegSize: %ld", 127 logSegments, logEntries, logEntriesPerSegment, logSegSize)); 128 129 tBuf = PR_Malloc(bufSize); 130 if (tBuf == NULL) { 131 PR_LOG(lm, PR_LOG_ERROR, ("PRTrace: Failed to get trace buffer")); 132 PR_ASSERT(0); 133 } else { 134 PR_LOG(lm, PR_LOG_NOTICE, 135 ("PRTrace: Got trace buffer of size: %ld, at %p", bufSize, tBuf)); 136 } 137 138 next = 0; 139 last = logEntries - 1; 140 logCount = 0; 141 logLostData = PR_TRUE; /* not really on first call */ 142 logOrder = LogReset; 143 144 } /* end NewTraceBuffer() */ 145 146 /* 147 ** _PR_InitializeTrace() -- Initialize the trace facility 148 */ 149 static void _PR_InitializeTrace(void) { 150 /* The lock pointer better be null on this call */ 151 PR_ASSERT(traceLock == NULL); 152 153 traceLock = PR_NewLock(); 154 PR_ASSERT(traceLock != NULL); 155 156 PR_Lock(traceLock); 157 158 PR_INIT_CLIST(&qNameList); 159 160 lm = PR_NewLogModule("trace"); 161 162 bufSize = DEFAULT_TRACE_BUFSIZE; 163 NewTraceBuffer(bufSize); 164 165 /* Initialize logging controls */ 166 logLock = PR_NewLock(); 167 logCVar = PR_NewCondVar(logLock); 168 169 PR_Unlock(traceLock); 170 return; 171 } /* end _PR_InitializeTrace() */ 172 173 /* 174 ** Create a Trace Handle 175 */ 176 PR_IMPLEMENT(PRTraceHandle) 177 PR_CreateTrace(const char* qName, /* QName for this trace handle */ 178 const char* rName, /* RName for this trace handle */ 179 const char* description /* description for this trace handle */ 180 ) { 181 QName* qnp; 182 RName* rnp; 183 PRBool matchQname = PR_FALSE; 184 185 /* Self initialize, if necessary */ 186 if (traceLock == NULL) { 187 _PR_InitializeTrace(); 188 } 189 190 /* Validate input arguments */ 191 PR_ASSERT(strlen(qName) <= PRTRACE_NAME_MAX); 192 PR_ASSERT(strlen(rName) <= PRTRACE_NAME_MAX); 193 PR_ASSERT(strlen(description) <= PRTRACE_DESC_MAX); 194 195 PR_LOG(lm, PR_LOG_DEBUG, 196 ("PRTRACE: CreateTrace: Qname: %s, RName: %s", qName, rName)); 197 198 /* Lock the Facility */ 199 PR_Lock(traceLock); 200 201 /* Do we already have a matching QName? */ 202 if (!PR_CLIST_IS_EMPTY(&qNameList)) { 203 qnp = (QName*)PR_LIST_HEAD(&qNameList); 204 do { 205 if (strcmp(qnp->name, qName) == 0) { 206 matchQname = PR_TRUE; 207 break; 208 } 209 qnp = (QName*)PR_NEXT_LINK(&qnp->link); 210 } while (qnp != (QName*)&qNameList); 211 } 212 /* 213 ** If we did not find a matching QName, 214 ** allocate one and initialize it. 215 ** link it onto the qNameList. 216 ** 217 */ 218 if (matchQname != PR_TRUE) { 219 qnp = PR_NEWZAP(QName); 220 PR_ASSERT(qnp != NULL); 221 PR_INIT_CLIST(&qnp->link); 222 PR_INIT_CLIST(&qnp->rNameList); 223 strcpy(qnp->name, qName); 224 PR_APPEND_LINK(&qnp->link, &qNameList); 225 } 226 227 /* Do we already have a matching RName? */ 228 if (!PR_CLIST_IS_EMPTY(&qnp->rNameList)) { 229 rnp = (RName*)PR_LIST_HEAD(&qnp->rNameList); 230 do { 231 /* 232 ** No duplicate RNames are allowed within a QName 233 ** 234 */ 235 PR_ASSERT(strcmp(rnp->name, rName)); 236 rnp = (RName*)PR_NEXT_LINK(&rnp->link); 237 } while (rnp != (RName*)&qnp->rNameList); 238 } 239 240 /* Get a new RName structure; initialize its members */ 241 rnp = PR_NEWZAP(RName); 242 PR_ASSERT(rnp != NULL); 243 PR_INIT_CLIST(&rnp->link); 244 strcpy(rnp->name, rName); 245 strcpy(rnp->desc, description); 246 rnp->lock = PR_NewLock(); 247 rnp->state = Running; 248 if (rnp->lock == NULL) { 249 PR_ASSERT(0); 250 } 251 252 PR_APPEND_LINK(&rnp->link, &qnp->rNameList); /* add RName to QName's rnList */ 253 rnp->qName = qnp; /* point the RName to the QName */ 254 255 /* Unlock the Facility */ 256 PR_Unlock(traceLock); 257 PR_LOG(lm, PR_LOG_DEBUG, 258 ("PRTrace: Create: QName: %s %p, RName: %s %p\n\t", qName, qnp, rName, 259 rnp)); 260 261 return ((PRTraceHandle)rnp); 262 } /* end PR_CreateTrace() */ 263 264 /* 265 ** 266 */ 267 PR_IMPLEMENT(void) 268 PR_DestroyTrace(PRTraceHandle handle /* Handle to be destroyed */ 269 ) { 270 RName* rnp = (RName*)handle; 271 QName* qnp = rnp->qName; 272 273 PR_LOG(lm, PR_LOG_DEBUG, 274 ("PRTrace: Deleting: QName: %s, RName: %s", qnp->name, rnp->name)); 275 276 /* Lock the Facility */ 277 PR_Lock(traceLock); 278 279 /* 280 ** Remove RName from the list of RNames in QName 281 ** and free RName 282 */ 283 PR_LOG(lm, PR_LOG_DEBUG, ("PRTrace: Deleting RName: %s, %p", rnp->name, rnp)); 284 PR_REMOVE_LINK(&rnp->link); 285 PR_Free(rnp->lock); 286 PR_DELETE(rnp); 287 288 /* 289 ** If this is the last RName within QName 290 ** remove QName from the qNameList and free it 291 */ 292 if (PR_CLIST_IS_EMPTY(&qnp->rNameList)) { 293 PR_LOG(lm, PR_LOG_DEBUG, 294 ("PRTrace: Deleting unused QName: %s, %p", qnp->name, qnp)); 295 PR_REMOVE_LINK(&qnp->link); 296 PR_DELETE(qnp); 297 } 298 299 /* Unlock the Facility */ 300 PR_Unlock(traceLock); 301 return; 302 } /* end PR_DestroyTrace() */ 303 304 /* 305 ** Create a TraceEntry in the trace buffer 306 */ 307 PR_IMPLEMENT(void) 308 PR_Trace(PRTraceHandle handle, /* use this trace handle */ 309 PRUint32 userData0, /* User supplied data word 0 */ 310 PRUint32 userData1, /* User supplied data word 1 */ 311 PRUint32 userData2, /* User supplied data word 2 */ 312 PRUint32 userData3, /* User supplied data word 3 */ 313 PRUint32 userData4, /* User supplied data word 4 */ 314 PRUint32 userData5, /* User supplied data word 5 */ 315 PRUint32 userData6, /* User supplied data word 6 */ 316 PRUint32 userData7 /* User supplied data word 7 */ 317 ) { 318 PRTraceEntry* tep; 319 PRInt32 mark; 320 321 if ((traceState == Suspended) || (((RName*)handle)->state == Suspended)) { 322 return; 323 } 324 325 /* 326 ** Get the next trace entry slot w/ minimum delay 327 */ 328 PR_Lock(traceLock); 329 330 tep = &tBuf[next++]; 331 if (next > last) { 332 next = 0; 333 } 334 if (fetchLostData == PR_FALSE && next == fetchLastSeen) { 335 fetchLostData = PR_TRUE; 336 } 337 338 mark = next; 339 340 PR_Unlock(traceLock); 341 342 /* 343 ** We have a trace entry. Fill it in. 344 */ 345 tep->thread = PR_GetCurrentThread(); 346 tep->handle = handle; 347 tep->time = PR_Now(); 348 tep->userData[0] = userData0; 349 tep->userData[1] = userData1; 350 tep->userData[2] = userData2; 351 tep->userData[3] = userData3; 352 tep->userData[4] = userData4; 353 tep->userData[5] = userData5; 354 tep->userData[6] = userData6; 355 tep->userData[7] = userData7; 356 357 /* When buffer segment is full, signal trace log thread to run */ 358 if ((mark % logEntriesPerSegment) == 0) { 359 PR_Lock(logLock); 360 logCount++; 361 PR_NotifyCondVar(logCVar); 362 PR_Unlock(logLock); 363 /* 364 ** Gh0D! This is awful! 365 ** Anyway, to minimize lost trace data segments, 366 ** I inserted the PR_Sleep(0) to cause a context switch 367 ** so that the log thread could run. 368 ** I know, it perturbs the universe and may cause 369 ** funny things to happen in the optimized builds. 370 ** Take it out, lose data; leave it in risk Heisenberg. 371 */ 372 /* PR_Sleep(0); */ 373 } 374 375 return; 376 } /* end PR_Trace() */ 377 378 /* 379 ** 380 */ 381 PR_IMPLEMENT(void) 382 PR_SetTraceOption(PRTraceOption command, /* One of the enumerated values */ 383 void* value /* command value or NULL */ 384 ) { 385 RName* rnp; 386 387 switch (command) { 388 case PRTraceBufSize: 389 PR_Lock(traceLock); 390 PR_Free(tBuf); 391 bufSize = *(PRInt32*)value; 392 NewTraceBuffer(bufSize); 393 PR_Unlock(traceLock); 394 PR_LOG(lm, PR_LOG_DEBUG, 395 ("PRSetTraceOption: PRTraceBufSize: %ld", bufSize)); 396 break; 397 398 case PRTraceEnable: 399 rnp = *(RName**)value; 400 rnp->state = Running; 401 PR_LOG(lm, PR_LOG_DEBUG, ("PRSetTraceOption: PRTraceEnable: %p", rnp)); 402 break; 403 404 case PRTraceDisable: 405 rnp = *(RName**)value; 406 rnp->state = Suspended; 407 PR_LOG(lm, PR_LOG_DEBUG, ("PRSetTraceOption: PRTraceDisable: %p", rnp)); 408 break; 409 410 case PRTraceSuspend: 411 traceState = Suspended; 412 PR_LOG(lm, PR_LOG_DEBUG, ("PRSetTraceOption: PRTraceSuspend")); 413 break; 414 415 case PRTraceResume: 416 traceState = Running; 417 PR_LOG(lm, PR_LOG_DEBUG, ("PRSetTraceOption: PRTraceResume")); 418 break; 419 420 case PRTraceSuspendRecording: 421 PR_Lock(logLock); 422 logOrder = LogSuspend; 423 PR_NotifyCondVar(logCVar); 424 PR_Unlock(logLock); 425 PR_LOG(lm, PR_LOG_DEBUG, ("PRSetTraceOption: PRTraceSuspendRecording")); 426 break; 427 428 case PRTraceResumeRecording: 429 PR_LOG(lm, PR_LOG_DEBUG, ("PRSetTraceOption: PRTraceResumeRecording")); 430 if (logState != LogSuspend) { 431 break; 432 } 433 PR_Lock(logLock); 434 logOrder = LogResume; 435 PR_NotifyCondVar(logCVar); 436 PR_Unlock(logLock); 437 break; 438 439 case PRTraceStopRecording: 440 PR_Lock(logLock); 441 logOrder = LogStop; 442 PR_NotifyCondVar(logCVar); 443 PR_Unlock(logLock); 444 PR_LOG(lm, PR_LOG_DEBUG, ("PRSetTraceOption: PRTraceStopRecording")); 445 break; 446 447 case PRTraceLockHandles: 448 PR_LOG(lm, PR_LOG_DEBUG, ("PRSetTraceOption: PRTraceLockTraceHandles")); 449 PR_Lock(traceLock); 450 break; 451 452 case PRTraceUnLockHandles: 453 PR_LOG(lm, PR_LOG_DEBUG, ("PRSetTraceOption: PRTraceUnLockHandles")); 454 PR_Unlock(traceLock); 455 break; 456 457 default: 458 PR_LOG(lm, PR_LOG_ERROR, 459 ("PRSetTraceOption: Invalid command %ld", command)); 460 PR_ASSERT(0); 461 break; 462 } /* end switch() */ 463 return; 464 } /* end PR_SetTraceOption() */ 465 466 /* 467 ** 468 */ 469 PR_IMPLEMENT(void) 470 PR_GetTraceOption(PRTraceOption command, /* One of the enumerated values */ 471 void* value /* command value or NULL */ 472 ) { 473 switch (command) { 474 case PRTraceBufSize: 475 *((PRInt32*)value) = bufSize; 476 PR_LOG(lm, PR_LOG_DEBUG, 477 ("PRGetTraceOption: PRTraceBufSize: %ld", bufSize)); 478 break; 479 480 default: 481 PR_LOG(lm, PR_LOG_ERROR, 482 ("PRGetTraceOption: Invalid command %ld", command)); 483 PR_ASSERT(0); 484 break; 485 } /* end switch() */ 486 return; 487 } /* end PR_GetTraceOption() */ 488 489 /* 490 ** 491 */ 492 PR_IMPLEMENT(PRTraceHandle) 493 PR_GetTraceHandleFromName(const char* qName, /* QName search argument */ 494 const char* rName /* RName search argument */ 495 ) { 496 const char *qn, *rn, *desc; 497 PRTraceHandle qh, rh = NULL; 498 RName* rnp = NULL; 499 500 PR_LOG(lm, PR_LOG_DEBUG, 501 ("PRTrace: GetTraceHandleFromName:\n\t" 502 "QName: %s, RName: %s", 503 qName, rName)); 504 505 qh = PR_FindNextTraceQname(NULL); 506 while (qh != NULL) { 507 rh = PR_FindNextTraceRname(NULL, qh); 508 while (rh != NULL) { 509 PR_GetTraceNameFromHandle(rh, &qn, &rn, &desc); 510 if ((strcmp(qName, qn) == 0) && (strcmp(rName, rn) == 0)) { 511 rnp = (RName*)rh; 512 goto foundIt; 513 } 514 rh = PR_FindNextTraceRname(rh, qh); 515 } 516 qh = PR_FindNextTraceQname(NULL); 517 } 518 519 foundIt: 520 PR_LOG(lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp)); 521 return (rh); 522 } /* end PR_GetTraceHandleFromName() */ 523 524 /* 525 ** 526 */ 527 PR_IMPLEMENT(void) 528 PR_GetTraceNameFromHandle( 529 PRTraceHandle handle, /* handle as search argument */ 530 const char** qName, /* pointer to associated QName */ 531 const char** rName, /* pointer to associated RName */ 532 const char** description /* pointer to associated description */ 533 ) { 534 RName* rnp = (RName*)handle; 535 QName* qnp = rnp->qName; 536 537 *qName = qnp->name; 538 *rName = rnp->name; 539 *description = rnp->desc; 540 541 PR_LOG(lm, PR_LOG_DEBUG, 542 ("PRTrace: GetConterNameFromHandle: " 543 "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s", 544 qnp, rnp, qnp->name, rnp->name, rnp->desc)); 545 546 return; 547 } /* end PR_GetTraceNameFromHandle() */ 548 549 /* 550 ** 551 */ 552 PR_IMPLEMENT(PRTraceHandle) 553 PR_FindNextTraceQname(PRTraceHandle handle) { 554 QName* qnp = (QName*)handle; 555 556 if (PR_CLIST_IS_EMPTY(&qNameList)) { 557 qnp = NULL; 558 } else if (qnp == NULL) { 559 qnp = (QName*)PR_LIST_HEAD(&qNameList); 560 } else if (PR_NEXT_LINK(&qnp->link) == &qNameList) { 561 qnp = NULL; 562 } else { 563 qnp = (QName*)PR_NEXT_LINK(&qnp->link); 564 } 565 566 PR_LOG(lm, PR_LOG_DEBUG, 567 ("PRTrace: FindNextQname: Handle: %p, Returns: %p", handle, qnp)); 568 569 return ((PRTraceHandle)qnp); 570 } /* end PR_FindNextTraceQname() */ 571 572 /* 573 ** 574 */ 575 PR_IMPLEMENT(PRTraceHandle) 576 PR_FindNextTraceRname(PRTraceHandle rhandle, PRTraceHandle qhandle) { 577 RName* rnp = (RName*)rhandle; 578 QName* qnp = (QName*)qhandle; 579 580 if (PR_CLIST_IS_EMPTY(&qnp->rNameList)) { 581 rnp = NULL; 582 } else if (rnp == NULL) { 583 rnp = (RName*)PR_LIST_HEAD(&qnp->rNameList); 584 } else if (PR_NEXT_LINK(&rnp->link) == &qnp->rNameList) { 585 rnp = NULL; 586 } else { 587 rnp = (RName*)PR_NEXT_LINK(&rnp->link); 588 } 589 590 PR_LOG(lm, PR_LOG_DEBUG, 591 ("PRTrace: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p", 592 rhandle, qhandle, rnp)); 593 594 return ((PRTraceHandle)rnp); 595 } /* end PR_FindNextTraceRname() */ 596 597 /* 598 ** 599 */ 600 static PRFileDesc* InitializeRecording(void) { 601 char* logFileName; 602 PRFileDesc* logFile; 603 604 /* Self initialize, if necessary */ 605 if (traceLock == NULL) { 606 _PR_InitializeTrace(); 607 } 608 609 PR_LOG(lm, PR_LOG_DEBUG, ("PR_RecordTraceEntries: begins")); 610 611 logLostData = 0; /* reset at entry */ 612 logState = LogReset; 613 614 /* Get the filename for the logfile from the environment */ 615 logFileName = PR_GetEnvSecure("NSPR_TRACE_LOG"); 616 if (logFileName == NULL) { 617 PR_LOG(lm, PR_LOG_ERROR, 618 ("RecordTraceEntries: Environment variable not defined. Exiting")); 619 return NULL; 620 } 621 622 /* Open the logfile */ 623 logFile = PR_Open(logFileName, PR_WRONLY | PR_CREATE_FILE, 0666); 624 if (logFile == NULL) { 625 PR_LOG( 626 lm, PR_LOG_ERROR, 627 ("RecordTraceEntries: Cannot open %s as trace log file. OS error: %ld", 628 logFileName, PR_GetOSError())); 629 return NULL; 630 } 631 return logFile; 632 } /* end InitializeRecording() */ 633 634 /* 635 ** 636 */ 637 static void ProcessOrders(void) { 638 switch (logOrder) { 639 case LogReset: 640 logOrder = logState = localState; 641 PR_LOG(lm, PR_LOG_DEBUG, ("RecordTraceEntries: LogReset")); 642 break; 643 644 case LogSuspend: 645 localState = logOrder = logState = LogSuspend; 646 PR_LOG(lm, PR_LOG_DEBUG, ("RecordTraceEntries: LogSuspend")); 647 break; 648 649 case LogResume: 650 localState = logOrder = logState = LogActive; 651 PR_LOG(lm, PR_LOG_DEBUG, ("RecordTraceEntries: LogResume")); 652 break; 653 654 case LogStop: 655 logOrder = logState = LogStop; 656 PR_LOG(lm, PR_LOG_DEBUG, ("RecordTraceEntries: LogStop")); 657 break; 658 659 default: 660 PR_LOG(lm, PR_LOG_ERROR, 661 ("RecordTraceEntries: Invalid logOrder: %ld", logOrder)); 662 PR_ASSERT(0); 663 break; 664 } /* end switch() */ 665 return; 666 } /* end ProcessOrders() */ 667 668 /* 669 ** 670 */ 671 static void WriteTraceSegment(PRFileDesc* logFile, void* buf, PRInt32 amount) { 672 PRInt32 rc; 673 674 PR_LOG(lm, PR_LOG_ERROR, 675 ("WriteTraceSegment: Buffer: %p, Amount: %ld", buf, amount)); 676 rc = PR_Write(logFile, buf, amount); 677 if (rc == -1) 678 PR_LOG( 679 lm, PR_LOG_ERROR, 680 ("RecordTraceEntries: PR_Write() failed. Error: %ld", PR_GetError())); 681 else if (rc != amount) 682 PR_LOG(lm, PR_LOG_ERROR, 683 ("RecordTraceEntries: PR_Write() Tried to write: %ld, Wrote: %ld", 684 amount, rc)); 685 else 686 PR_LOG(lm, PR_LOG_DEBUG, 687 ("RecordTraceEntries: PR_Write(): Buffer: %p, bytes: %ld", buf, 688 amount)); 689 690 return; 691 } /* end WriteTraceSegment() */ 692 693 /* 694 ** 695 */ 696 PR_IMPLEMENT(void) 697 PR_RecordTraceEntries(void) { 698 PRFileDesc* logFile; 699 PRInt32 lostSegments; 700 PRInt32 currentSegment = 0; 701 void* buf; 702 PRBool doWrite; 703 704 logFile = InitializeRecording(); 705 if (logFile == NULL) { 706 PR_LOG(lm, PR_LOG_DEBUG, ("PR_RecordTraceEntries: Failed to initialize")); 707 return; 708 } 709 710 /* Do this until told to stop */ 711 while (logState != LogStop) { 712 PR_Lock(logLock); 713 714 while ((logCount == 0) && (logOrder == logState)) { 715 PR_WaitCondVar(logCVar, PR_INTERVAL_NO_TIMEOUT); 716 } 717 718 /* Handle state transitions */ 719 if (logOrder != logState) { 720 ProcessOrders(); 721 } 722 723 /* recalculate local controls */ 724 if (logCount) { 725 lostSegments = logCount - logSegments; 726 if (lostSegments > 0) { 727 logLostData += (logCount - logSegments); 728 logCount = (logCount % logSegments); 729 currentSegment = logCount; 730 PR_LOG(lm, PR_LOG_DEBUG, 731 ("PR_RecordTraceEntries: LostData segments: %ld", logLostData)); 732 } else { 733 logCount--; 734 } 735 736 buf = tBuf + (logEntriesPerSegment * currentSegment); 737 if (++currentSegment >= logSegments) { 738 currentSegment = 0; 739 } 740 doWrite = PR_TRUE; 741 } else { 742 doWrite = PR_FALSE; 743 } 744 745 PR_Unlock(logLock); 746 747 if (doWrite == PR_TRUE) { 748 if (localState != LogSuspend) { 749 WriteTraceSegment(logFile, buf, logSegSize); 750 } else 751 PR_LOG(lm, PR_LOG_DEBUG, 752 ("RecordTraceEntries: PR_Write(): is suspended")); 753 } 754 755 } /* end while(logState...) */ 756 757 PR_Close(logFile); 758 PR_LOG(lm, PR_LOG_DEBUG, ("RecordTraceEntries: exiting")); 759 return; 760 } /* end PR_RecordTraceEntries() */ 761 762 /* 763 ** 764 */ 765 PR_IMPLEMENT(PRIntn) 766 PR_GetTraceEntries(PRTraceEntry* buffer, /* where to write output */ 767 PRInt32 count, /* number to get */ 768 PRInt32* found /* number you got */ 769 ) { 770 PRInt32 rc; 771 PRInt32 copied = 0; 772 773 PR_Lock(traceLock); 774 775 /* 776 ** Depending on where the LastSeen and Next indices are, 777 ** copy the trace buffer in one or two pieces. 778 */ 779 PR_LOG(lm, PR_LOG_ERROR, 780 ("PR_GetTraceEntries: Next: %ld, LastSeen: %ld", next, fetchLastSeen)); 781 782 if (fetchLastSeen <= next) { 783 while ((count-- > 0) && (fetchLastSeen < next)) { 784 *(buffer + copied++) = *(tBuf + fetchLastSeen++); 785 } 786 PR_LOG(lm, PR_LOG_ERROR, 787 ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, 788 fetchLastSeen)); 789 } else /* copy in 2 parts */ 790 { 791 while (count-- > 0 && fetchLastSeen <= last) { 792 *(buffer + copied++) = *(tBuf + fetchLastSeen++); 793 } 794 fetchLastSeen = 0; 795 796 PR_LOG(lm, PR_LOG_ERROR, 797 ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, 798 fetchLastSeen)); 799 800 while (count-- > 0 && fetchLastSeen < next) { 801 *(buffer + copied++) = *(tBuf + fetchLastSeen++); 802 } 803 PR_LOG(lm, PR_LOG_ERROR, 804 ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, 805 fetchLastSeen)); 806 } 807 808 *found = copied; 809 rc = (fetchLostData == PR_TRUE) ? 1 : 0; 810 fetchLostData = PR_FALSE; 811 812 PR_Unlock(traceLock); 813 return rc; 814 } /* end PR_GetTraceEntries() */ 815 816 /* end prtrace.c */