Decision time again, as per usual . . .
[aesalon.git] / src / monitor / SHMReader.cpp
blobb0340363cff64f739fe27c427b4893e748f84bb9
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
8 */
10 #include <semaphore.h>
11 #include <sys/mman.h>
12 #include <fcntl.h>
13 #include <cstring>
14 #include <errno.h>
16 #include "Config.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"
25 namespace Monitor {
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));
33 setupHeader();
34 setupConfiguration();
35 setupZones();
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);
51 if(zone == NULL) {
52 Message(Warning, "Could not open zone #" << i);
53 continue;
56 SHM::ZoneHeader *zheader = reinterpret_cast<SHM::ZoneHeader *>(zone);
58 if(sem_wait(&zheader->packetSemaphore) == -1 && errno == EAGAIN) continue;
60 return i;
63 return -1;
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 . . . */
78 /* Copy the data. */
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);
86 if(size2 > 0) {
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];
96 uint8_t *zone =
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;
102 return 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);
117 void *memory =
118 mmap(NULL, size * AesalonPageSize, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, start * AesalonPageSize);
120 return memory;
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);
141 uint32_t offset = 0;
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