1 /** Aesalon, a tool to visualize program behaviour in real time.
2 Copyright (C) 2009-2011, Aesalon development team.
4 Aesalon is distributed under the terms of the GNU GPLv3. See
5 the included file LICENSE for more information.
7 @file modules/informer/src/collector/Informer.c
21 #include "informer/Informer.h"
22 #include "shm/PacketHeader.h"
23 #include "shm/ZoneHeader.h"
24 #include "util/StringToBool.h"
26 typedef struct InformerData InformerData
;
31 pthread_t monitorThreadList
[AesalonInformerMonitorThreadListSize
];
32 int monitorThreadListSize
;
34 pthread_t
*threadList
;
42 const char *configData
;
47 static InformerData AI_InformerData
;
49 static THREAD_SPECIFIC
uint8_t *AI_Zone
= NULL
;
50 static THREAD_SPECIFIC PacketHeader
*AI_ZonePacket
= NULL
;
52 static void AI_SetupSHM();
53 static void *AI_MapSHM(uint32_t start
, uint32_t size
);
54 static void *AI_SetupZone();
55 static void *AI_ReserveSpace(uint32_t size
);
58 const char *shmName
= getenv("AesalonSHMName");
60 fprintf(stderr
, "AesalonSHMName not set, aborting . . .\n");
64 AI_InformerData
.shmFd
= shm_open(shmName
, O_RDWR
, S_IRUSR
| S_IWUSR
);
66 AI_InformerData
.shmHeader
= AI_MapSHM(0, 1);
67 AI_InformerData
.configData
= AI_MapSHM(1, AI_InformerData
.shmHeader
->configDataSize
);
68 AI_InformerData
.zoneUseData
=
69 AI_MapSHM(AI_InformerData
.shmHeader
->configDataSize
+1, AI_InformerData
.shmHeader
->zoneUsagePages
);
72 void *AI_MapSHM(uint32_t start
, uint32_t size
) {
73 if(AI_InformerData
.shmHeader
!= NULL
) printf("Overall size: %i\n", AI_InformerData
.shmHeader
->shmSize
);
74 if(AI_InformerData
.shmHeader
!= NULL
&& AI_InformerData
.shmHeader
->shmSize
< (start
+size
)) {
75 sem_wait(&AI_InformerData
.shmHeader
->resizeSemaphore
);
77 if(ftruncate(AI_InformerData
.shmFd
, (start
+size
) * AesalonPageSize
) != 0) {
78 fprintf(stderr
, "Could not resize shared memory.");
82 sem_post(&AI_InformerData
.shmHeader
->resizeSemaphore
);
86 mmap(NULL
, size
* AesalonPageSize
, PROT_READ
| PROT_WRITE
,
87 MAP_SHARED
, AI_InformerData
.shmFd
, start
* AesalonPageSize
);
92 static void *AI_SetupZone() {
93 /* While more memory is required . . . */
94 while(AI_InformerData
.shmHeader
->zoneCount
>= AI_InformerData
.shmHeader
->zonesAllocated
) {
95 /* Allocate more memory. */
96 sem_wait(&AI_InformerData
.shmHeader
->resizeSemaphore
);
98 /* This seemingly-nonsensical statement is to account for the fact that during the wait above,
99 another thread may have jumped in and allocated a zone that can now be used.
101 if(AI_InformerData
.shmHeader
->zoneCount
>= AI_InformerData
.shmHeader
->zonesAllocated
) {
102 /* Allocate two zones per iteration. */
103 AI_InformerData
.shmHeader
->shmSize
+= AI_InformerData
.shmHeader
->zoneSize
* 2;
104 AI_InformerData
.shmHeader
->zonesAllocated
+= 2;
106 ftruncate(AI_InformerData
.shmFd
, AI_InformerData
.shmHeader
->shmSize
* AesalonPageSize
);
109 sem_post(&AI_InformerData
.shmHeader
->resizeSemaphore
);
112 printf("Allocated zones: %i\n", AI_InformerData
.shmHeader
->zonesAllocated
);
115 for(i
= 0; i
< AI_InformerData
.shmHeader
->zonesAllocated
; i
++) {
116 if((AI_InformerData
.zoneUseData
[i
/8] & (0x01 << (i
% 8))) == 0) break;
118 printf("Zone ID#: %i\n", i
);
119 if(i
== AI_InformerData
.shmHeader
->zonesAllocated
) {
120 /* Something went pretty seriously wrong. Perhaps another target jumped in and took the spot first? */
121 printf("Something very wrong occurred. Trying again . . .\n");
122 /* Just temporarily use recursion to fix the problem. Note: don't try this at home . . . */
125 AI_InformerData
.zoneUseData
[i
/8] |= (0x01 << (i
%8));
128 AI_InformerData
.shmHeader
->zonePageOffset
+ (i
*AI_InformerData
.shmHeader
->zoneSize
),
129 AI_InformerData
.shmHeader
->zoneSize
);
131 ((ZoneHeader
*)AI_Zone
)->head
= ((ZoneHeader
*)AI_Zone
)->tail
= ZoneDataOffset
;
132 ((ZoneHeader
*)AI_Zone
)->overflow
= 0;
133 /* TODO: implement support for finding the process ID. */
134 ((ZoneHeader
*)AI_Zone
)->processID
= 0;
135 ((ZoneHeader
*)AI_Zone
)->threadID
= ++AI_InformerData
.shmHeader
->lastThreadID
;
140 static void *AI_ReserveSpace(uint32_t size
) {
141 ZoneHeader
*header
= (ZoneHeader
*)AI_Zone
;
143 /* Three cases for remaining check (and also below).
144 1) head > tail (memory is in two chunks)
145 2) head < tail (memory is in one chunk), tail+size >= zoneSize
146 3) head < tail (memory is in one chunk), tail+size < zoneSize
148 if(header
->head
> header
->tail
) {
149 remaining
= header
->head
- ZoneDataOffset
- header
->tail
;
151 else if(header
->head
<= header
->tail
152 && (header
->tail
+ size
) < AI_InformerData
.shmHeader
->zoneSize
*AesalonPageSize
) {
154 remaining
= AI_InformerData
.shmHeader
->zoneSize
*AesalonPageSize
155 - (header
->tail
- header
->head
) - ZoneDataOffset
;
157 else if(header
->head
<= header
->tail
158 && (header
->tail
+ size
) >= AI_InformerData
.shmHeader
->zoneSize
*AesalonPageSize
) {
160 remaining
= header
->head
- ZoneDataOffset
;
163 if(remaining
< size
) {
164 printf("Not enough space remaining!\n");
165 printf("remaining: %i\n", remaining
);
166 header
->overflow
= size
- remaining
;
167 printf("Overflow: %i\n", header
->overflow
);
168 sem_wait(&header
->overflowSemaphore
);
171 if(header
->head
> header
->tail
) {
172 header
->tail
+= size
;
173 return AI_Zone
+ header
->tail
- size
;
175 else if(header
->head
<= header
->tail
176 && (header
->tail
+ size
) < AI_InformerData
.shmHeader
->zoneSize
*AesalonPageSize
) {
178 header
->tail
+= size
;
179 return AI_Zone
+ header
->tail
- size
;
181 else if(header
->head
<= header
->tail
182 && (header
->tail
+ size
) >= AI_InformerData
.shmHeader
->zoneSize
*AesalonPageSize
) {
184 header
->gapSize
= AI_InformerData
.shmHeader
->zoneSize
*AesalonPageSize
- header
->tail
;
185 header
->tail
= ZoneDataOffset
+ size
;
186 return AI_Zone
+ ZoneDataOffset
;
189 printf("Something unforeseen occured. This should not have happened . . .\n");
193 void __attribute__((constructor
)) AI_Construct() {
194 if(AI_InformerData
.initialized
== 1) return;
195 pthread_t self
= pthread_self();
196 AI_StopCollection(self
);
197 AI_InformerData
.initialized
= 1;
201 AI_InformerData
.threadList
= malloc(sizeof(pthread_t
) * 16);
202 AI_InformerData
.threadListSize
= 16;
203 AI_InformerData
.threadCount
= 1;
204 AI_InformerData
.threadList
[0] = self
;
206 AI_ContinueCollection(self
);
216 void __attribute__((destructor
)) AI_Destruct() {
220 void AC_EXPORT
AI_StartPacket(ModuleID moduleID
) {
221 if(AI_Zone
== NULL
) AI_SetupZone();
222 AI_ZonePacket
= AI_ReserveSpace(sizeof(PacketHeader
));
223 AI_ZonePacket
->packetSize
= 0;
224 AI_ZonePacket
->moduleID
= moduleID
;
227 void AC_EXPORT
*AI_PacketSpace(uint32_t size
) {
228 AI_ZonePacket
->packetSize
+= size
;
229 return AI_ReserveSpace(size
);
232 void AC_EXPORT
AI_EndPacket() {
233 AI_ZonePacket
= NULL
;
234 sem_post(&((ZoneHeader
*)AI_Zone
)->packetSemaphore
);
235 sem_post(&AI_InformerData
.shmHeader
->packetSemaphore
);
238 const char *AI_ConfigurationString(const char *name
) {
241 const char *itemName
= &AI_InformerData
.configData
[offset
];
242 if(itemName
== 0 || itemName
[0] == 0) break;
244 int nameLength
= strlen(itemName
)+1;
245 const char *itemData
= &AI_InformerData
.configData
[offset
+nameLength
];
246 if(!strcmp(name
, itemName
)) return itemData
;
248 int dataLength
= strlen(itemData
)+1;
249 offset
+= nameLength
+ dataLength
;
254 long AI_ConfigurationLong(const char *name
) {
255 const char *s
= AI_ConfigurationString(name
);
256 if(s
== NULL
) return -1;
258 sscanf(s
, "%ld", &value
);
262 int AI_ConfigurationBool(const char *name
) {
263 const char *s
= AI_ConfigurationString(name
);
264 if(s
== NULL
) return 0;
265 return StringToBool(s
);
268 void AI_StopCollection(pthread_t threadID
) {
269 if(AI_InformerData
.monitorThreadListSize
< AesalonInformerMonitorThreadListSize
) {
270 AI_InformerData
.monitorThreadList
[AI_InformerData
.monitorThreadListSize
] = threadID
;
271 AI_InformerData
.monitorThreadListSize
++;
275 "Too many threads in monitor thread list, output data will be corrupted with Aesalon"
276 "collection-thread data.\n");
277 fprintf(stderr
, "Increasing threadListSize in build/config may be a good idea.\n");
281 void AI_ContinueCollection(pthread_t threadID
) {
283 while(i
< AI_InformerData
.monitorThreadListSize
) {
284 if(pthread_equal(AI_InformerData
.monitorThreadList
[i
], threadID
)) {
285 AI_InformerData
.monitorThreadListSize
--;
286 AI_InformerData
.monitorThreadList
[i
] =
287 AI_InformerData
.monitorThreadList
[AI_InformerData
.monitorThreadListSize
-1];
294 short AI_CollectionStatus() {
295 if(AI_InformerData
.initialized
== 0) return 0;
296 pthread_t self
= pthread_self();
298 while(i
< AI_InformerData
.monitorThreadListSize
) {
299 if(pthread_equal(self
, AI_InformerData
.monitorThreadList
[i
])) return 0;