CMSDK 2.0.1
Cross-platform C++ base library and SDK for the Psyclone AIOS platform
Loading...
Searching...
No Matches
PsyAPI.cpp
Go to the documentation of this file.
1
8#include "PsyAPI.h"
9
10namespace cmlabs {
11
12struct PsyType PsyAPI::CTRL_SYSTEM_READY = { { 1,10200,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };
13struct PsyType PsyAPI::CTRL_PROCESS_INITIALISE = { { 1,10201,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };
14struct PsyType PsyAPI::CTRL_PROCESS_GREETING = { { 1,10202,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };
15struct PsyType PsyAPI::CTRL_PROCESS_SHUTDOWN = { { 1,10203,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };
16struct PsyType PsyAPI::CTRL_CONTEXT_CHANGE = { { 1,10297,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };
17struct PsyType PsyAPI::CTRL_SYSTEM_SHUTDOWN = { { 1,10298,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };
18struct PsyType PsyAPI::CTRL_SYSTEM_SHUTTINGDOWN = { { 1,10299,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };
19struct PsyType PsyAPI::CTRL_TRIGGER = { { 1,10300,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };
20struct PsyType PsyAPI::CTRL_TRIGGER_GROUP = { { 1,10307,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };
21struct PsyType PsyAPI::CTRL_QUERY = { { 1,10301,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };
22struct PsyType PsyAPI::CTRL_QUERY_REPLY = { { 1,10302,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };
23struct PsyType PsyAPI::CTRL_PULLCOMPONENTDATA = { { 1,10303,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };
24struct PsyType PsyAPI::CTRL_CREATECUSTOMPAGE = { { 1,10304,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };
25struct PsyType PsyAPI::CTRL_ADDSUBSCRIPTION = { { 1,10305,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };
26struct PsyType PsyAPI::CTRL_RETRIEVESYSTEMIDS = { { 1,10306,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };
27struct PsyType PsyAPI::CTRL_INTERSYSTEM_QUERY = { { 1,10998,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };
28struct PsyType PsyAPI::CTRL_INTERSYSTEM_QUERY_REPLY = { { 1,10999,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } };
29
31 this->space = space;
32 autoDelete = true;
33 startedRunning = 0;
34 shouldContinueRunning = false;
35 currentCrankID = 0;
36 lastCPUTicks = 0;
37 lastWallTime = 0;
38 chainCPUTicks = 0;
39 chainWallTime = 0;
40 chainCount = 0;
41 currentCompID = 0;
42 msgReceivedCount = 0;
43 msgInputCount = 0;
44 msgSentCount = 0;
45 msgPostedCount = 0;
46 commandlineBasedir[0] = 0;
47 currentTriggerName[0] = 0;
48 currentTriggerMsg = NULL;
49 currentMsg = NULL;
50 currentSignalMsg = NULL;
51 currentTriggerSpec = NULL;
52}
53
55 apiMutex.enter(2000);
56 shouldContinueRunning = false;
57 this->space = NULL;
58 delete(currentTriggerMsg);
59 currentTriggerMsg = NULL;
60 delete(currentMsg);
61 currentMsg = NULL;
62 delete(currentSignalMsg);
63 currentSignalMsg = NULL;
64 // T1.6: free any owned grouped-set member messages.
65 std::map<std::string, DataMessage*>::iterator git, gitEnd;
66 for (git = currentGroupMap.begin(), gitEnd = currentGroupMap.end(); git != gitEnd; git++)
67 if (git->second) delete(git->second);
68 currentGroupMap.clear();
69 apiMutex.leave();
70}
71
72PsyAPI* PsyAPI::fromPython(unsigned long long ptr) {
73 return (PsyAPI*)ptr;
74}
75
76const char* PsyAPI::fromPythonAddressOf(unsigned long long ptr) {
77 return (const char*)ptr;
78}
79
81 if (!apiMutex.enter(1000))
82 return false;
83 if (startedRunning) {
84 apiMutex.leave();
85 return true;
86 }
87 else {
88 apiMutex.leave();
89 return false;
90 }
91}
92
94 if (!apiMutex.enter(1000))
95 return true;
96 if (shouldContinueRunning) {
97 apiMutex.leave();
98 return true;
99 }
100 else {
101 apiMutex.leave();
102 return false;
103 }
104}
105
107 return commandlineBasedir;
108}
109
110bool PsyAPI::setCommandlineBasedir(const char* cmdlineBasedir) {
111 utils::strcpyavail(commandlineBasedir, cmdlineBasedir, MAXCOMMANDLINELEN, true);
112 return true;
113}
114
115
116bool PsyAPI::getModuleName(char* name, uint32 maxSize) {
117 return space->manager->componentMemory->getComponentName(currentCompID, name, maxSize);
118}
119
121 return space->manager->componentMemory->getComponentNameString(currentCompID);
122}
123
124std::string PsyAPI::getOtherModuleName(uint32 id) {
125 return space->manager->componentMemory->getComponentNameString(id);
126}
127
128bool PsyAPI::getCurrentScriptLanguage(char* language, uint32 maxSize) {
129 return space->manager->dataMapsMemory->getCrankLanguage(currentCrankID, language, maxSize);
130}
131
133 char* language = new char[1024];
134 if (!space->manager->dataMapsMemory->getCrankLanguage(currentCrankID, language, 1024)) {
135 delete[] language;
136 return "";
137 }
138 std::string lang = language;
139 delete[] language;
140 return lang;
141}
142
143bool PsyAPI::getCurrentScript(char* script, uint32 maxSize) {
144 return space->manager->dataMapsMemory->getCrankScript(currentCrankID, script, 1024);
145}
146
148 char* script = new char[MAXSCRIPTLEN];
149 if (!space->manager->dataMapsMemory->getCrankScript(currentCrankID, script, MAXSCRIPTLEN)) {
150 delete[] script;
151 return "";
152 }
153 std::string scr = script;
154 delete[] script;
155 return scr;
156}
157
158bool PsyAPI::getCurrentScriptFilename(char* file, uint32 maxSize) {
159 return space->manager->dataMapsMemory->getCrankLibraryFilename(currentCrankID, file, 1024);
160}
161
163 char* file = new char[1024];
164 if (!space->manager->dataMapsMemory->getCrankLibraryFilename(currentCrankID, file, 1024)) {
165 delete[] file;
166 return "";
167 }
168 std::string filename = file;
169 delete[] file;
170 return filename;
171}
172
173bool PsyAPI::hasCurrentRetrieveName(const char* name) {
174 if (!apiMutex.enter(1000, __FUNCTION__))
175 return false;
176 if (currentTriggerSpec) {
177 if (currentTriggerSpec->getRetrieveSpec(name)) {
178 apiMutex.leave();
179 return true;
180 }
181 }
182 apiMutex.leave();
183 return false;
184}
185
186bool PsyAPI::hasCurrentSignalName(const char* name) {
187 if (!apiMutex.enter(1000, __FUNCTION__))
188 return false;
189 if (currentTriggerSpec) {
190 if (currentTriggerSpec->getSignalSpec(name)) {
191 apiMutex.leave();
192 return true;
193 }
194 }
195 apiMutex.leave();
196 return false;
197}
198
199
200bool PsyAPI::hasCurrentQueryName(const char* name) {
201 if (!apiMutex.enter(1000, __FUNCTION__))
202 return false;
203 if (currentTriggerSpec) {
204 if (currentTriggerSpec->getQuerySpec(name)) {
205 apiMutex.leave();
206 return true;
207 }
208 }
209 apiMutex.leave();
210 return false;
211}
212
213bool PsyAPI::hasCurrentPostName(const char* name) {
214 if (!apiMutex.enter(1000, __FUNCTION__))
215 return false;
216 if (currentTriggerSpec) {
217 if (currentTriggerSpec->getPostSpec(name)) {
218 apiMutex.leave();
219 return true;
220 }
221 }
222 apiMutex.leave();
223 return false;
224}
225
226std::set<std::string> PsyAPI::getCurrentPostNames() {
227 std::set<std::string> postNames;
228 if (!apiMutex.enter(1000, __FUNCTION__))
229 return postNames;
230 if (currentTriggerSpec) {
231 std::list<PostSpec*>* postSpecs = currentTriggerSpec->getPostSpecs(NULL);
232 if (postSpecs && postSpecs->size()) {
233 std::list<PostSpec*>::iterator it = postSpecs->begin(), itEnd = postSpecs->end();
234 while (it != itEnd) {
235 postNames.insert((*it)->name);
236 it++;
237 }
238 }
239 delete(postSpecs);
240 }
241 apiMutex.leave();
242 return postNames;
243}
244
246 if (!apiMutex.enter(1000, __FUNCTION__))
247 return 0;
248 uint32 qSize = (uint32)inputQueue.size();
249 apiMutex.leave();
250// printf("Pointer: %llu Q: %u\n", (uint64)this, qSize);
251 return qSize;
252}
253
254std::string PsyAPI::typeToText(PsyType type) {
255 return space->manager->typeToText(type);
256}
257
258std::string PsyAPI::contextToText(PsyContext context) {
259 return space->manager->contextToText(context);
260}
261
262bool PsyAPI::begin() {
263 if (!apiMutex.enter(1000))
264 return false;
265
266 shouldContinueRunning = true;
267 startedRunning = GetTimeNow();
268 utils::GetCPUTicks(lastCPUTicks);
269 lastWallTime = startedRunning;
270
272 0, // cpu usage
273 NULL, // no input message here, set in waitForNewMessage
274 NULL, // no output message here
275 1, // run count 1, only incremented at start
276 0 // cycle count 0, only incremented at waitForNewMessage
277 );
278 apiMutex.leave();
279 return true;
280}
281
282bool PsyAPI::finish() {
283
284 if (!apiMutex.enter(1000))
285 return false;
286
287 startedRunning = 0;
288 currentCrankID = 0;
289 currentCompID = 0;
290
291 uint64 currentCPUTicks;
292 utils::GetCPUTicks(currentCPUTicks);
294 currentCPUTicks - lastCPUTicks, // cpu usage
295 NULL, // no input message here
296 NULL, // no output message here
297 0, // run count 0, only incremented at start
298 0 // cycle count 0, only incremented at waitForMessage
299 );
300 //utils::GetCPUUsage(cpuUsageBefore);
301 lastCPUTicks = currentCPUTicks;
302 lastWallTime = GetTimeNow();
303 apiMutex.leave();
304 return true;
305}
306
307bool PsyAPI::stop() {
308 apiMutex.enter(1000);
309 shouldContinueRunning = false;
310 apiMutex.leave();
311 return true;
312}
313
314
315
316// ***************** PsyProbe plugins *****************
317bool PsyAPI::addPsyProbeCustomView(const char* name, const char* templateURL) {
318 return space->addPsyProbeCustomView(currentCompID, name, templateURL);
319}
320
321
322
323uint64 PsyAPI::checkLastWaitForMessage() {
324 if (!apiMutex.enter(1000))
325 return CRANKAPI_FAILED;
326
327 // If currently running
328 if (startedRunning && currentCrankID) {
329 if (inputQueue.size() && (GetTimeAgeMS(lastWallTime) > 5000)) {
330 apiMutex.leave();
331 return lastWallTime;
332 }
333 }
334 apiMutex.leave();
335 return 0;
336}
337
338uint8 PsyAPI::addInputTrigger(uint32 crankID, uint32 compID, DataMessage* trigger, DataMessage* msg) {
339
340// printf("************ API Add Input Trigger %llu us old, Msg %llu us old...\n", GetTimeAge(trigger->getCreatedTime()), GetTimeAge(msg->getCreatedTime()));
341 if (!apiMutex.enter(1000))
342 return CRANKAPI_FAILED;
343
344 msgReceivedCount++;
345 if (startedRunning && currentCrankID) {
346 if (crankID == currentCrankID) {
347 // just add the trigger and msg and return
348 inputQueue.push(TriggerAndMessage(trigger, msg));
349 inputQueueSemaphore.signal();
350 apiMutex.leave();
351 return CRANKAPI_RUNNING;
352 }
353 else {
354 apiMutex.leave();
355 return CRANKAPI_INUSE;
356 }
357 }
358
359 // reset measurements
360 currentCrankID = crankID;
361 currentCompID = compID;
362 // CLAIM the API here, inside apiMutex, not later in begin(). The caller (the
363 // thread-pool dispatcher) releases its pool lock between this IDLE return and
364 // api->begin(), and the test above is "startedRunning && currentCrankID". If only
365 // begin() set startedRunning, a second pool thread delivering the next message for
366 // the same crank in that gap ALSO got CRANKAPI_IDLE, and two threads then ran the
367 // same crank on the same PsyAPI at once: one thread's waitForNewMessage()
368 // delete(currentMsg) freed the message the other had just popped (ASan:
369 // heap-use-after-free in addComponentStats <- waitForNewMessage, freed at the
370 // delete(currentMsg) line; test=udpservice crashed ~1 in 12 under a UDP burst).
371 // begin() re-stamps the time; finish() still clears it.
372 startedRunning = GetTimeNow();
373
374 // add the trigger and msg
375 inputQueue.push(TriggerAndMessage(trigger, msg));
376 inputQueueSemaphore.signal();
377
378 apiMutex.leave();
379 return CRANKAPI_IDLE;
380}
381
383 const char* triggerName;
384 return waitForNewMessage(ms, triggerName);
385}
386
388 return currentTriggerName;
389}
390
392 if (this->currentTriggerSpec)
393 return this->currentTriggerSpec->context;
394 else
395 return NOCONTEXT;
396}
397
398
399DataMessage* PsyAPI::waitForNewMessage(uint32 ms, const char* &triggerName) {
400
401 DataMessage* msg = NULL;
402 uint32 s;
403 uint64 currentCPUTicks;
404
405// if (!apiMutex.enter(ms ? ms : 10, __FUNCTION__))sig
406 if (!apiMutex.enter(1000, __FUNCTION__))
407 return NULL;
408
409 if (!inputQueue.size()) {
410 apiMutex.leave();
411 // possible queue.size without mutex issue?
412 if (!inputQueueSemaphore.wait(ms) || !inputQueue.size()) {
413 utils::GetCPUTicks(currentCPUTicks);
414 space->manager->componentMemory->addComponentStats(currentCompID, COMPSTATUS_RUNNING,
415 currentCPUTicks - lastCPUTicks, // cpu usage
416 NULL, // input message if any
417 NULL, // no output message here
418 0, // run count 0, only incremented at start
419 1 // cycle count
420 );
421 lastCPUTicks = currentCPUTicks;
422 lastWallTime = GetTimeNow();
423 chainCPUTicks = 0;
424 chainWallTime = 0;
425 chainCount = 0;
426 return NULL;
427 }
428// if (!apiMutex.enter(ms, __FUNCTION__))
429 if (!apiMutex.enter(1000, __FUNCTION__))
430 return NULL;
431 }
432
433 delete(currentMsg);
434 //delete(currentTriggerMsg);
435
436 // COPY, not a reference: the old code bound `TriggerAndMessage& tm` to
437 // inputQueue.front() and then immediately pop()ed, which destroys the element
438 // the reference names - every later read of tm (the while condition, the
439 // tm.first/tm.second extraction below) was a dangling read into a freed queue
440 // slot. ASan reports it as container-overflow. It survived because
441 // std::queue/deque usually leaves the popped slot's bytes intact, so the
442 // pointers still looked valid; under memory pressure or a different allocator
443 // it hands back whatever now occupies the slot and the two DataMessage* are
444 // then freed. TriggerAndMessage is a pair of pointers, so copying costs
445 // nothing. Found by Isaac on macOS.
446 TriggerAndMessage tm = inputQueue.front();
447 inputQueue.pop();
448
449 while ((inputQueue.size() > 100) && (tm.second->getPolicy() & MESSAGE_NON_GUARANTEED)) {
450 delete(tm.first);
451 delete(tm.second);
452 tm = inputQueue.front();
453 inputQueue.pop();
454 }
455
456 DataMessage* msgFirst = tm.first;
457 DataMessage* msgSecond = tm.second;
458
459 // If this message is a trigger message (has tm.first) replace currentTriggerXXX
460 if (msgFirst) {
461 delete(currentTriggerMsg);
462 currentTriggerMsg = msgFirst;
463 currentTriggerSpec = (TriggerSpec*)currentTriggerMsg->getData("TriggerSpec", s);
464 utils::strcpyavail(currentTriggerName, currentTriggerSpec->name, MAXKEYNAMELEN, true);
465 triggerName = currentTriggerName;
466 }
467 else {
468 // this is a temporary query message, keep the previous currentTriggerXXX around
469 triggerName = NULL;
470 }
471
472 //currentTriggerMsg = msgFirst;
473 //if (currentTriggerMsg) {
474 // currentTriggerSpec = (TriggerSpec*) currentTriggerMsg->getData("TriggerSpec", s);
475 // utils::strcpyavail(currentTriggerName, currentTriggerSpec->name, MAXKEYNAMELEN, true);
476 // triggerName = currentTriggerName;
477 //}
478 //else {
479 // triggerName = NULL;
480 // currentTriggerSpec = NULL;
481 //}
482 msg = msgSecond;
483 if (autoDelete)
484 currentMsg = msg;
485
486// printf("************ API Trigger %llu us old, Msg %llu us old...\n", GetTimeAge(currentTriggerMsg->getCreatedTime()), GetTimeAge(msg->getCreatedTime()));
487
488 if (msgFirst && msgSecond) {
489 chainCPUTicks = msgSecond->data->chaincputime;
490 chainWallTime = msgSecond->data->chainwalltime;
491 chainCount = msgSecond->data->chaincount;
492 }
493 else {
494 chainCPUTicks = 0;
495 chainWallTime = 0;
496 chainCount = 0;
497 }
498
499 // calc stats
500 apiMutex.leave();
501
502 // Add stats to component
503 utils::GetCPUTicks(currentCPUTicks);
504 space->manager->componentMemory->addComponentStats(currentCompID, COMPSTATUS_RUNNING,
505 currentCPUTicks - lastCPUTicks, // cpu usage
506 msg, // input message if any
507 NULL, // no output message here
508 0, // run count 0, only incremented at start
509 1 // cycle count
510 );
511 lastCPUTicks = currentCPUTicks;
512 lastWallTime = GetTimeNow();
513
514 msgInputCount++;
515 return msg;
516}
517
518
519// T1.6: wait for a joined <triggergroup> set. Reuses waitForNewMessage() to dequeue
520// (which sets currentTriggerMsg + currentTriggerName), then reads the member map that
521// deliverTriggerGroup() attached under "Members". If the dequeued delivery is not a
522// group activation, returns an empty map (and the group name is empty).
523std::map<std::string, DataMessage*> PsyAPI::waitForNewMessageGroup(uint32 ms, std::string& groupName) {
524 // Free any member messages we own from the previous grouped activation.
525 std::map<std::string, DataMessage*>::iterator git, gitEnd;
526 for (git = currentGroupMap.begin(), gitEnd = currentGroupMap.end(); git != gitEnd; git++)
527 if (git->second) delete(git->second);
528 currentGroupMap.clear();
529 groupName.clear();
530
531 const char* triggerName = NULL;
532 DataMessage* primary = waitForNewMessage(ms, triggerName);
533 // currentTriggerMsg is the delivery wrapper; it persists across timeout polls, so
534 // only treat this as a group delivery when waitForNewMessage() actually dequeued a
535 // fresh trigger this call (triggerName is non-NULL only for a fresh trigger msg).
536 // Without this guard a completed group re-fires on every subsequent timeout poll.
537 if (triggerName && currentTriggerMsg && currentTriggerMsg->getType() == CTRL_TRIGGER_GROUP) {
538 currentGroupMap = currentTriggerMsg->getAttachedMessageMap("Members");
539 groupName = triggerName;
540 }
541 else if (triggerName && primary) {
542 // Not a group delivery: hand back the single message under its trigger name so a
543 // crank calling only waitForNewMessageGroup() still sees something sensible.
544 if (triggerName) groupName = triggerName;
545 // Note: 'primary' is owned by the API (currentMsg); we do NOT copy it into the
546 // owned map to avoid a double free. Callers mixing both APIs should prefer one.
547 }
548 return currentGroupMap;
549}
550
551bool PsyAPI::setAutoDelete(bool autodel) {
552 autoDelete = autodel;
553 return true;
554}
555
556// Get current message receive time
558 uint64 t;
559 if (currentTriggerMsg && (t = currentTriggerMsg->getRecvTime()) )
560 return t;
561 else if (currentMsg)
562 return currentMsg->getRecvTime();
563 else
564 return 0;
565}
566
568 if (msgType == NOTYPE)
569 return postOutputMessage(NULL, msg);
570 if (msg) {
571 msg->setType(msgType);
572 return postOutputMessage(NULL, msg);
573 }
574 DataMessage* newMsg = new DataMessage(msgType, 0);
575 bool result = postOutputMessage("A non-existing postname", newMsg);
576 delete(newMsg);
577 return result;
578}
579
580
581int32 PsyAPI::postOutputMessage(const char* postName, DataMessage* msg) {
582
583 uint64 currentCPUTicks;
584 utils::GetCPUTicks(currentCPUTicks);
585
586 if (!apiMutex.enter(1000))
587 return POST_FAILED;
588
589 if (msg)
590 msg->addTimeUsage((uint32)(currentCPUTicks - lastCPUTicks), (uint32)GetTimeAge(lastWallTime), chainCPUTicks, chainWallTime, chainCount + 1);
591
592 uint32 currentTag = 0;
593 if (currentMsg)
594 currentTag = currentMsg->getTag();
595
596 uint32 to;
597 int32 failed = 0;
598 int32 success = 0;
599 if (!currentTriggerSpec) {
600 if (!msg) {
601 apiMutex.leave();
602 logPrint(1, "Posting none - out of context");
603 return POST_OUTOFCONTEXT;
604 }
605 if (currentTag && !msg->getTag())
606 msg->setTag(currentTag);
607 if ( (to = msg->getTo()) || msg->getType().isValid()) {
608 if (space->postMessage(msg)) {
609 //logPrint(3,"Posted direct message to component %u", to);
610 success++;
611 }
612 else {
613 logPrint(0,"Failed to post direct message to component %u", to);
614 failed++;
615 }
616 }
617 else {
618 apiMutex.leave();
619 logPrint(1,"Posting none - out of context");
620 delete(msg);
621 return POST_OUTOFCONTEXT;
622 }
623 }
624 else {
625 PostSpec* postSpec;
626 std::list<PostSpec*>* postSpecs = currentTriggerSpec->getPostSpecs(postName);
627 if (!postSpecs || !postSpecs->size()) {
628 delete(postSpecs);
629 postSpecs = NULL;
630 if (msg)
631 postSpecs = currentTriggerSpec->getPostSpecs(msg->getType());
632 if (!postSpecs || !postSpecs->size()) {
633 delete(postSpecs);
634 apiMutex.leave();
635 logPrint(2, "Posting nothing - no post specs match for post name '%s'", postName);
636 //logPrint(0, "Posting nothing - no post specs match for post name '%s'\n%s",
637 // postName, currentTriggerSpec->toXML().c_str());
638 delete(msg);
639 return POST_NOSPEC;
640 }
641 }
642
643 uint64 msgTTL = 0;
644 if (!msg) {
645 msg = new DataMessage();
646 msg->addTimeUsage((uint32)(currentCPUTicks - lastCPUTicks), (uint32)GetTimeAge(lastWallTime), chainCPUTicks, chainWallTime, chainCount + 1);
647 }
648 else
649 msgTTL = msg->getTTL();
650
651 if (currentTag && !msg->getTag())
652 msg->setTag(currentTag);
653
654 // uint32 msgTTL = msg->getTTL();
655
656 std::list<PostSpec*>::iterator it = postSpecs->begin(), itEnd = postSpecs->end();
657 while (it != itEnd) {
658 if (postSpec = *it) {
659 if (postSpec->contextchange.isValid()) {
661 msg->setContextChange(postSpec->contextchange);
662 // msg->setData("Context", &postSpec->contextchange, sizeof(PsyContext));
663 }
664 else {
665 msg->setType(postSpec->type);
666 }
667 postSpec->addContentToMsg(msg);
668 //if (strlen(postSpec->contentKey) && !msg->getString(postSpec->contentKey))
669 // msg->setString(postSpec->contentKey, postSpec->content);
670 msg->setMultiple(currentCompID, postSpec->to, postSpec->tag, msgTTL ? msgTTL : postSpec->ttl, postSpec->policy, GetTimeNow());
671
672 if (space->postMessage(msg)) {
673 //logPrint(3,"Posted msg delivered to %u", postSpec->to);
674 success++;
675 }
676 else {
677 logPrint(0,"Failed to deliver posted msg to %u", postSpec->to);
678 failed++;
679 }
680 }
681 it++;
682 }
683 delete(postSpecs);
684 }
685
686 msgPostedCount++;
687 msgSentCount += success;
688
689 if (!success)
690 logPrint(0,"No msgs were delivered at postOutputMessage", success);
691 //else
692 // logPrint(3,"Posted msg was delivered to %u receivers", success);
693
694 // Add stats to component
695 space->manager->componentMemory->addComponentStats(currentCompID, COMPSTATUS_RUNNING,
696 currentCPUTicks - lastCPUTicks, // cpu usage
697 NULL, // no input message here
698 msg, // output message
699 0, // run count 0, only incremented at start
700 0 // cycle count 0, only incremented at waitForNewMessage
701 );
702 // utils::GetCPUUsage(cpuUserBefore, cpuKernelBefore);
703 lastCPUTicks = currentCPUTicks;
704
705 apiMutex.leave();
706 delete(msg);
707 if (!success && failed)
708 return POST_FAILED;
709 else
710 return success;
711}
712
713// ***************** Signals *****************
714bool PsyAPI::emitSignal(const char* name, DataMessage* msg) {
715
716 if (!apiMutex.enter(1000))
717 return false;
718
719 if (!currentTriggerSpec) {
720 apiMutex.leave();
721 delete(msg);
722 return false;
723 }
724
725 SignalSpec* signalSpec = currentTriggerSpec->getSignalSpec(name);
726 if (!signalSpec) {
727 apiMutex.leave();
728 delete(msg);
729 return false;
730 }
731
732 if (!msg)
733 msg = new DataMessage();
734 msg->setType(signalSpec->type);
735 if (space->emitSignal(signalSpec->type, msg)) {
736 apiMutex.leave();
737 return true;
738 }
739 else {
740 apiMutex.leave();
741 delete(msg);
742 return false;
743 }
744}
745
746DataMessage* PsyAPI::waitForSignal(const char* name, uint32 timeout, uint64 lastReceivedTime) {
747
748 apiMutex.enter(3000, __FUNCTION__);
749
750 if (!currentTriggerSpec) {
751 apiMutex.leave();
752 return NULL;
753 }
754
755 SignalSpec* signalSpec = currentTriggerSpec->getSignalSpec(name);
756 if (!signalSpec) {
757 apiMutex.leave();
758 return NULL;
759 }
760
761 apiMutex.leave();
762 DataMessage* msg = space->waitForSignal(signalSpec->type, timeout, lastReceivedTime);
763
764 if (msg) {
765 apiMutex.enter(3000, __FUNCTION__);
766 if (currentSignalMsg)
767 delete(currentSignalMsg);
768 currentSignalMsg = msg;
769 apiMutex.leave();
770 return msg;
771 }
772 else
773 return NULL;
774}
775
776
777
778uint8 PsyAPI::retrieve(std::list<DataMessage*> &result, const char* name, uint32 maxcount, uint32 maxage, uint32 timeout) {
779 if (!apiMutex.enter(1000))
780 return QUERY_FAILED;
781
782 if (!currentTriggerSpec) {
783 apiMutex.leave();
784 return QUERY_FAILED;
785 }
786
787 RetrieveSpec* retrieveSpec = currentTriggerSpec->getRetrieveSpec(name);
788 if (!retrieveSpec) {
789 apiMutex.leave();
790 return QUERY_NAME_UNKNOWN;
791 }
792
793 RetrieveSpec* specCopy = new RetrieveSpec;
794 memcpy(specCopy, retrieveSpec, sizeof(RetrieveSpec));
795
796 if (maxcount)
797 specCopy->maxcount = maxcount;
798 if (maxage)
799 specCopy->maxage = maxage;
800
801 apiMutex.leave();
802 uint8 res = retrieve(result, specCopy, timeout);
803 return res;
804}
805
806uint8 PsyAPI::retrieveTimeParam(std::list<DataMessage*> &result, const char* name, uint64 startTime, uint64 endTime, uint32 maxcount, uint32 maxage, uint32 timeout) {
807 std::list<DataMessage*> list;
808 if (!startTime)
809 return QUERY_FAILED;
810 if (!apiMutex.enter(1000))
811 return QUERY_FAILED;
812
813 if (!currentTriggerSpec) {
814 apiMutex.leave();
815 return QUERY_FAILED;
816 }
817
818 RetrieveSpec* retrieveSpec = currentTriggerSpec->getRetrieveSpec(name);
819 if (!retrieveSpec) {
820 apiMutex.leave();
821 return QUERY_NAME_UNKNOWN;
822 }
823
824 RetrieveSpec* specCopy = new RetrieveSpec;
825 memcpy(specCopy, retrieveSpec, sizeof(RetrieveSpec));
826
827 specCopy->startTime = startTime;
828 if (endTime)
829 specCopy->endTime = endTime;
830 if (maxcount)
831 specCopy->maxcount = maxcount;
832 if (maxage)
833 specCopy->maxage = maxage;
834
835 apiMutex.leave();
836 uint8 res = retrieve(result, specCopy, timeout);
837 return res;
838}
839
840uint8 PsyAPI::retrieveStringParam(std::list<DataMessage*> &result, const char* name, const char* startString, const char* endString, uint32 maxcount, uint32 maxage, uint32 timeout) {
841 std::list<DataMessage*> list;
842 if (!startString || !strlen(startString))
843 return QUERY_FAILED;
844
845 if (!apiMutex.enter(1000))
846 return QUERY_FAILED;
847
848 if (!currentTriggerSpec) {
849 apiMutex.leave();
850 return QUERY_FAILED;
851 }
852
853 RetrieveSpec* retrieveSpec = currentTriggerSpec->getRetrieveSpec(name);
854 if (!retrieveSpec) {
855 apiMutex.leave();
856 return QUERY_NAME_UNKNOWN;
857 }
858
859 RetrieveSpec* specCopy = new RetrieveSpec;
860 memcpy(specCopy, retrieveSpec, sizeof(RetrieveSpec));
861
862 utils::strcpyavail(specCopy->startString, startString, MAXVALUENAMELEN, true);
863 if (endString)
864 utils::strcpyavail(specCopy->endString, endString, MAXVALUENAMELEN, true);
865 if (maxcount)
866 specCopy->maxcount = maxcount;
867 if (maxage)
868 specCopy->maxage = maxage;
869
870 apiMutex.leave();
871 uint8 res = retrieve(result, specCopy, timeout);
872 return res;
873}
874
875uint8 PsyAPI::retrieveIntegerParam(std::list<DataMessage*> &result, const char* name, int64 startInteger, int64 endInteger, uint32 maxcount, uint32 maxage, uint32 timeout) {
876 std::list<DataMessage*> list;
877 if (startInteger == INT64_NOVALUE)
878 return QUERY_FAILED;
879
880 if (!apiMutex.enter(1000))
881 return QUERY_FAILED;
882
883 if (!currentTriggerSpec) {
884 apiMutex.leave();
885 return QUERY_FAILED;
886 }
887
888 RetrieveSpec* retrieveSpec = currentTriggerSpec->getRetrieveSpec(name);
889 if (!retrieveSpec) {
890 apiMutex.leave();
891 return QUERY_NAME_UNKNOWN;
892 }
893
894 RetrieveSpec* specCopy = new RetrieveSpec;
895 memcpy(specCopy, retrieveSpec, sizeof(RetrieveSpec));
896
897 specCopy->startInt = startInteger;
898 if (endInteger != INT64_NOVALUE)
899 specCopy->endInt = endInteger;
900 if (maxcount)
901 specCopy->maxcount = maxcount;
902 if (maxage)
903 specCopy->maxage = maxage;
904
905 apiMutex.leave();
906 uint8 res = retrieve(result, specCopy, timeout);
907 return res;
908}
909
910uint8 PsyAPI::retrieveFloatParam(std::list<DataMessage*> &result, const char* name, float64 startFloat, float64 endFloat, uint32 maxcount, uint32 maxage, uint32 timeout) {
911 std::list<DataMessage*> list;
912 if (startFloat == FLOAT64_NOVALUE)
913 return QUERY_FAILED;
914 if (!apiMutex.enter(1000))
915 return QUERY_FAILED;
916
917 if (!currentTriggerSpec) {
918 apiMutex.leave();
919 return QUERY_FAILED;
920 }
921
922 RetrieveSpec* retrieveSpec = currentTriggerSpec->getRetrieveSpec(name);
923 if (!retrieveSpec) {
924 apiMutex.leave();
925 return QUERY_NAME_UNKNOWN;
926 }
927
928 RetrieveSpec* specCopy = new RetrieveSpec;
929 memcpy(specCopy, retrieveSpec, sizeof(RetrieveSpec));
930
931 specCopy->startFloat = startFloat;
932 if (endFloat != FLOAT64_NOVALUE)
933 specCopy->endFloat = endFloat;
934 if (maxcount)
935 specCopy->maxcount = maxcount;
936 if (maxage)
937 specCopy->maxage = maxage;
938
939 apiMutex.leave();
940 uint8 res = retrieve(result, specCopy, timeout);
941 return res;
942}
943
944uint8 PsyAPI::retrieve(std::list<DataMessage*> &result, RetrieveSpec* spec, uint32 timeout) {
945 if (!spec)
946 return QUERY_FAILED;
947 spec->origin = currentCompID;
948
949 DataMessage* msg = new DataMessage(PsyAPI::CTRL_QUERY, this->currentCompID, spec->source, timeout);
950 msg->setData("RetrieveSpec", (char*)spec, sizeof(RetrieveSpec));
951
952 DataMessage* resultMsg = NULL;
953 uint8 status = space->query(msg, &resultMsg, timeout);
954 delete(msg);
955
956 if (!resultMsg) {
957 if (status == QUERY_FAILED)
958 logPrint(0,"Query failed and did not return a message...");
959 delete(spec);
960 return status;
961 }
962
963 uint32 size;
964 int64 count;
965 const char* data = resultMsg->getData("ReplyData", size);
966 if (!data || !resultMsg->getInt("ReplyCount", count)) {
967 if (!data)
968 logPrint(0,"Query did not return any ReplyData...");
969 else
970 logPrint(0,"Query did not return any ReplyCount...");
971 delete(resultMsg);
972 delete(spec);
973 return QUERY_FAILED;
974 }
975
976 DataMessage* subMsg;
977 const char* src = data;
978 for (uint32 n=0; n<(uint32)count; n++) {
979 if (GetObjID(src) != DATAMESSAGEID)
980 break;
981 subMsg = new DataMessage(src);
982 result.push_back(subMsg);
983 src += subMsg->getSize();
984 }
985
986 delete(spec);
987 delete(resultMsg);
988 return QUERY_SUCCESS;
989}
990
991bool PsyAPI::addSubscription(const char* xml) {
992 if (!apiMutex.enter(1000))
993 return false;
994 DataMessage* msg = new DataMessage(PsyAPI::CTRL_ADDSUBSCRIPTION, this->currentCompID, 0, 5000);
995 msg->setString("Subscription", xml);
996
997 DataMessage* resultMsg = NULL;
998 uint8 status = space->query(msg, &resultMsg, 5000);
999 delete(msg);
1000
1001 if (resultMsg)
1002 delete(resultMsg);
1003
1004 apiMutex.leave();
1005 return (status == QUERY_SUCCESS);
1006}
1007
1008
1009uint8 PsyAPI::queryCatalog(DataMessage** resultMsg, const char* name, DataMessage* msg, uint32 timeout) {
1010 *resultMsg = NULL;
1011 if (!msg)
1012 return QUERY_FAILED;
1013 if (!apiMutex.enter(1000))
1014 return QUERY_FAILED;
1015
1016 if (!currentTriggerSpec) {
1017 logPrint(1, "Query '%s' cannot execute before a trigger message has been processed", name);
1018 apiMutex.leave();
1019 return QUERY_FAILED;
1020 }
1021
1022 QuerySpec* querySpec = currentTriggerSpec->getQuerySpec(name);
1023 if (!querySpec) {
1024 logPrint(1, "Query '%s' not found in PsySpec", name);
1025 apiMutex.leave();
1026 return QUERY_NAME_UNKNOWN;
1027 }
1028
1029 if (strlen(querySpec->operation))
1030 msg->setString("Operation", querySpec->operation);
1031 if (strlen(querySpec->type))
1032 msg->setString("Type", querySpec->type);
1033 if (strlen(querySpec->ext))
1034 msg->setString("Ext", querySpec->ext);
1035 if (strlen(querySpec->subdir))
1036 msg->setString("Subdir", querySpec->subdir);
1037 if (strlen(querySpec->key))
1038 msg->setString("Key", querySpec->key);
1039 if (strlen(querySpec->value))
1040 msg->setString("Value", querySpec->value);
1041 if (querySpec->binary)
1042 msg->setString("Binary", "yes");
1043
1044 if (strlen(querySpec->hostName)) {
1045 // This is a query for another system
1046 if (!querySpec->ipHost) {
1047 if (!utils::LookupIPAddress(querySpec->hostName, querySpec->ipHost)) {
1048 apiMutex.leave();
1050 }
1051 }
1052 if (!querySpec->ipPort)
1053 querySpec->ipPort = 10000;
1054 // now we have all the info we need
1056 msg->setFrom(currentCompID);
1057 msg->setTo(0);
1058 msg->setString("INTERSYSTEM_SOURCENAME", querySpec->sourceName);
1059 msg->setInt("INTERSYSTEM_ADDRESS", querySpec->ipHost);
1060 msg->setInt("INTERSYSTEM_PORT", querySpec->ipPort);
1061 }
1062 else {
1064 msg->setFrom(currentCompID);
1065 msg->setTo(querySpec->source);
1066 }
1067
1068 apiMutex.leave();
1069 uint8 status = space->query(msg, resultMsg, timeout);
1070 delete(msg);
1071
1072 return status;
1073}
1074
1075uint8 PsyAPI::queryRemoteCatalog(DataMessage** resultMsg, const char* componentName, const char* ipAddress, uint16 port, DataMessage* msg, uint32 timeout) {
1076 uint32 addr = 0;
1077 if (!utils::LookupIPAddress(ipAddress, addr))
1078 return QUERY_NOT_AVAILABLE;
1079 return queryRemoteCatalog(resultMsg, componentName, addr, port, msg, timeout);
1080}
1081
1082uint8 PsyAPI::queryRemoteCatalog(DataMessage** resultMsg, uint32& chosenAddress, const char* componentName, uint32* ipAddresses, uint32 numAddresses, uint16 port, DataMessage* msg, uint32 timeout) {
1083 if (chosenAddress > numAddresses)
1084 return QUERY_NOT_AVAILABLE;
1085
1086 uint8 result;
1087 if (chosenAddress) {
1088 // try this address first
1089 result = queryRemoteCatalog(resultMsg, componentName, ipAddresses[chosenAddress-1], port, msg, timeout);
1090 if (result != QUERY_NOT_REACHABLE)
1091 return result;
1092 // if it failed, go back and try all again
1093 }
1094
1095 chosenAddress = 0;
1096 for (uint32 n = 0; n < numAddresses; n++) {
1097 result = queryRemoteCatalog(resultMsg, componentName, ipAddresses[n], port, msg, timeout);
1098 if (result != QUERY_NOT_REACHABLE) {
1099 chosenAddress = n + 1;
1100 return result;
1101 }
1102 // else continue trying next address
1103 }
1104 // and give up if none of them connects
1105 return QUERY_NOT_REACHABLE;
1106}
1107
1108uint8 PsyAPI::queryRemoteCatalog(DataMessage** resultMsg, const char* componentName, uint32 ipAddress, uint16 port, DataMessage* msg, uint32 timeout) {
1109 *resultMsg = NULL;
1110 if (!msg)
1111 return QUERY_FAILED;
1112
1113 // This is a query for another system
1114 // we have all the info we need
1116 msg->setFrom(currentCompID);
1117 msg->setTo(0);
1118 msg->setString("INTERSYSTEM_SOURCENAME", componentName);
1119 msg->setInt("INTERSYSTEM_ADDRESS", ipAddress);
1120 msg->setInt("INTERSYSTEM_PORT", port);
1121
1122 uint8 status = space->query(msg, resultMsg, timeout);
1123 delete(msg);
1124
1125 return status;
1126}
1127
1128
1129
1130
1131uint8 PsyAPI::queryCatalog(char** result, uint32 &resultsize, const char* name, const char* query, const char* operation, const char* data, uint32 datasize, uint32 timeout) {
1132 *result = NULL;
1133 if (!apiMutex.enter(1000, "Replying to query"))
1134 return QUERY_FAILED;
1135
1136 if (!currentTriggerSpec) {
1137 apiMutex.leave();
1138 return QUERY_FAILED;
1139 }
1140
1141 QuerySpec* querySpec = currentTriggerSpec->getQuerySpec(name);
1142 if (!querySpec) {
1143 apiMutex.leave();
1144 return QUERY_NAME_UNKNOWN;
1145 }
1146
1147 DataMessage* msg = new DataMessage();
1148
1149 msg->setString("Name", querySpec->name);
1150
1151 if (query && strlen(query))
1152 msg->setString("Query", query);
1153 if (data && datasize)
1154 msg->setData("Data", data, datasize);
1155 if (operation && strlen(operation))
1156 msg->setString("Operation", operation);
1157 else if (strlen(querySpec->operation))
1158 msg->setString("Operation", querySpec->operation);
1159
1160 if (strlen(querySpec->type))
1161 msg->setString("Type", querySpec->type);
1162 if (strlen(querySpec->ext))
1163 msg->setString("Ext", querySpec->ext);
1164 if (strlen(querySpec->subdir))
1165 msg->setString("Subdir", querySpec->subdir);
1166 if (strlen(querySpec->key))
1167 msg->setString("Key", querySpec->key);
1168 if (strlen(querySpec->value))
1169 msg->setString("Value", querySpec->value);
1170 if (querySpec->binary)
1171 msg->setString("Binary", "yes");
1172
1173 if (strlen(querySpec->hostName)) {
1174 // This is a query for another system
1175 if (!querySpec->ipHost) {
1176 if (!utils::LookupIPAddress(querySpec->hostName, querySpec->ipHost)) {
1177 apiMutex.leave();
1179 }
1180 }
1181 if (!querySpec->ipPort)
1182 querySpec->ipPort = 10000;
1183 // now we have all the info we need
1185 msg->setFrom(currentCompID);
1186 msg->setTo(0);
1187 msg->setString("INTERSYSTEM_SOURCENAME", querySpec->sourceName);
1188 msg->setInt("INTERSYSTEM_ADDRESS", querySpec->ipHost);
1189 msg->setInt("INTERSYSTEM_PORT", querySpec->ipPort);
1190 }
1191 else {
1193 msg->setFrom(currentCompID);
1194 msg->setTo(querySpec->source);
1195 }
1196
1197 apiMutex.leave();
1198 DataMessage* resultMsg = NULL;
1199 uint8 status = space->query(msg, &resultMsg, timeout);
1200 delete(msg);
1201
1202 if (resultMsg) {
1203 *result = resultMsg->getDataCopy("ReplyData", resultsize);
1204 delete(resultMsg);
1205 }
1206
1207 return status;
1208}
1209
1210bool PsyAPI::queryReply(uint32 id, uint8 status, char* data, uint32 size, uint32 count) {
1211 DataMessage* msg = NULL;
1212 if (data && size) {
1213 msg = new DataMessage(PsyAPI::CTRL_QUERY_REPLY, currentCompID);
1214 msg->setData("ReplyData", data, size);
1215 msg->setInt("ReplyCount", count);
1216 // decide on EOL ###################
1217 }
1218 bool res = queryReply(id, status, msg);
1219 //delete(msg);
1220 return res;
1221}
1222
1223bool PsyAPI::queryReply(uint32 id, uint8 status, DataMessage* msg) {
1224 if (!apiMutex.enter(1000, "Replying to query"))
1225 return false;
1226 bool res = space->queryReply(id, status, msg);
1227 apiMutex.leave();
1228 return res;
1229}
1230
1231bool PsyAPI::logPrint(int level, const char *formatstring, ... ) {
1232 char* str;
1233 uint32 lenStr;
1234 va_list args;
1235 va_start(args, formatstring);
1236 str = utils::StringFormatVA(lenStr, formatstring, args);
1237 va_end(args);
1238 if (!str || !lenStr) {
1239 free(str);
1240 return false;
1241 }
1242
1243 char* name = new char[256];
1244 if (!space->manager->componentMemory->getComponentName(currentCompID, name, 255)) {
1245 delete [] name;
1246 free(str);
1247 return false;
1248 }
1249
1250 uint32 lenNewStr;
1251 char* newStr = utils::StringFormat(lenNewStr, "[%s] %s", name, str);
1252 // delete[] for `name` (new char[256] at the top of this function), free() for
1253 // `str` and `newStr` (StringFormat returns a vasprintf/malloc'd buffer,
1254 // Utils.cpp:7644). The two allocators sit two lines apart here, which is
1255 // exactly how this function ended up mismatched in the first place.
1256 delete [] name;
1257 free(str);
1258
1259 LogEntry* entry = (LogEntry*) malloc(sizeof(LogEntry)+lenNewStr+1);
1260 entry->size = sizeof(LogEntry)+lenNewStr+1;
1261 entry->cid = LOGENTRYID;
1262 entry->time = GetTimeNow();
1263 entry->source = currentCompID;
1264 entry->subject = LOG_COMPONENT;
1265 entry->level = (uint8)level;
1266 entry->type = LOGPRINT;
1267 entry->setText(newStr, lenNewStr);
1268 free(newStr);
1269
1270 return space->logEntry(entry);
1271// return LogPrint(this->currentCompID, LOG_COMPONENT, level, str);
1272}
1273
1274} // namespace cmlabs
#define COMPSTATUS_STARTING
Component is starting up.
#define COMPSTATUS_FINISHED
Component finished/stopped.
#define COMPSTATUS_RUNNING
Component is executing a run.
#define LOGENTRYID
Definition ObjectIDs.h:55
#define DATAMESSAGEID
Definition ObjectIDs.h:75
#define GetObjID(data)
Extract the cid field from a binary object block: the uint32 at byte offset 4 (after the leading size...
Definition ObjectIDs.h:26
PsyAPI — the component-facing API handle of the CMSDK.
#define QUERY_NOT_REACHABLE
The target could not be reached (e.g.
Definition PsyAPI.h:62
#define QUERY_SUCCESS
The query succeeded.
Definition PsyAPI.h:60
#define POST_NOSPEC
Posting attempted before any trigger arrived (no active spec).
Definition PsyAPI.h:48
#define POST_FAILED
An error occurred while posting.
Definition PsyAPI.h:47
#define QUERY_NOT_AVAILABLE
The target exists but is not available.
Definition PsyAPI.h:61
#define CRANKAPI_RUNNING
The crank is currently executing.
Definition PsyAPI.h:40
#define QUERY_FAILED
General failure.
Definition PsyAPI.h:55
#define QUERY_COMPONENT_UNKNOWN
The target component is unknown.
Definition PsyAPI.h:58
#define POST_OUTOFCONTEXT
The crank's context is no longer active.
Definition PsyAPI.h:49
#define CRANKAPI_IDLE
The crank is idle, waiting for input.
Definition PsyAPI.h:41
#define LOG_COMPONENT
Log source id used by components when writing entries to the system log.
Definition PsyAPI.h:68
#define CRANKAPI_FAILED
The API could not be obtained or is invalid.
Definition PsyAPI.h:38
#define CRANKAPI_INUSE
The API is already in use by another thread.
Definition PsyAPI.h:39
#define QUERY_NAME_UNKNOWN
The query name is not defined in the spec.
Definition PsyAPI.h:57
#define MESSAGE_NON_GUARANTEED
Delivery policy flag: message delivery is not guaranteed (may be dropped under load).
static struct PsyType NOTYPE
The empty/unset message type (isValid() == false).
Definition Types.h:436
#define FLOAT64_NOVALUE
Definition Types.h:81
static struct PsyContext NOCONTEXT
The empty/unset context (isValid() == false).
Definition Types.h:437
#define INT64_NOVALUE
Definition Types.h:80
#define LOGPRINT
Definition Utils.h:210
#define MAXKEYNAMELEN
Definition Utils.h:85
#define MAXCOMMANDLINELEN
Definition Utils.h:88
#define MAXSCRIPTLEN
Definition Utils.h:91
#define MAXVALUENAMELEN
Definition Utils.h:86
bool addComponentStats(uint32 cid, uint8 status, uint64 usageCPUTicks, DataMessage *inputMsg, DataMessage *outputMsg, uint32 runCount, uint32 cycleCount)
Fold a run's activity into the component's stats (counters, rings, CPU ticks).
The central Psyclone data container: a self-contained binary message with typed, named user entries.
bool addTimeUsage(uint32 cycleCPUTime, uint32 cycleWallTime, uint32 chainCPUTime=0, uint32 chainWallTime=0, uint32 chainCount=0)
addTimeUsage()
bool setString(const char *key, const char *value)
setString(const char* key, const char* value)
bool getInt(const char *key, int64 &value)
getInt(const char* key, int64& value)
bool setInt(const char *key, int64 value)
setInt(const char* key, int64 value)
bool setTag(uint32 tag)
setTag(uint32 tag)
char * getDataCopy(const char *key, uint32 &size)
getDataCopy(const char* key, uint32& size)
DataMessageHeader * data
Pointer to the message's flat memory block (header + user entries).
PsyType getType()
getType()
const char * getData(const char *key, uint32 &size)
getData(const char* key, uint32& size)
uint32 getSize()
getSize() Get message size Many types of data of any size can be put into a message as user entries; ...
bool setFrom(uint32 from)
setFrom(uint32 from)
bool setTo(uint32 to)
setTo(uint32 to)
bool setType(PsyType &type)
setType(PsyType &type)
uint64 getTTL()
getTTL()
uint32 getTag()
getTag() Retrieve and return message tag id Tags can be used to segment data temporally,...
bool setData(const char *key, const char *value, uint32 size)
setData(const char* key, const char* value, uint32 size)
uint32 getTo()
getTo()
bool setMultiple(uint32 from, uint32 to, uint32 tag, uint64 ttl, uint8 policy, uint64 sendtime)
setMultiple(uint32 from, uint32 to, uint32 tag, uint64 ttl, uint8 policy, uint64 sendtime) Set multip...
bool setContextChange(PsyContext &context)
setContextChange(PsyContext& context)
ComponentMemory * componentMemory
Accessor for the component registry.
The API handle a component (crank) uses to talk to the Psyclone system.
Definition PsyAPI.h:82
bool setAutoDelete(bool autodel)
Internal use only.
Definition PsyAPI.cpp:551
static struct PsyType CTRL_CONTEXT_CHANGE
Announces a system context change.
Definition PsyAPI.h:94
static const char * fromPythonAddressOf(unsigned long long ptr)
Internal use only — debug helper returning a printable address string for a Python-held pointer.
Definition PsyAPI.cpp:76
PsyContext getCurrentTriggerContext()
Get the context of the current trigger, just retrieved using waitForNewMessage().
Definition PsyAPI.cpp:391
PsyAPI(PsySpace *space)
Constructor from a PsySpace.
Definition PsyAPI.cpp:30
uint8 retrieveIntegerParam(std::list< DataMessage * > &result, const char *name, int64 startInteger, int64 endInteger=INT64_NOVALUE, uint32 maxcount=0, uint32 maxage=0, uint32 timeout=5000)
Used by a module to retrieve messages from a whiteboard.
Definition PsyAPI.cpp:875
bool isRunning()
Internal use only.
Definition PsyAPI.cpp:80
std::string contextToText(PsyContext context)
Get textual representation of the context.
Definition PsyAPI.cpp:258
uint8 retrieve(std::list< DataMessage * > &result, const char *name, uint32 maxcount=0, uint32 maxage=0, uint32 timeout=5000)
Retrieve stored messages from a whiteboard, by named <retrieve> spec entry.
Definition PsyAPI.cpp:778
static struct PsyType CTRL_TRIGGER_GROUP
T1.6: wraps a <triggergroup> joined-set delivery (member map) to a component.
Definition PsyAPI.h:98
static PsyAPI * fromPython(unsigned long long ptr)
Internal use only.
Definition PsyAPI.cpp:72
bool addSubscription(const char *xml)
This function adds triggers and posts to an existing registration.
Definition PsyAPI.cpp:991
bool addPsyProbeCustomView(const char *name, const char *templateURL)
Add a custom module view tab for the PsyProbe web interface by providing a template file.
Definition PsyAPI.cpp:317
~PsyAPI()
Destructor for the PsyAPI.
Definition PsyAPI.cpp:54
std::string getCommandlineBasedir()
Get the base dir that Psyclone is running from.
Definition PsyAPI.cpp:106
int32 postOutputMessage(const char *postName=NULL, DataMessage *msg=NULL)
Post the crank's output according to the spec's post entries.
Definition PsyAPI.cpp:581
bool shouldContinue()
Check whether the crank should keep running, or exit its loop.
Definition PsyAPI.cpp:93
bool hasCurrentRetrieveName(const char *name)
Check to see if the retrieve name is currently active - i.e.
Definition PsyAPI.cpp:173
bool emitSignal(const char *name, DataMessage *msg=NULL)
Emit a signal by its spec name.
Definition PsyAPI.cpp:714
bool hasCurrentPostName(const char *name)
Check to see if the post name is currently active - i.e.
Definition PsyAPI.cpp:213
bool queryReply(uint32 id, uint8 status, char *data, uint32 size, uint32 count)
Used by a module to reply to an incoming query by id.
Definition PsyAPI.cpp:1210
std::map< std::string, DataMessage * > waitForNewMessageGroup(uint32 ms, std::string &groupName)
T1.6: Wait for the next <triggergroup> joined-set delivery from the input queue.
Definition PsyAPI.cpp:523
std::string getCurrentScript()
Internal use only.
Definition PsyAPI.cpp:147
static struct PsyType CTRL_QUERY_REPLY
Carries a query reply back to the asker.
Definition PsyAPI.h:100
bool setCommandlineBasedir(const char *cmdlineBasedir)
Internal use only.
Definition PsyAPI.cpp:110
std::string getOtherModuleName(uint32 id)
Get the name of another module by id.
Definition PsyAPI.cpp:124
DataMessage * waitForSignal(const char *name, uint32 timeout, uint64 lastReceivedTime=0)
Wait for a signal (latest-value broadcast) by its spec name.
Definition PsyAPI.cpp:746
uint8 queryCatalog(char **result, uint32 &resultsize, const char *name, const char *query, const char *operation=NULL, const char *data=NULL, uint32 datasize=0, uint32 timeout=5000)
Send a query to another module or catalog by named <query> spec entry, receiving raw bytes back.
Definition PsyAPI.cpp:1131
uint32 getInputQueueSize()
Get the size of the input queue, i.e.
Definition PsyAPI.cpp:245
uint64 getCurrentMessageReceiveTime()
Get the time the current trigger (or, failing that, the current message) was received by the system,...
Definition PsyAPI.cpp:557
uint8 retrieveStringParam(std::list< DataMessage * > &result, const char *name, const char *startString, const char *endString=NULL, uint32 maxcount=0, uint32 maxage=0, uint32 timeout=5000)
Used by a module to retrieve messages from a whiteboard.
Definition PsyAPI.cpp:840
DataMessage * waitForNewMessage(uint32 ms)
Wait for the next trigger message from the component's input queue.
Definition PsyAPI.cpp:382
uint8 queryRemoteCatalog(DataMessage **resultMsg, const char *componentName, const char *ipAddress, uint16 port, DataMessage *msg, uint32 timeout=5000)
Send a query to a component in a different Psyclone system by hostname/IP.
Definition PsyAPI.cpp:1075
bool logPrint(int level, const char *formatstring,...)
Write a printf-style entry to the component's log (and the console when level is below the logging th...
Definition PsyAPI.cpp:1231
static struct PsyType CTRL_QUERY
Carries a query to a component/catalog.
Definition PsyAPI.h:99
std::set< std::string > getCurrentPostNames()
Get a list of post names currently active - i.e.
Definition PsyAPI.cpp:226
static struct PsyType CTRL_ADDSUBSCRIPTION
Adds triggers/posts to a registration at runtime.
Definition PsyAPI.h:103
friend class PsySpace
Definition PsyAPI.h:83
bool hasCurrentQueryName(const char *name)
Check to see if the query name is currently active - i.e.
Definition PsyAPI.cpp:200
std::string getCurrentTriggerName()
Get the name of the current trigger, i.e.
Definition PsyAPI.cpp:387
std::string getCurrentScriptFilename()
Internal use only.
Definition PsyAPI.cpp:162
static struct PsyType CTRL_INTERSYSTEM_QUERY
Query crossing to a different Psyclone system.
Definition PsyAPI.h:105
std::string typeToText(PsyType type)
Get textual representation of the type.
Definition PsyAPI.cpp:254
uint8 retrieveFloatParam(std::list< DataMessage * > &result, const char *name, float64 startFloat, float64 endFloat=FLOAT64_NOVALUE, uint32 maxcount=0, uint32 maxage=0, uint32 timeout=5000)
Used by a module to retrieve messages from a whiteboard.
Definition PsyAPI.cpp:910
std::string getModuleName()
Get the module name.
Definition PsyAPI.cpp:120
uint8 retrieveTimeParam(std::list< DataMessage * > &result, const char *name, uint64 startTime, uint64 endTime=0, uint32 maxcount=0, uint32 maxage=0, uint32 timeout=5000)
Used by a module to retrieve messages from a whiteboard.
Definition PsyAPI.cpp:806
bool hasCurrentSignalName(const char *name)
Check to see if the signal name is currently active - i.e.
Definition PsyAPI.cpp:186
std::string getCurrentScriptLanguage()
Internal use only.
Definition PsyAPI.cpp:132
MemoryManager * manager
The process-local memory manager: entry point to the node's shared-memory fabric. Owned by the space.
Definition PsySpace.h:339
bool leave()
Release the mutex.
Definition Utils.cpp:1330
bool enter()
Block until the mutex is acquired.
Definition Utils.cpp:1158
uint64 GetTimeNow()
Return the current absolute time (µs since year 0) according to the TMC.
Definition PsyTime.cpp:69
int32 GetTimeAgeMS(uint64 t)
Age of a timestamp relative to now, in milliseconds.
Definition PsyTime.cpp:35
int64 GetTimeAge(uint64 t)
Age of a timestamp relative to now.
Definition PsyTime.cpp:25
bool GetCPUTicks(ThreadHandle hThread, uint64 &ticks)
Get accumulated CPU time of a specific thread.
Definition Utils.cpp:3596
uint32 strcpyavail(char *dst, const char *src, uint32 maxlen, bool copyAvailable)
Bounded strcpy that always NUL-terminates.
Definition Utils.cpp:7510
char * StringFormatVA(uint32 &size, const char *format, va_list args)
va_list core used by the other StringFormat overloads.
Definition Utils.cpp:8020
bool LookupIPAddress(const char *name, uint32 &address)
Resolve a hostname to an IPv4 address.
Definition Utils.cpp:6800
std::string StringFormat(const char *format,...)
printf into a std::string.
Definition Utils.cpp:8080
std::pair< DataMessage *, DataMessage * > TriggerAndMessage
Pairing of a trigger message and its accompanying data message, as queued for a crank's input.
Definition PsyAPI.h:71
Hierarchical execution-context identifier.
Definition Types.h:284
bool isValid()
Definition Types.h:289
Hierarchical message type identifier — the key used for publish/subscribe matching in Psyclone.
Definition Types.h:123
bool isValid()
A type is valid if its root level is non-zero.
Definition Types.h:126
uint32 chaincputime
Accumulated CPU time across the whole causal message chain, in microseconds.
uint32 chainwalltime
Accumulated wall time across the whole causal message chain, in microseconds.
uint32 chaincount
Number of messages in the causal chain leading to (and including) this one.
Wire/storage layout of one log record: fixed header immediately followed by the message text.
Definition Utils.h:228
uint32 source
Definition Utils.h:232
uint32 size
Definition Utils.h:229
uint8 level
Definition Utils.h:234
uint64 time
Definition Utils.h:231
bool setText(char *text, uint32 len)
Copy len bytes of text into the payload area and update size.
Definition Utils.cpp:260
uint8 subject
Definition Utils.h:233
uint8 type
Definition Utils.h:235
uint32 cid
Definition Utils.h:230
Specification of a message to post when a trigger fires (or a crank completes).
uint8 policy
Delivery policy flags (e.g.
PsyType type
Type of the posted message.
uint32 addContentToMsg(DataMessage *msg)
Unpack the inline content entries into msg as typed user entries.
uint32 to
Addressee component id (0 = publish to subscribers).
uint32 tag
Tag for the posted message.
uint64 ttl
Time-to-live of the posted message in microseconds.
PsyContext contextchange
Context switch the posted message announces (NOCONTEXT if none).
Specification of a query against a catalog/service/feed, attached to a TriggerSpec.
char type[MAXKEYNAMELEN+1]
Requested data/content type.
char hostName[MAXKEYNAMELEN+1]
External source: host name (alternative to ipHost).
uint32 ipHost
External source: IPv4 host (as uint32), 0 if not used.
char operation[MAXKEYNAMELEN+1]
Operation to perform (source-specific verb).
char key[MAXKEYNAMELEN+1]
Key to query on.
char value[MAXVALUENAMELEN+1]
Value to match.
char name[MAXKEYNAMELEN+1]
Name of this query, used to reference its results in the crank.
char subdir[MAXKEYNAMELEN+1]
Sub-directory/collection within the source.
char sourceName[MAXKEYNAMELEN+1]
Name of the source component (alternative to numeric id).
bool binary
Request results in binary form rather than text.
uint16 ipPort
External source: TCP/UDP port, 0 if not used.
char ext[MAXKEYNAMELEN+1]
File extension / data format selector.
uint32 source
Component id of the source to query.
Specification of a whiteboard retrieval attached to a TriggerSpec.
uint64 endTime
Range end when keytype == INDEX_TIME (microseconds).
char endString[MAXVALUENAMELEN+1]
Range end when keytype == INDEX_STRING.
char startString[MAXVALUENAMELEN+1]
Range start when keytype == INDEX_STRING.
uint64 startTime
Range start when keytype == INDEX_TIME (microseconds).
uint32 origin
Restrict to messages originating from this component id (0 = any).
int64 endInt
Range end when keytype == INDEX_INTEGER.
int64 startInt
Range start when keytype == INDEX_INTEGER.
uint32 maxcount
Maximum number of messages to return (0 = unlimited).
uint32 source
Component id of the whiteboard to retrieve from.
float64 startFloat
Range start when keytype == INDEX_FLOAT.
float64 endFloat
Range end when keytype == INDEX_FLOAT.
uint64 maxage
Maximum message age in MICROSECONDS (XML gives ms; parser multiplies by 1000).
Specification of a signal (a typed notification without payload) emitted when a trigger fires.
PsyType type
Type of the signal to emit.
A complete trigger definition: what fires a component's crank and what happens then.