]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/arm-ds5-gator.git/blob - daemon/Child.cpp
gator-driver: Disable event-base sampling support
[android-sdk/arm-ds5-gator.git] / daemon / Child.cpp
1 /**
2  * Copyright (C) ARM Limited 2010-2011. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
9 #include <stdlib.h>
10 #include <string.h>
11 #include <signal.h>
12 #include <sys/syscall.h>
13 #include <sys/resource.h>
14 #include <unistd.h>
15 #include <sys/prctl.h>
16 #include "Logging.h"
17 #include "CapturedXML.h"
18 #include "SessionData.h"
19 #include "Child.h"
20 #include "LocalCapture.h"
21 #include "Collector.h"
22 #include "Sender.h"
23 #include "OlyUtility.h"
24 #include "StreamlineSetup.h"
26 static sem_t haltPipeline, senderThreadStarted, startProfile; // Shared by Child and spawned threads
27 static Fifo* collectorFifo = NULL;   // Shared by Child.cpp and spawned threads
28 static Sender* sender = NULL;        // Shared by Child.cpp and spawned threads
29 Collector* collector = NULL;         // shared by Child.cpp and ConfigurationXML.cpp
30 Child* child = NULL;                 // shared by Child.cpp and main.cpp
32 extern void cleanUp();
33 void handleException() {
34         if (child && child->numExceptions++ > 0) {
35                 // it is possible one of the below functions itself can cause an exception, thus allow only one exception
36                 logg->logMessage("Received multiple exceptions, terminating the child");
37                 exit(1);
38         }
39         fprintf(stderr, "%s", logg->getLastError());
41         if (child && child->socket) {
42                 if (sender) {
43                         // send the error, regardless of the command sent by Streamline
44                         sender->writeData(logg->getLastError(), strlen(logg->getLastError()), RESPONSE_ERROR);
46                         // cannot close the socket before Streamline issues the command, so wait for the command before exiting
47                         if (gSessionData.mWaitingOnCommand) {
48                                 char discard;
49                                 child->socket->receiveNBytes(&discard, 1);
50                         }
52                         // this indirectly calls close socket which will ensure the data has been sent
53                         delete sender;
54                 }
55         }
57         if (gSessionData.mLocalCapture)
58                 cleanUp();
60         exit(1);
61 }
63 // CTRL C Signal Handler for child process
64 void child_handler(int signum) {
65         static bool beenHere = false;
66         if (beenHere == true) {
67                 logg->logMessage("Gator is being forced to shut down.");
68                 exit(1);
69         }
70         beenHere = true;
71         logg->logMessage("Gator is shutting down.");
72         if (signum == SIGALRM || !collector) {
73                 exit(1);
74         } else {
75                 child->endSession();
76                 alarm(5); // Safety net in case endSession does not complete within 5 seconds
77         }
78 }
80 void* durationThread(void* pVoid) {
81         prctl(PR_SET_NAME, (unsigned int)&"gatord-duration", 0, 0, 0);
82         sem_wait(&startProfile);
83         if (gSessionData.mSessionIsActive) {
84                 // Time out after duration seconds
85                 // Add a second for host-side filtering
86                 sleep(gSessionData.mDuration + 1);
87                 if (gSessionData.mSessionIsActive) {
88                         logg->logMessage("Duration expired.");
89                         child->endSession();
90                 }
91         }
92         logg->logMessage("Exit duration thread");
93         return 0;
94 }
96 void* stopThread(void* pVoid) {
97         int length;
98         char type;
99         OlySocket* socket = child->socket;
101         prctl(PR_SET_NAME, (unsigned int)&"gatord-stopper", 0, 0, 0);
102         while (gSessionData.mSessionIsActive) {
103                 // This thread will stall until the APC_STOP or PING command is received over the socket or the socket is disconnected
104                 if (socket->receiveNBytes(&type, sizeof(type)) > 0) {
105                         if ((type != COMMAND_APC_STOP) && (type != COMMAND_PING)) {
106                                 logg->logMessage("INVESTIGATE: Received unknown command type %d", type);
107                         } else {
108                                 // verify a length of zero
109                                 if (socket->receiveNBytes((char*)&length, sizeof(length)) < 0) {
110                                         break;
111                                 }
113                                 if (length == 0) {
114                                         if (type == COMMAND_APC_STOP) {
115                                                 logg->logMessage("Stop command received.");
116                                                 child->endSession();
117                                         } else {
118                                                 // Ping is used to make sure gator is alive and requires an ACK as the response
119                                                 logg->logMessage("Ping command received.");
120                                                 sender->writeData(NULL, 0, RESPONSE_ACK);
121                                         }
122                                 } else {
123                                         logg->logMessage("INVESTIGATE: Received stop command but with length = %d", length);
124                                 }
125                         }
126                 }
127         }
129         logg->logMessage("Exit stop thread");
130         return 0;
133 void* senderThread(void* pVoid) {
134         int length;
135         char* data;
137         sem_post(&senderThreadStarted);
138         prctl(PR_SET_NAME, (unsigned int)&"gatord-sender", 0, 0, 0);
139         sem_wait(&haltPipeline);
141         do {
142                 data = collectorFifo->read(&length);
143                 sender->writeData(data, length, RESPONSE_APC_DATA);
144         } while (length > 0);
145         logg->logMessage("Exit sender thread");
146         return 0;
149 Child::Child(char* path) {
150         initialization();
151         sessionXMLPath = path;
154 Child::Child(OlySocket* sock, int conn) {
155         initialization();
156         socket = sock;
157         numConnections = conn;
160 Child::~Child() {
163 void Child::initialization() {
164         // Set up different handlers for signals
165         gSessionData.mSessionIsActive = true;
166         signal(SIGINT, child_handler);
167         signal(SIGTERM, child_handler);
168         signal(SIGABRT, child_handler);
169         signal(SIGALRM, child_handler);
170         socket = NULL;
171         numExceptions = 0;
172         numConnections = 0;
173         sessionXMLPath = 0;
175         // Initialize semaphores
176         sem_init(&senderThreadStarted, 0, 0);
177         sem_init(&startProfile, 0, 0);
180 void Child::endSession() {
181         gSessionData.mSessionIsActive = false;
182         collector->stop();
183         sem_post(&haltPipeline);
186 void Child::run() {
187         char* collectBuffer;
188         int bytesCollected = 0;
189         LocalCapture* localCapture = NULL;
191         prctl(PR_SET_NAME, (unsigned int)&"gatord-child", 0, 0, 0);
193         // Instantiate the Sender - must be done first, after which error messages can be sent
194         sender = new Sender(socket);
196         if (numConnections > 1) {
197                 logg->logError(__FILE__, __LINE__, "Session already in progress");
198                 handleException();
199         }
201         // Set up the driver
202         collector = new Collector();
204         // Start up and parse session xml
205         if (socket) {
206                 // Respond to Streamline requests
207                 StreamlineSetup ss(socket);
208         } else {
209                 xmlString = util->readFromDisk(sessionXMLPath);
210                 gSessionData.mLocalCapture = true;
211                 if (xmlString == 0) {
212                         logg->logError(__FILE__, __LINE__, "Unable to read session xml file: %s", sessionXMLPath);
213                         handleException();
214                 }
215                 gSessionData.parseSessionXML(xmlString);
216                 localCapture = new LocalCapture();
217                 localCapture->createAPCDirectory(gSessionData.target_path, gSessionData.title);
218                 localCapture->copyImages(gSessionData.images);
219                 localCapture->write(xmlString);
220                 sender->createDataFile(gSessionData.apcDir);
221                 delete xmlString;
222         }
224         // Create user-space buffers
225         int fifoBufferSize = collector->getBufferSize();
226         int numCollectorBuffers = (gSessionData.mTotalBufferSize * 1024 * 1024 + fifoBufferSize - 1) / fifoBufferSize;
227         numCollectorBuffers = (numCollectorBuffers < 4) ? 4 : numCollectorBuffers;
228         logg->logMessage("Created %d %d-byte collector buffers", numCollectorBuffers, fifoBufferSize);
229         collectorFifo = new Fifo(numCollectorBuffers, fifoBufferSize);
231         // Get the initial pointer to the collect buffer
232         collectBuffer = collectorFifo->start();
234         // Sender thread shall be halted until it is signaled for one shot mode
235         sem_init(&haltPipeline, 0, gSessionData.mOneShot ? 0 : 2);
237         // Create the duration, stop, and sender threads
238         bool thread_creation_success = true;
239         if (gSessionData.mDuration > 0 && pthread_create(&durationThreadID, NULL, durationThread, NULL))
240                 thread_creation_success = false;
241         else if (socket && pthread_create(&stopThreadID, NULL, stopThread, NULL))
242                 thread_creation_success = false;
243         else if (pthread_create(&senderThreadID, NULL, senderThread, NULL))
244                 thread_creation_success = false;
245         if (!thread_creation_success) {
246                 logg->logError(__FILE__, __LINE__, "Failed to create gator threads");
247                 handleException();
248         }
250         // Wait until thread has started
251         sem_wait(&senderThreadStarted);
253         // Start profiling
254         logg->logMessage("********** Profiling started **********");
255         collector->start();
256         sem_post(&startProfile);
258         // Collect Data
259         do {
260                 // This command will stall until data is received from the driver
261                 bytesCollected = collector->collect(collectBuffer);
263                 // In one shot mode, stop collection once all the buffers are filled
264                 if (gSessionData.mOneShot && gSessionData.mSessionIsActive) {
265                         // Depth minus 1 because write() has not yet been called
266                         if ((bytesCollected == -1) || (collectorFifo->numWriteToReadBuffersFilled() == collectorFifo->depth() - 1)) {
267                                 logg->logMessage("One shot");
268                                 endSession();
269                         }
270                 }
271                 collectBuffer = collectorFifo->write(bytesCollected);
272         } while (bytesCollected > 0);
273         logg->logMessage("Exit collect data loop");
275         // Wait for the other threads to exit
276         pthread_join(senderThreadID, NULL);
278         // Shutting down the connection should break the stop thread which is stalling on the socket recv() function
279         if (socket) {
280                 logg->logMessage("Waiting on stop thread");
281                 socket->shutdownConnection();
282                 pthread_join(stopThreadID, NULL);
283         }
285         // Write the captured xml file
286         if (gSessionData.mLocalCapture) {
287                 CapturedXML capturedXML;
288                 capturedXML.write(gSessionData.apcDir);
289         }
291         logg->logMessage("Profiling ended.");
293         delete collectorFifo;
294         delete sender;
295         delete collector;
296         delete localCapture;