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 src/monitor/SHMReader.cpp
10 #include <semaphore.h>
18 #include "monitor/SHMReader.h"
19 #include "monitor/Coordinator.h"
20 #include "util/StreamAsString.h"
21 #include "util/MessageSystem.h"
22 #include "util/StringTo.h"
23 #include "shm/ZoneHeader.h"
27 SHMReader::SHMReader() : m_header(NULL
) {
28 m_shmName
= Util::StreamAsString() << "/Aesalon-" << getpid();
30 m_fd
= shm_open(m_shmName
.c_str(), O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
);
31 if(m_fd
== -1) Message(Fatal
, "Could not open shared memory: " << strerror(errno
));
38 SHMReader::~SHMReader() {
42 uint32_t SHMReader::zoneCount() {
43 return m_header
->zoneCount
;
46 int32_t SHMReader::zoneWithData() {
47 for(uint32_t i
= 0; i
< m_header
->zonesAllocated
; i
++) {
48 if(m_zoneUseData
[i
% 8] & (0x01 << (i
% 8))) {
49 uint8_t *zone
= getZone(i
);
52 Message(Warning
, "Could not open zone #" << i
);
56 SHM::ZoneHeader
*zheader
= reinterpret_cast<SHM::ZoneHeader
*>(zone
);
58 if(sem_wait(&zheader
->packetSemaphore
) == -1 && errno
== EAGAIN
) continue;
66 void SHMReader::waitForPacket() {
67 sem_wait(&m_header
->packetSemaphore
);
70 void SHMReader::readData(uint32_t zoneID
, void *buffer
, uint32_t size
) {
71 uint8_t *zone
= getZone(zoneID
);
73 SHM::ZoneHeader
*header
= reinterpret_cast<SHM::ZoneHeader
*>(zone
);
75 /* Wait for the data to become available . . . */
79 uint32_t start1
= header
->head
+ ZoneDataOffset
;
80 uint32_t size1
= std::min(size
, (m_header
->zoneSize
*AesalonPageSize
)-start1
);
82 uint32_t size2
= size
- size1
;
83 uint32_t start2
= ZoneDataOffset
;
85 memcpy(buffer
, zone
+ start1
, size1
);
87 memcpy(static_cast<uint8_t *>(buffer
) + size1
, zone
+ start2
, size2
);
91 uint8_t *SHMReader::getZone(uint32_t id
) {
92 if(id
< m_zoneList
.size() && m_zoneList
[id
] != NULL
) {
93 return m_zoneList
[id
];
97 static_cast<uint8_t *>(mapRegion(m_header
->zonePageOffset
+ id
*m_header
->zoneSize
, m_header
->zoneSize
));
99 m_zoneList
.resize(id
+1);
100 m_zoneList
[id
] = zone
;
105 void *SHMReader::mapRegion(uint32_t start
, uint32_t size
) {
106 if(m_header
== NULL
|| m_header
->shmSize
< (start
+size
)) {
107 if(m_header
) sem_wait(&m_header
->resizeSemaphore
);
109 Message(Debug
, "Resizing SHM to " << start
+size
<< " page(s).");
110 if(ftruncate(m_fd
, (start
+size
) * AesalonPageSize
) != 0) {
111 Message(Fatal
, "Could not resize shared memory.");
114 if(m_header
) sem_post(&m_header
->resizeSemaphore
);
118 mmap(NULL
, size
* AesalonPageSize
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, m_fd
, start
* AesalonPageSize
);
123 void SHMReader::unmapRegion(void *data
, uint32_t size
) {
124 munmap(data
, size
*AesalonPageSize
);
127 void SHMReader::setupHeader() {
128 m_header
= reinterpret_cast<SHM::Header
*>(mapRegion(0, 1));
130 sem_init(&m_header
->packetSemaphore
, 1, 0);
131 sem_init(&m_header
->resizeSemaphore
, 1, 1);
134 void SHMReader::setupConfiguration() {
135 char *configurationData
= static_cast<char *>(mapRegion(1, 1));
136 m_header
->configDataSize
= 1;
138 std::vector
<Config::Vault::KeyPair
> configItems
;
139 Coordinator::instance()->vault()->match("*", configItems
);
143 for(std::vector
<Config::Vault::KeyPair
>::iterator i
= configItems
.begin(); i
!= configItems
.end(); ++i
) {
144 /* Ignore all internal items. */
145 if(i
->first
.find("::") == 0) continue;
147 while((offset
+ i
->first
.length() + i
->second
.length() + 2) > m_header
->configDataSize
*AesalonPageSize
) {
148 unmapRegion(configurationData
, m_header
->configDataSize
);
149 m_header
->configDataSize
++;
150 configurationData
= static_cast<char *>(mapRegion(1, m_header
->configDataSize
));
152 memcpy(&configurationData
[offset
], i
->first
.c_str(), i
->first
.length()+1);
153 offset
+= i
->first
.length()+1;
154 memcpy(&configurationData
[offset
], i
->second
.c_str(), i
->second
.length()+1);
155 offset
+= i
->second
.length()+1;
159 void SHMReader::setupZones() {
160 m_header
->zoneCount
= 0;
161 m_header
->zoneSize
= Util::StringTo
<uint32_t>(Coordinator::instance()->vault()->get("zoneSize"));
162 m_header
->zoneUsagePages
= Util::StringTo
<uint32_t>(Coordinator::instance()->vault()->get("zoneUsePages"));
164 m_header
->zonePageOffset
= m_header
->configDataSize
+ 1 + m_header
->zoneUsagePages
;
167 } // namespace Monitor