2 Aesalon, a tool to visualize a program's behaviour at run-time.
3 Copyright (C) 2010, Aesalon Development Team.
5 Aesalon is distributed under the terms of the GNU GPLv3. For more
6 licensing information, see the file LICENSE included with the distribution.
8 @file modules/informer/src/collector/informer.c
19 #include <sys/types.h>
25 #include "informer/Informer.h"
26 #include "common/Config.h"
27 #include "common/ZoneHeader.h"
29 typedef struct Zone_t Zone_t
;
35 typedef struct InformerData_t InformerData_t
;
36 struct InformerData_t
{
40 pthread_t monitorThreadList
[AesalonInformerMonitorThreadListSize
];
41 int monitorThreadListSize
;
43 pthread_t
*threadList
;
49 SharedMemoryHeader_t
*shmHeader
;
51 const char *configData
;
56 static InformerData_t AI_InformerData
;
58 static __thread
uint8_t *AI_Zone
= NULL
;
59 static __thread SHMPacketHeader_t
*AI_ZonePacket
= NULL
;
61 /** Interally-used function; opens shared memory for later use.
62 @param name The name of the SHM to use.
64 static void AI_OpenSHM(const char *name
);
66 static void AI_SetupHeader();
67 static void AI_SetupConfig();
68 static void AI_SetupZoneUse();
70 static void AI_SetupZone();
71 static void *AI_ReserveSpace(uint32_t amount
);
73 static int AI_ZoneAvailable(uint32_t id
);
74 static void AI_MarkZone(uint32_t id
);
75 static void AI_ClearZone(uint32_t id
);
77 /** Internally-used function to calculate the amount of space remaining in the zone for
79 @param zoneID The zone to calculate the remaining space.
81 static uint32_t AI_RemainingSpace();
83 /* ------------------------------------------------------------------ */
85 void __attribute__((constructor
)) AI_Construct() {
86 /* By default, .initialized will be set to 0 (AI_InformerData is a global). */
87 if(AI_InformerData
.initialized
) return;
88 AI_InformerData
.initialized
= 1;
90 printf("[AI] **** Constructing Informer . . .\n");
92 pthread_t self
= pthread_self();
94 AI_StopCollection(self
);
100 int fd
= open("/proc/self/cmdline", O_RDONLY
);
102 read(fd
, filename
, sizeof(filename
));
106 /* String hashing algorithm: djb2. */
108 uint64_t pathHash
= 0;
111 while((c
= (*p
++))) {
112 pathHash
= c
+ (pathHash
<< 6) + (pathHash
<< 16) - pathHash
;
115 /* Clear the first 16 bits for the PID to be inserted properly. */
118 AI_InformerData
.processID
= pathHash
^ pid
;
120 const char *shmName
= getenv("AesalonSHMName");
121 if(shmName
== NULL
) {
122 fprintf(stderr
, "[aesalon] AesalonSHMName not set, aborting.\n");
131 AI_InformerData
.threadList
= malloc(sizeof(pthread_t
) * 16);
132 AI_InformerData
.threadListSize
= 16;
133 AI_InformerData
.threadCount
= 1;
134 AI_InformerData
.threadList
[0] = self
;
136 AI_ContinueCollection(self
);
143 void __attribute__((destructor
)) AI_Destruct() {
144 printf("[AI] Destructing Informer . . .\n");
147 static void AI_OpenSHM(const char *name
) {
148 AI_InformerData
.shmFd
= shm_open(name
, O_RDWR
, S_IRUSR
| S_IWUSR
);
151 static void AI_SetupHeader() {
152 AI_InformerData
.shmHeader
= mmap(NULL
, AesalonPageSize
,
153 PROT_READ
| PROT_WRITE
, MAP_SHARED
, AI_InformerData
.shmFd
, 0);
156 static void AI_SetupConfig() {
157 AI_InformerData
.configData
= mmap(NULL
, AI_InformerData
.shmHeader
->configDataSize
*AesalonPageSize
,
158 PROT_READ
| PROT_WRITE
, MAP_SHARED
, AI_InformerData
.shmFd
, AesalonPageSize
);
161 static void AI_SetupZoneUse() {
162 AI_InformerData
.zoneUseData
= mmap(NULL
, AI_InformerData
.shmHeader
->zoneUsagePages
*AesalonPageSize
,
163 PROT_READ
| PROT_WRITE
, MAP_SHARED
, AI_InformerData
.shmFd
,
164 (AI_InformerData
.shmHeader
->configDataSize
+ 1)*AesalonPageSize
);
166 /* +1 for the header. */
167 AI_InformerData
.shmHeader
->zonePageOffset
=
168 AI_InformerData
.shmHeader
->zoneUsagePages
+ AI_InformerData
.shmHeader
->configDataSize
+ 1;
171 static void AI_SetupZone() {
172 printf("Setting up new zone . . .\n");
173 printf("\tActive zone count: %i\n", AI_InformerData
.shmHeader
->zoneCount
);
174 printf("\tAllocated zone count: %i\n", AI_InformerData
.shmHeader
->zonesAllocated
);
175 /* Check if more memory is required. */
176 while(AI_InformerData
.shmHeader
->zoneCount
>= AI_InformerData
.shmHeader
->zonesAllocated
) {
177 /* Allocate more memory. */
178 sem_wait(&AI_InformerData
.shmHeader
->resizeSemaphore
);
180 if(AI_InformerData
.shmHeader
->zoneCount
>= AI_InformerData
.shmHeader
->zonesAllocated
) {
181 AI_InformerData
.shmHeader
->shmSize
+= AI_InformerData
.shmHeader
->zoneSize
;
183 AI_InformerData
.shmHeader
->zonesAllocated
++;
185 printf("New size: %i pages\n", AI_InformerData
.shmHeader
->shmSize
);
186 ftruncate(AI_InformerData
.shmFd
, AI_InformerData
.shmHeader
->shmSize
* AesalonPageSize
);
189 sem_post(&AI_InformerData
.shmHeader
->resizeSemaphore
);
193 for(i
= 0; i
< AI_InformerData
.shmHeader
->zonesAllocated
; i
++) {
194 if(AI_ZoneAvailable(i
)) break;
196 if(i
== AI_InformerData
.shmHeader
->zonesAllocated
) {
197 /* Something went pretty seriously wrong. Perhaps another target jumped in and took the spot first? */
198 printf("Something very wrong occurred. Trying again . . .\n");
201 printf("Marking zone . . .\n");
203 printf("Zone marked, mapping . . .\n");
205 AI_InformerData
.shmHeader
->zoneSize
*AesalonPageSize
,
206 PROT_READ
| PROT_WRITE
, MAP_SHARED
, AI_InformerData
.shmFd
,
207 (AI_InformerData
.shmHeader
->zonePageOffset
+ i
*AI_InformerData
.shmHeader
->zoneSize
)*AesalonPageSize
);
209 printf("Mapped, initializing . . .\n");
211 printf("Mapping offset: %x\n",
212 (AI_InformerData
.shmHeader
->zonePageOffset
+ i
*AI_InformerData
.shmHeader
->zoneSize
)*AesalonPageSize
);
213 printf("Mapping size: %x\n", AI_InformerData
.shmHeader
->zoneSize
*AesalonPageSize
);
215 ((ZoneHeader_t
*)AI_Zone
)->head
= ((ZoneHeader_t
*)AI_Zone
)->tail
= ZoneDataOffset
;
216 ((ZoneHeader_t
*)AI_Zone
)->overflow
= 0;
217 ((ZoneHeader_t
*)AI_Zone
)->processID
= getpid();
218 ((ZoneHeader_t
*)AI_Zone
)->threadID
= pthread_self();
220 printf("Setting up semaphores . . .\n");
222 sem_init(&((ZoneHeader_t
*)AI_Zone
)->packetSemaphore
, 1, 0);
223 sem_init(&((ZoneHeader_t
*)AI_Zone
)->overflowSemaphore
, 1, 0);
225 printf("Set up zone properly . . .\n");
228 static int AI_ZoneAvailable(uint32_t id
) {
229 uint32_t byteOffset
= id
/ 8;
230 uint32_t bitOffset
= id
% 8;
231 uint32_t mask
= 0x01;
232 return !(AI_InformerData
.zoneUseData
[byteOffset
] & (mask
<< bitOffset
));
235 static void AI_MarkZone(uint32_t id
) {
236 uint32_t byteOffset
= id
/ 8;
237 uint32_t bitOffset
= id
% 8;
238 uint32_t mask
= 0x01;
239 AI_InformerData
.zoneUseData
[byteOffset
] |= (mask
<< bitOffset
);
240 AI_InformerData
.shmHeader
->zoneCount
++;
243 static void AI_ClearZone(uint32_t id
) {
244 uint32_t byteOffset
= id
/ 8;
245 uint32_t bitOffset
= id
% 8;
246 uint32_t mask
= 0x01;
247 AI_InformerData
.zoneUseData
[byteOffset
] &= ~(mask
<< bitOffset
);
248 AI_InformerData
.shmHeader
->zoneCount
--;
251 static uint32_t AI_RemainingSpace() {
252 ZoneHeader_t
*header
= (ZoneHeader_t
*)AI_Zone
;
253 if(header
->head
<= header
->tail
) {
254 return ((AI_InformerData
.shmHeader
->zoneSize
*AesalonPageSize
) - ZoneDataOffset
)
255 - (header
->tail
- header
->head
);
258 return header
->head
- ZoneDataOffset
- header
->tail
;
262 static void *AI_ReserveSpace(uint32_t amount
) {
263 uint32_t remaining
= AI_RemainingSpace();
264 ZoneHeader_t
*header
= (ZoneHeader_t
*)AI_Zone
;
265 /*uint32_t zoneDataSize = (AI_InformerData.shmHeader->zoneSize*AesalonPageSize) - ZoneDataOffset;*/
266 if(remaining
< amount
) {
267 header
->overflow
= amount
- remaining
;
268 sem_wait(&header
->overflowSemaphore
);
271 /* If the head is less than (or equal to) the tail, then the used memory
272 is in one contiguous chunk, and the buffer has not wrapped yet. */
273 if(header
->head
<= header
->tail
) {
274 /* if(header->head + amount >= zoneDataSize) {
275 header->gapSize = (amount + header->head) - zoneDataSize;
276 amount += header->gapSize;
277 header->head = ZoneDataOffset;
280 header
->tail
+= amount
;
281 return &AI_Zone
[header
->tail
-amount
];
284 printf("**** Second case, returning NULL.\n");
289 void AI_StartPacket(ModuleID moduleID
) {
290 if(AI_Zone
== NULL
) AI_SetupZone();
291 AI_ZonePacket
= AI_ReserveSpace(sizeof(SHMPacketHeader_t
));
292 AI_ZonePacket
->packetSize
= 0;
293 AI_ZonePacket
->moduleID
= moduleID
;
296 void AC_EXPORT
*AI_PacketSpace(uint32_t size
) {
297 AI_ZonePacket
->packetSize
+= size
;
298 return AI_ReserveSpace(size
);
301 void AC_EXPORT
AI_EndPacket() {
302 printf("packet size: %i\n", AI_ZonePacket
->packetSize
);
303 AI_ZonePacket
= NULL
;
305 ZoneHeader_t
*header
= (ZoneHeader_t
*)AI_Zone
;
307 sem_post(&header
->packetSemaphore
);
309 sem_post(&AI_InformerData
.shmHeader
->packetSemaphore
);
312 uint64_t AI_Timestamp() {
314 clock_gettime(CLOCK_REALTIME
, &t
);
315 return (t
.tv_sec
* 1000000000) + t
.tv_nsec
;
318 const char *AI_ConfigurationString(const char *name
) {
321 const char *itemName
= &AI_InformerData
.configData
[offset
];
322 if(itemName
== 0 || itemName
[0] == 0) break;
324 int nameLength
= strlen(itemName
)+1;
325 const char *itemData
= &AI_InformerData
.configData
[offset
+nameLength
];
326 if(!strcmp(name
, itemName
)) return itemData
;
328 int dataLength
= strlen(itemData
)+1;
329 offset
+= nameLength
+ dataLength
;
334 long AI_ConfigurationLong(const char *name
) {
335 const char *s
= AI_ConfigurationString(name
);
336 if(s
== NULL
) return -1;
338 sscanf(s
, "%ld", &value
);
342 int AI_ConfigurationBool(const char *name
) {
343 const char *s
= AI_ConfigurationString(name
);
344 if(s
== NULL
) return 0;
345 return strcmp(s
, "false") != 0;
348 pthread_t
*AI_TargetThreadList(int *size
) {
349 if(size
== NULL
) return NULL
;
350 *size
= AI_InformerData
.threadCount
;
352 return AI_InformerData
.threadList
;
355 short AI_CollectionStatus() {
356 if(AI_InformerData
.threadList
== NULL
) return 0;
357 pthread_t self
= pthread_self();
359 while(i
< AI_InformerData
.monitorThreadListSize
) {
360 if(pthread_equal(self
, AI_InformerData
.monitorThreadList
[i
])) return 0;
367 void AI_StopCollection(pthread_t tid
) {
368 if(AI_InformerData
.monitorThreadListSize
< AesalonInformerMonitorThreadListSize
) {
369 AI_InformerData
.monitorThreadList
[AI_InformerData
.monitorThreadListSize
] = tid
;
370 AI_InformerData
.monitorThreadListSize
++;
374 "Too many threads in monitor thread list, output data will be corrupted with Aesalon"
375 "collection-thread data.\n");
376 fprintf(stderr
, "Increasing threadListSize in build/config may be a good idea.\n");
380 void AI_ContinueCollection(pthread_t tid
) {
382 while(i
< AI_InformerData
.monitorThreadListSize
) {
383 if(pthread_equal(AI_InformerData
.monitorThreadList
[i
], tid
)) {
384 AI_InformerData
.monitorThreadListSize
--;
385 AI_InformerData
.monitorThreadList
[i
] =
386 AI_InformerData
.monitorThreadList
[AI_InformerData
.monitorThreadListSize
-1];