/////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2006 Intel Corporation // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither name of Intel Corporation nor the names of its contributors // may be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////// #include #include #include #include // Global data where current data sample is stored static int m_global = 0; // hMutex is the synchronization mechanism that // protects the global data static CRITICAL_SECTION hLock; // Circular 1K Trace buffer #define TRACE_BUFFER_SIZE 1024 typedef struct traceBufferElement { DWORD threadId; time_t timestamp; const char *msg; } traceBufferElement; static LONG m_TraceBufferIdx = -1; static traceBufferElement traceBuffer[TRACE_BUFFER_SIZE]; void InitializeTraceBuffer() { m_TraceBufferIdx = -1; /* initialize all entries to {0, 0, ""} */ memset(traceBuffer, 0, TRACE_BUFFER_SIZE*sizeof(traceBufferElement)); } void AddEntryToTraceBuffer(const char *msg) { LONG idx = 0; // Get the index into the trace buffer that this thread should use idx = InterlockedIncrement(&m_TraceBufferIdx) % TRACE_BUFFER_SIZE; // Enter the data into the Trace Buffer traceBuffer[idx].threadId = GetCurrentThreadId(); traceBuffer[idx].timestamp = time(NULL); traceBuffer[idx].msg = msg; } void PrintTraceBuffer() { int i; printf("Thread ID Timestamp Msg\n"); printf("----------|----------|---------------------------------------\n"); for (i = 0; i < TRACE_BUFFER_SIZE; i++) { if (traceBuffer[i].timestamp == 0) { break; } printf("0x%8.8x|0x%8.8x| %s\n", traceBuffer[i].threadId, traceBuffer[i].timestamp, traceBuffer[i].msg); } } // These values are used by RaiseException // To associate a name with a given thread // The specific values are defined by Microsoft #define NAME_THREAD_EXCEPTION_CODE 0x406D1388 #define NAME_THREAD_TYPE 0x1000 #define RESERVED 0x0 typedef struct threadProperties { DWORD dwType; LPCSTR szThreadName; // name of thread DWORD dwThreadID; // thread ID DWORD dwFlags; } threadProperties; void SetThreadName(DWORD tid, LPCSTR name) { threadProperties prop; prop.dwThreadID = tid; prop.szThreadName = name; prop.dwType = NAME_THREAD_TYPE; prop.dwFlags = RESERVED; // Reserved by Microsoft __try { RaiseException(NAME_THREAD_EXCEPTION_CODE, 0, sizeof(prop)/sizeof(DWORD), (DWORD *)&prop); } __except(EXCEPTION_CONTINUE_EXECUTION) { } } void init_daq() { srand((unsigned int)time(NULL)); } // Simple simulation of random data void sample_data() { EnterCriticalSection(&hLock); m_global = rand(); // check for data error if ((m_global % (2<<14)) == 0) { // handle error LeaveCriticalSection(&hLock); return; } LeaveCriticalSection(&hLock); } // This function is an example // of what can be done to data // after collection // In this case, we update the display // in real time void process_data() { EnterCriticalSection(&hLock); printf("m_global = 0x%x\n", m_global); LeaveCriticalSection(&hLock); } // Producer thread to simulate real time // data acquisition. Collect 30 s // worth of data unsigned __stdcall Thread1(void *) { int count = 0; SetThreadName(-1, "Producer"); while (1) { // update the data AddEntryToTraceBuffer("Producer: before" " sample_data"); sample_data(); AddEntryToTraceBuffer("Producer: after" " sample_data"); Sleep(1000); count++; if (count > 30) break; } return 0; } // Consumer thread // Collect data when scheduled and // process it. Read 30 s worth of data unsigned __stdcall Thread2(void *) { int count = 0; SetThreadName(-1, "Consumer"); while (1) { AddEntryToTraceBuffer("Consumer: before" " process_data()"); process_data(); AddEntryToTraceBuffer("Consumer: after" " process_data()"); Sleep(1000); count++; if (count > 30) break; } return 0; } int main(int argc, char **argv) { // Create two threads named Thread1 and Thread2 HANDLE hThread1, hThread2; unsigned int threadID1, threadID2; InitializeTraceBuffer(); // Initialize the data acqusition device init_daq(); // Initialize the lock InitializeCriticalSection(&hLock); hThread1 = (HANDLE)_beginthreadex(NULL, 0, &Thread1, NULL, 0, &threadID1); hThread2 = (HANDLE)_beginthreadex(NULL, 0, &Thread2, NULL, 0, &threadID2); WaitForSingleObject(hThread1, INFINITE); WaitForSingleObject(hThread2, INFINITE); DeleteCriticalSection(&hLock); // Print the log of thread accesses PrintTraceBuffer(); printf("-------------------------------------\n"); printf("End of daq\n"); return 0; }