/* * ======== traceThrFxn ======== */ static void *traceThrFxn(void *arg) { String engineName = (String) arg; Server_Status status; FILE *f; IArg key; /* determine DSP line prefix: "[DSP] " if local and DSP trace end up at the same * file, otherwise "" */ char *dspPrefix = (dsp0TraceFilePtr == localTraceFilePtr) ? "[DSP] " : ""; DBG("Trace thread started\n"); hEngine = Engine_open(engineName, NULL, NULL); if (hEngine == NULL) { ERR("Failed to open codec engine \"%s\"\n", engineName); threadCreateFailed = TRUE; return ((void *) -1); } /* for multi-process situations, make sure can acquire server trace */ if (Global_useLinkArbiter) { /* get server handle */ hServer = Engine_getServer(hEngine); /* cleanup and abort if can't get server handle */ if (hServer == NULL) { Engine_close(hEngine); ERR("Failed to get server handle\n"); threadCreateFailed = TRUE; return ((void *) -1); } /* request server trace token */ status = Server_connectTrace(hServer, &traceToken); /* cleanup and abort if trace could not acquire trace token */ if (status != Server_EOK) { Engine_close(hEngine); ERR("Failed to connect for server trace\n"); threadCreateFailed = TRUE; return ((void *) -1); } } /* else: if single-process, don't need to explictly connect for trace */ Engine_setTrace(hEngine, dsp0mask); /* create the pipe thread now */ if (cmdPipeFile != NULL && cmdPipeFile[0] != '\0') { if (pthread_create(&pipeThread, NULL, pipeThrFxn, NULL)) { ERR("Failed to create pipe thread\n"); } else { /* run the thread just created so it can immediately execute * pending cmdPipe trace commands -- in case there are any */ while (pipeThreadCreated == FALSE) { sched_yield(); } } } /* TODO: remove? will LogClient_connect be inside CE? */ /* * Note, call LogClient_connect() before releasing the main thread to * avoid context switching away _during_ the connect() call - which could * result in a skewed timesynch log. */ if (dsp0BiosFilePtr != NULL) { // LogClient_connect(); } /* Release the spinning main thread to run */ traceThreadCreated = TRUE; while (!quit) { if (refresh > 0) { DBG("Writing DSP logs\n"); key = Gate_enterModule(); Engine_fwriteTrace(hEngine, dspPrefix, dsp0TraceFilePtr); if (dsp0BiosFilePtr != NULL) { // LogClient_fwriteLogs(dsp0BiosFilePtr); } Gate_leaveModule(key); DBG("Sleeping for %d us\n", refresh); usleep(refresh); } else { DBG("Sleeping for %d us\n", SLEEPWHENNOREFRESH); usleep( SLEEPWHENNOREFRESH ); } } if (refresh > 0) { DBG("Trace thread exiting, writing final DSP logs\n"); /* try to collect anything that remained one more time */ key = Gate_enterModule(); Engine_fwriteTrace(hEngine, dspPrefix, dsp0TraceFilePtr); if (dsp0BiosFilePtr != NULL) { // LogClient_fwriteLogs(dsp0BiosFilePtr); } Gate_leaveModule(key); } if (dsp0BiosFilePtr != NULL) { // LogClient_disconnect(); } /* for multi-process situations, release trace token back to RMS */ if (Global_useLinkArbiter) { Server_disconnectTrace(hServer, traceToken); } Engine_close(hEngine); DBG("Quitting trace thread\n"); /* and killing our offspring. */ if (pipeThread != NULL) { DBG("Telling pipe thread to quit\n"); f = fopen(cmdPipeFile, "w"); if (f != NULL) { fputs(TRACECMD_QUIT, f); fclose(f); DBG("Wrote quit command, waiting for the pipe thread to join\n"); if (pthread_join(pipeThread, NULL)) { ERR("Failed to join pipe thread\n"); } DBG("Pipe thread joined.\n"); } } return ((void *) 1); }
/* * ======== smain ======== */ Int smain(Int argc, String argv[]) { Char newTraceMask[MAXTRACESTRING]; Server_Handle server = NULL; Bool finished = FALSE; Uns mode = PULLTRACE; Server_Status status; Int traceToken; String mask; Uns rate; /* interpret PULLTRACE mode args */ if (argc == 3) { rate = atoi(argv[1]); mask = argv[2]; } /* else, if no args, set mode to TRACEUTIL */ else if (argc == 1) { mode = TRACEUTIL; } /* else, show usage */ else { fprintf(stderr, usage, argv[0]); goto done; } /* reset, load, and start DSP Engine */ if ((engine = Engine_open(engineName, NULL, NULL)) == NULL) { fprintf(stderr, "Error: can't open engine %s!\n", engineName); goto done; } /* setup file descriptor mask for checking for user key input */ FD_ZERO(&fdMask); FD_SET(STDIN_FILENO, &fdMask); /* if standard output mode... */ if (mode == PULLTRACE) { printf("Trace polling rate: %d msec\n", rate); rate *= 1000; printf("DSP trace mask: %s\n", mask); /* get server handle */ server = Engine_getServer(engine); if (server == NULL) { fprintf(stderr, "Error: can't get server handle!\n"); goto closeEngine; } /* connect for server trace data */ status = Server_connectTrace(server, &traceToken); if (status == Server_EINUSE) { fprintf(stderr, "Error: server trace already in use by another process!\n"); goto closeEngine; } else if (status != Server_EOK) { fprintf(stderr, "Error: server connect failed, status = 0x%x!\n", status); goto closeEngine; } /* server trace mask */ status = Server_setTrace(server, mask); if (status != (Int) Engine_EOK) { fprintf(stderr, "Error: unable to set trace mask, status = 0x%x!\n", status); goto closeEngine; } printf("Hit <Enter> to exit, or, new trace mask and then <Enter>...\n"); while (finished == FALSE) { dumpTrace(server); usleep(rate); if (checkInput(newTraceMask) == TRUE) { if (strlen(newTraceMask) == 0) { finished = TRUE; } else { printf("setting new trace mask: %s\n", newTraceMask); status = Server_setTrace(server, newTraceMask); if (status != (Int) Engine_EOK) { fprintf(stderr, "Error updating trace mask, status = 0x%x!\n", status); } } } }; /* discconnect from server trace data */ status = Server_disconnectTrace(server, traceToken); if (status != Server_EOK) { fprintf(stderr, "Error: unable to disconnect from server trace, status = 0x%x!\n", status); } } /* else, startup TraceUtil to retrieve trace/LOG data and write to files */ else { TraceUtil_start(engineName); printf("Started TraceUtil thread\nHit <Enter> to exit...\n"); getchar(); TraceUtil_stop(); } printf("Done.\n"); closeEngine: /* close the engine */ if (engine) { Engine_close(engine); } done: return (0); }