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
363 // add the trigger and msg
364 inputQueue.push(TriggerAndMessage(trigger, msg));
365 inputQueueSemaphore.signal();
366
367 apiMutex.leave();
368 return CRANKAPI_IDLE;
369}
370
372 const char* triggerName;
373 return waitForNewMessage(ms, triggerName);
374}
375
377 return currentTriggerName;
378}
379
381 if (this->currentTriggerSpec)
382 return this->currentTriggerSpec->context;
383 else
384 return NOCONTEXT;
385}
386
387
388DataMessage* PsyAPI::waitForNewMessage(uint32 ms, const char* &triggerName) {
389
390 DataMessage* msg = NULL;
391 uint32 s;
392 uint64 currentCPUTicks;
393
394// if (!apiMutex.enter(ms ? ms : 10, __FUNCTION__))sig
395 if (!apiMutex.enter(1000, __FUNCTION__))
396 return NULL;
397
398 if (!inputQueue.size()) {
399 apiMutex.leave();
400 // possible queue.size without mutex issue?
401 if (!inputQueueSemaphore.wait(ms) || !inputQueue.size()) {
402 utils::GetCPUTicks(currentCPUTicks);
403 space->manager->componentMemory->addComponentStats(currentCompID, COMPSTATUS_RUNNING,
404 currentCPUTicks - lastCPUTicks, // cpu usage
405 NULL, // input message if any
406 NULL, // no output message here
407 0, // run count 0, only incremented at start
408 1 // cycle count
409 );
410 lastCPUTicks = currentCPUTicks;
411 lastWallTime = GetTimeNow();
412 chainCPUTicks = 0;
413 chainWallTime = 0;
414 chainCount = 0;
415 return NULL;
416 }
417// if (!apiMutex.enter(ms, __FUNCTION__))
418 if (!apiMutex.enter(1000, __FUNCTION__))
419 return NULL;
420 }
421
422 delete(currentMsg);
423 //delete(currentTriggerMsg);
424
425 // COPY, not a reference: the old code bound `TriggerAndMessage& tm` to
426 // inputQueue.front() and then immediately pop()ed, which destroys the element
427 // the reference names - every later read of tm (the while condition, the
428 // tm.first/tm.second extraction below) was a dangling read into a freed queue
429 // slot. ASan reports it as container-overflow. It survived because
430 // std::queue/deque usually leaves the popped slot's bytes intact, so the
431 // pointers still looked valid; under memory pressure or a different allocator
432 // it hands back whatever now occupies the slot and the two DataMessage* are
433 // then freed. TriggerAndMessage is a pair of pointers, so copying costs
434 // nothing. Found by Isaac on macOS.
435 TriggerAndMessage tm = inputQueue.front();
436 inputQueue.pop();
437
438 while ((inputQueue.size() > 100) && (tm.second->getPolicy() & MESSAGE_NON_GUARANTEED)) {
439 delete(tm.first);
440 delete(tm.second);
441 tm = inputQueue.front();
442 inputQueue.pop();
443 }
444
445 DataMessage* msgFirst = tm.first;
446 DataMessage* msgSecond = tm.second;
447
448 // If this message is a trigger message (has tm.first) replace currentTriggerXXX
449 if (msgFirst) {
450 delete(currentTriggerMsg);
451 currentTriggerMsg = msgFirst;
452 currentTriggerSpec = (TriggerSpec*)currentTriggerMsg->getData("TriggerSpec", s);
453 utils::strcpyavail(currentTriggerName, currentTriggerSpec->name, MAXKEYNAMELEN, true);
454 triggerName = currentTriggerName;
455 }
456 else {
457 // this is a temporary query message, keep the previous currentTriggerXXX around
458 triggerName = NULL;
459 }
460
461 //currentTriggerMsg = msgFirst;
462 //if (currentTriggerMsg) {
463 // currentTriggerSpec = (TriggerSpec*) currentTriggerMsg->getData("TriggerSpec", s);
464 // utils::strcpyavail(currentTriggerName, currentTriggerSpec->name, MAXKEYNAMELEN, true);
465 // triggerName = currentTriggerName;
466 //}
467 //else {
468 // triggerName = NULL;
469 // currentTriggerSpec = NULL;
470 //}
471 msg = msgSecond;
472 if (autoDelete)
473 currentMsg = msg;
474
475// printf("************ API Trigger %llu us old, Msg %llu us old...\n", GetTimeAge(currentTriggerMsg->getCreatedTime()), GetTimeAge(msg->getCreatedTime()));
476
477 if (msgFirst && msgSecond) {
478 chainCPUTicks = msgSecond->data->chaincputime;
479 chainWallTime = msgSecond->data->chainwalltime;
480 chainCount = msgSecond->data->chaincount;
481 }
482 else {
483 chainCPUTicks = 0;
484 chainWallTime = 0;
485 chainCount = 0;
486 }
487
488 // calc stats
489 apiMutex.leave();
490
491 // Add stats to component
492 utils::GetCPUTicks(currentCPUTicks);
493 space->manager->componentMemory->addComponentStats(currentCompID, COMPSTATUS_RUNNING,
494 currentCPUTicks - lastCPUTicks, // cpu usage
495 msg, // input message if any
496 NULL, // no output message here
497 0, // run count 0, only incremented at start
498 1 // cycle count
499 );
500 lastCPUTicks = currentCPUTicks;
501 lastWallTime = GetTimeNow();
502
503 msgInputCount++;
504 return msg;
505}
506
507
508// T1.6: wait for a joined <triggergroup> set. Reuses waitForNewMessage() to dequeue
509// (which sets currentTriggerMsg + currentTriggerName), then reads the member map that
510// deliverTriggerGroup() attached under "Members". If the dequeued delivery is not a
511// group activation, returns an empty map (and the group name is empty).
512std::map<std::string, DataMessage*> PsyAPI::waitForNewMessageGroup(uint32 ms, std::string& groupName) {
513 // Free any member messages we own from the previous grouped activation.
514 std::map<std::string, DataMessage*>::iterator git, gitEnd;
515 for (git = currentGroupMap.begin(), gitEnd = currentGroupMap.end(); git != gitEnd; git++)
516 if (git->second) delete(git->second);
517 currentGroupMap.clear();
518 groupName.clear();
519
520 const char* triggerName = NULL;
521 DataMessage* primary = waitForNewMessage(ms, triggerName);
522 // currentTriggerMsg is the delivery wrapper; it persists across timeout polls, so
523 // only treat this as a group delivery when waitForNewMessage() actually dequeued a
524 // fresh trigger this call (triggerName is non-NULL only for a fresh trigger msg).
525 // Without this guard a completed group re-fires on every subsequent timeout poll.
526 if (triggerName && currentTriggerMsg && currentTriggerMsg->getType() == CTRL_TRIGGER_GROUP) {
527 currentGroupMap = currentTriggerMsg->getAttachedMessageMap("Members");
528 groupName = triggerName;
529 }
530 else if (triggerName && primary) {
531 // Not a group delivery: hand back the single message under its trigger name so a
532 // crank calling only waitForNewMessageGroup() still sees something sensible.
533 if (triggerName) groupName = triggerName;
534 // Note: 'primary' is owned by the API (currentMsg); we do NOT copy it into the
535 // owned map to avoid a double free. Callers mixing both APIs should prefer one.
536 }
537 return currentGroupMap;
538}
539
540bool PsyAPI::setAutoDelete(bool autodel) {
541 autoDelete = autodel;
542 return true;
543}
544
545// Get current message receive time
547 uint64 t;
548 if (currentTriggerMsg && (t = currentTriggerMsg->getRecvTime()) )
549 return t;
550 else if (currentMsg)
551 return currentMsg->getRecvTime();
552 else
553 return 0;
554}
555
557 if (msgType == NOTYPE)
558 return postOutputMessage(NULL, msg);
559 if (msg) {
560 msg->setType(msgType);
561 return postOutputMessage(NULL, msg);
562 }
563 DataMessage* newMsg = new DataMessage(msgType, 0);
564 bool result = postOutputMessage("A non-existing postname", newMsg);
565 delete(newMsg);
566 return result;
567}
568
569
570int32 PsyAPI::postOutputMessage(const char* postName, DataMessage* msg) {
571
572 uint64 currentCPUTicks;
573 utils::GetCPUTicks(currentCPUTicks);
574
575 if (!apiMutex.enter(1000))
576 return POST_FAILED;
577
578 if (msg)
579 msg->addTimeUsage((uint32)(currentCPUTicks - lastCPUTicks), (uint32)GetTimeAge(lastWallTime), chainCPUTicks, chainWallTime, chainCount + 1);
580
581 uint32 currentTag = 0;
582 if (currentMsg)
583 currentTag = currentMsg->getTag();
584
585 uint32 to;
586 int32 failed = 0;
587 int32 success = 0;
588 if (!currentTriggerSpec) {
589 if (!msg) {
590 apiMutex.leave();
591 logPrint(1, "Posting none - out of context");
592 return POST_OUTOFCONTEXT;
593 }
594 if (currentTag && !msg->getTag())
595 msg->setTag(currentTag);
596 if ( (to = msg->getTo()) || msg->getType().isValid()) {
597 if (space->postMessage(msg)) {
598 //logPrint(3,"Posted direct message to component %u", to);
599 success++;
600 }
601 else {
602 logPrint(0,"Failed to post direct message to component %u", to);
603 failed++;
604 }
605 }
606 else {
607 apiMutex.leave();
608 logPrint(1,"Posting none - out of context");
609 delete(msg);
610 return POST_OUTOFCONTEXT;
611 }
612 }
613 else {
614 PostSpec* postSpec;
615 std::list<PostSpec*>* postSpecs = currentTriggerSpec->getPostSpecs(postName);
616 if (!postSpecs || !postSpecs->size()) {
617 delete(postSpecs);
618 postSpecs = NULL;
619 if (msg)
620 postSpecs = currentTriggerSpec->getPostSpecs(msg->getType());
621 if (!postSpecs || !postSpecs->size()) {
622 delete(postSpecs);
623 apiMutex.leave();
624 logPrint(2, "Posting nothing - no post specs match for post name '%s'", postName);
625 //logPrint(0, "Posting nothing - no post specs match for post name '%s'\n%s",
626 // postName, currentTriggerSpec->toXML().c_str());
627 delete(msg);
628 return POST_NOSPEC;
629 }
630 }
631
632 uint64 msgTTL = 0;
633 if (!msg) {
634 msg = new DataMessage();
635 msg->addTimeUsage((uint32)(currentCPUTicks - lastCPUTicks), (uint32)GetTimeAge(lastWallTime), chainCPUTicks, chainWallTime, chainCount + 1);
636 }
637 else
638 msgTTL = msg->getTTL();
639
640 if (currentTag && !msg->getTag())
641 msg->setTag(currentTag);
642
643 // uint32 msgTTL = msg->getTTL();
644
645 std::list<PostSpec*>::iterator it = postSpecs->begin(), itEnd = postSpecs->end();
646 while (it != itEnd) {
647 if (postSpec = *it) {
648 if (postSpec->contextchange.isValid()) {
650 msg->setContextChange(postSpec->contextchange);
651 // msg->setData("Context", &postSpec->contextchange, sizeof(PsyContext));
652 }
653 else {
654 msg->setType(postSpec->type);
655 }
656 postSpec->addContentToMsg(msg);
657 //if (strlen(postSpec->contentKey) && !msg->getString(postSpec->contentKey))
658 // msg->setString(postSpec->contentKey, postSpec->content);
659 msg->setMultiple(currentCompID, postSpec->to, postSpec->tag, msgTTL ? msgTTL : postSpec->ttl, postSpec->policy, GetTimeNow());
660
661 if (space->postMessage(msg)) {
662 //logPrint(3,"Posted msg delivered to %u", postSpec->to);
663 success++;
664 }
665 else {
666 logPrint(0,"Failed to deliver posted msg to %u", postSpec->to);
667 failed++;
668 }
669 }
670 it++;
671 }
672 delete(postSpecs);
673 }
674
675 msgPostedCount++;
676 msgSentCount += success;
677
678 if (!success)
679 logPrint(0,"No msgs were delivered at postOutputMessage", success);
680 //else
681 // logPrint(3,"Posted msg was delivered to %u receivers", success);
682
683 // Add stats to component
684 space->manager->componentMemory->addComponentStats(currentCompID, COMPSTATUS_RUNNING,
685 currentCPUTicks - lastCPUTicks, // cpu usage
686 NULL, // no input message here
687 msg, // output message
688 0, // run count 0, only incremented at start
689 0 // cycle count 0, only incremented at waitForNewMessage
690 );
691 // utils::GetCPUUsage(cpuUserBefore, cpuKernelBefore);
692 lastCPUTicks = currentCPUTicks;
693
694 apiMutex.leave();
695 delete(msg);
696 if (!success && failed)
697 return POST_FAILED;
698 else
699 return success;
700}
701
702// ***************** Signals *****************
703bool PsyAPI::emitSignal(const char* name, DataMessage* msg) {
704
705 if (!apiMutex.enter(1000))
706 return false;
707
708 if (!currentTriggerSpec) {
709 apiMutex.leave();
710 delete(msg);
711 return false;
712 }
713
714 SignalSpec* signalSpec = currentTriggerSpec->getSignalSpec(name);
715 if (!signalSpec) {
716 apiMutex.leave();
717 delete(msg);
718 return false;
719 }
720
721 if (!msg)
722 msg = new DataMessage();
723 msg->setType(signalSpec->type);
724 if (space->emitSignal(signalSpec->type, msg)) {
725 apiMutex.leave();
726 return true;
727 }
728 else {
729 apiMutex.leave();
730 delete(msg);
731 return false;
732 }
733}
734
735DataMessage* PsyAPI::waitForSignal(const char* name, uint32 timeout, uint64 lastReceivedTime) {
736
737 apiMutex.enter(3000, __FUNCTION__);
738
739 if (!currentTriggerSpec) {
740 apiMutex.leave();
741 return NULL;
742 }
743
744 SignalSpec* signalSpec = currentTriggerSpec->getSignalSpec(name);
745 if (!signalSpec) {
746 apiMutex.leave();
747 return NULL;
748 }
749
750 apiMutex.leave();
751 DataMessage* msg = space->waitForSignal(signalSpec->type, timeout, lastReceivedTime);
752
753 if (msg) {
754 apiMutex.enter(3000, __FUNCTION__);
755 if (currentSignalMsg)
756 delete(currentSignalMsg);
757 currentSignalMsg = msg;
758 apiMutex.leave();
759 return msg;
760 }
761 else
762 return NULL;
763}
764
765
766
767uint8 PsyAPI::retrieve(std::list<DataMessage*> &result, const char* name, uint32 maxcount, uint32 maxage, uint32 timeout) {
768 if (!apiMutex.enter(1000))
769 return QUERY_FAILED;
770
771 if (!currentTriggerSpec) {
772 apiMutex.leave();
773 return QUERY_FAILED;
774 }
775
776 RetrieveSpec* retrieveSpec = currentTriggerSpec->getRetrieveSpec(name);
777 if (!retrieveSpec) {
778 apiMutex.leave();
779 return QUERY_NAME_UNKNOWN;
780 }
781
782 RetrieveSpec* specCopy = new RetrieveSpec;
783 memcpy(specCopy, retrieveSpec, sizeof(RetrieveSpec));
784
785 if (maxcount)
786 specCopy->maxcount = maxcount;
787 if (maxage)
788 specCopy->maxage = maxage;
789
790 apiMutex.leave();
791 uint8 res = retrieve(result, specCopy, timeout);
792 return res;
793}
794
795uint8 PsyAPI::retrieveTimeParam(std::list<DataMessage*> &result, const char* name, uint64 startTime, uint64 endTime, uint32 maxcount, uint32 maxage, uint32 timeout) {
796 std::list<DataMessage*> list;
797 if (!startTime)
798 return QUERY_FAILED;
799 if (!apiMutex.enter(1000))
800 return QUERY_FAILED;
801
802 if (!currentTriggerSpec) {
803 apiMutex.leave();
804 return QUERY_FAILED;
805 }
806
807 RetrieveSpec* retrieveSpec = currentTriggerSpec->getRetrieveSpec(name);
808 if (!retrieveSpec) {
809 apiMutex.leave();
810 return QUERY_NAME_UNKNOWN;
811 }
812
813 RetrieveSpec* specCopy = new RetrieveSpec;
814 memcpy(specCopy, retrieveSpec, sizeof(RetrieveSpec));
815
816 specCopy->startTime = startTime;
817 if (endTime)
818 specCopy->endTime = endTime;
819 if (maxcount)
820 specCopy->maxcount = maxcount;
821 if (maxage)
822 specCopy->maxage = maxage;
823
824 apiMutex.leave();
825 uint8 res = retrieve(result, specCopy, timeout);
826 return res;
827}
828
829uint8 PsyAPI::retrieveStringParam(std::list<DataMessage*> &result, const char* name, const char* startString, const char* endString, uint32 maxcount, uint32 maxage, uint32 timeout) {
830 std::list<DataMessage*> list;
831 if (!startString || !strlen(startString))
832 return QUERY_FAILED;
833
834 if (!apiMutex.enter(1000))
835 return QUERY_FAILED;
836
837 if (!currentTriggerSpec) {
838 apiMutex.leave();
839 return QUERY_FAILED;
840 }
841
842 RetrieveSpec* retrieveSpec = currentTriggerSpec->getRetrieveSpec(name);
843 if (!retrieveSpec) {
844 apiMutex.leave();
845 return QUERY_NAME_UNKNOWN;
846 }
847
848 RetrieveSpec* specCopy = new RetrieveSpec;
849 memcpy(specCopy, retrieveSpec, sizeof(RetrieveSpec));
850
851 utils::strcpyavail(specCopy->startString, startString, MAXVALUENAMELEN, true);
852 if (endString)
853 utils::strcpyavail(specCopy->endString, endString, MAXVALUENAMELEN, true);
854 if (maxcount)
855 specCopy->maxcount = maxcount;
856 if (maxage)
857 specCopy->maxage = maxage;
858
859 apiMutex.leave();
860 uint8 res = retrieve(result, specCopy, timeout);
861 return res;
862}
863
864uint8 PsyAPI::retrieveIntegerParam(std::list<DataMessage*> &result, const char* name, int64 startInteger, int64 endInteger, uint32 maxcount, uint32 maxage, uint32 timeout) {
865 std::list<DataMessage*> list;
866 if (startInteger == INT64_NOVALUE)
867 return QUERY_FAILED;
868
869 if (!apiMutex.enter(1000))
870 return QUERY_FAILED;
871
872 if (!currentTriggerSpec) {
873 apiMutex.leave();
874 return QUERY_FAILED;
875 }
876
877 RetrieveSpec* retrieveSpec = currentTriggerSpec->getRetrieveSpec(name);
878 if (!retrieveSpec) {
879 apiMutex.leave();
880 return QUERY_NAME_UNKNOWN;
881 }
882
883 RetrieveSpec* specCopy = new RetrieveSpec;
884 memcpy(specCopy, retrieveSpec, sizeof(RetrieveSpec));
885
886 specCopy->startInt = startInteger;
887 if (endInteger != INT64_NOVALUE)
888 specCopy->endInt = endInteger;
889 if (maxcount)
890 specCopy->maxcount = maxcount;
891 if (maxage)
892 specCopy->maxage = maxage;
893
894 apiMutex.leave();
895 uint8 res = retrieve(result, specCopy, timeout);
896 return res;
897}
898
899uint8 PsyAPI::retrieveFloatParam(std::list<DataMessage*> &result, const char* name, float64 startFloat, float64 endFloat, uint32 maxcount, uint32 maxage, uint32 timeout) {
900 std::list<DataMessage*> list;
901 if (startFloat == FLOAT64_NOVALUE)
902 return QUERY_FAILED;
903 if (!apiMutex.enter(1000))
904 return QUERY_FAILED;
905
906 if (!currentTriggerSpec) {
907 apiMutex.leave();
908 return QUERY_FAILED;
909 }
910
911 RetrieveSpec* retrieveSpec = currentTriggerSpec->getRetrieveSpec(name);
912 if (!retrieveSpec) {
913 apiMutex.leave();
914 return QUERY_NAME_UNKNOWN;
915 }
916
917 RetrieveSpec* specCopy = new RetrieveSpec;
918 memcpy(specCopy, retrieveSpec, sizeof(RetrieveSpec));
919
920 specCopy->startFloat = startFloat;
921 if (endFloat != FLOAT64_NOVALUE)
922 specCopy->endFloat = endFloat;
923 if (maxcount)
924 specCopy->maxcount = maxcount;
925 if (maxage)
926 specCopy->maxage = maxage;
927
928 apiMutex.leave();
929 uint8 res = retrieve(result, specCopy, timeout);
930 return res;
931}
932
933uint8 PsyAPI::retrieve(std::list<DataMessage*> &result, RetrieveSpec* spec, uint32 timeout) {
934 if (!spec)
935 return QUERY_FAILED;
936 spec->origin = currentCompID;
937
938 DataMessage* msg = new DataMessage(PsyAPI::CTRL_QUERY, this->currentCompID, spec->source, timeout);
939 msg->setData("RetrieveSpec", (char*)spec, sizeof(RetrieveSpec));
940
941 DataMessage* resultMsg = NULL;
942 uint8 status = space->query(msg, &resultMsg, timeout);
943 delete(msg);
944
945 if (!resultMsg) {
946 if (status == QUERY_FAILED)
947 logPrint(0,"Query failed and did not return a message...");
948 delete(spec);
949 return status;
950 }
951
952 uint32 size;
953 int64 count;
954 const char* data = resultMsg->getData("ReplyData", size);
955 if (!data || !resultMsg->getInt("ReplyCount", count)) {
956 if (!data)
957 logPrint(0,"Query did not return any ReplyData...");
958 else
959 logPrint(0,"Query did not return any ReplyCount...");
960 delete(resultMsg);
961 delete(spec);
962 return QUERY_FAILED;
963 }
964
965 DataMessage* subMsg;
966 const char* src = data;
967 for (uint32 n=0; n<(uint32)count; n++) {
968 if (GetObjID(src) != DATAMESSAGEID)
969 break;
970 subMsg = new DataMessage(src);
971 result.push_back(subMsg);
972 src += subMsg->getSize();
973 }
974
975 delete(spec);
976 delete(resultMsg);
977 return QUERY_SUCCESS;
978}
979
980bool PsyAPI::addSubscription(const char* xml) {
981 if (!apiMutex.enter(1000))
982 return false;
983 DataMessage* msg = new DataMessage(PsyAPI::CTRL_ADDSUBSCRIPTION, this->currentCompID, 0, 5000);
984 msg->setString("Subscription", xml);
985
986 DataMessage* resultMsg = NULL;
987 uint8 status = space->query(msg, &resultMsg, 5000);
988 delete(msg);
989
990 if (resultMsg)
991 delete(resultMsg);
992
993 apiMutex.leave();
994 return (status == QUERY_SUCCESS);
995}
996
997
998uint8 PsyAPI::queryCatalog(DataMessage** resultMsg, const char* name, DataMessage* msg, uint32 timeout) {
999 *resultMsg = NULL;
1000 if (!msg)
1001 return QUERY_FAILED;
1002 if (!apiMutex.enter(1000))
1003 return QUERY_FAILED;
1004
1005 if (!currentTriggerSpec) {
1006 logPrint(1, "Query '%s' cannot execute before a trigger message has been processed", name);
1007 apiMutex.leave();
1008 return QUERY_FAILED;
1009 }
1010
1011 QuerySpec* querySpec = currentTriggerSpec->getQuerySpec(name);
1012 if (!querySpec) {
1013 logPrint(1, "Query '%s' not found in PsySpec", name);
1014 apiMutex.leave();
1015 return QUERY_NAME_UNKNOWN;
1016 }
1017
1018 if (strlen(querySpec->operation))
1019 msg->setString("Operation", querySpec->operation);
1020 if (strlen(querySpec->type))
1021 msg->setString("Type", querySpec->type);
1022 if (strlen(querySpec->ext))
1023 msg->setString("Ext", querySpec->ext);
1024 if (strlen(querySpec->subdir))
1025 msg->setString("Subdir", querySpec->subdir);
1026 if (strlen(querySpec->key))
1027 msg->setString("Key", querySpec->key);
1028 if (strlen(querySpec->value))
1029 msg->setString("Value", querySpec->value);
1030 if (querySpec->binary)
1031 msg->setString("Binary", "yes");
1032
1033 if (strlen(querySpec->hostName)) {
1034 // This is a query for another system
1035 if (!querySpec->ipHost) {
1036 if (!utils::LookupIPAddress(querySpec->hostName, querySpec->ipHost)) {
1037 apiMutex.leave();
1039 }
1040 }
1041 if (!querySpec->ipPort)
1042 querySpec->ipPort = 10000;
1043 // now we have all the info we need
1045 msg->setFrom(currentCompID);
1046 msg->setTo(0);
1047 msg->setString("INTERSYSTEM_SOURCENAME", querySpec->sourceName);
1048 msg->setInt("INTERSYSTEM_ADDRESS", querySpec->ipHost);
1049 msg->setInt("INTERSYSTEM_PORT", querySpec->ipPort);
1050 }
1051 else {
1053 msg->setFrom(currentCompID);
1054 msg->setTo(querySpec->source);
1055 }
1056
1057 apiMutex.leave();
1058 uint8 status = space->query(msg, resultMsg, timeout);
1059 delete(msg);
1060
1061 return status;
1062}
1063
1064uint8 PsyAPI::queryRemoteCatalog(DataMessage** resultMsg, const char* componentName, const char* ipAddress, uint16 port, DataMessage* msg, uint32 timeout) {
1065 uint32 addr = 0;
1066 if (!utils::LookupIPAddress(ipAddress, addr))
1067 return QUERY_NOT_AVAILABLE;
1068 return queryRemoteCatalog(resultMsg, componentName, addr, port, msg, timeout);
1069}
1070
1071uint8 PsyAPI::queryRemoteCatalog(DataMessage** resultMsg, uint32& chosenAddress, const char* componentName, uint32* ipAddresses, uint32 numAddresses, uint16 port, DataMessage* msg, uint32 timeout) {
1072 if (chosenAddress > numAddresses)
1073 return QUERY_NOT_AVAILABLE;
1074
1075 uint8 result;
1076 if (chosenAddress) {
1077 // try this address first
1078 result = queryRemoteCatalog(resultMsg, componentName, ipAddresses[chosenAddress-1], port, msg, timeout);
1079 if (result != QUERY_NOT_REACHABLE)
1080 return result;
1081 // if it failed, go back and try all again
1082 }
1083
1084 chosenAddress = 0;
1085 for (uint32 n = 0; n < numAddresses; n++) {
1086 result = queryRemoteCatalog(resultMsg, componentName, ipAddresses[n], port, msg, timeout);
1087 if (result != QUERY_NOT_REACHABLE) {
1088 chosenAddress = n + 1;
1089 return result;
1090 }
1091 // else continue trying next address
1092 }
1093 // and give up if none of them connects
1094 return QUERY_NOT_REACHABLE;
1095}
1096
1097uint8 PsyAPI::queryRemoteCatalog(DataMessage** resultMsg, const char* componentName, uint32 ipAddress, uint16 port, DataMessage* msg, uint32 timeout) {
1098 *resultMsg = NULL;
1099 if (!msg)
1100 return QUERY_FAILED;
1101
1102 // This is a query for another system
1103 // we have all the info we need
1105 msg->setFrom(currentCompID);
1106 msg->setTo(0);
1107 msg->setString("INTERSYSTEM_SOURCENAME", componentName);
1108 msg->setInt("INTERSYSTEM_ADDRESS", ipAddress);
1109 msg->setInt("INTERSYSTEM_PORT", port);
1110
1111 uint8 status = space->query(msg, resultMsg, timeout);
1112 delete(msg);
1113
1114 return status;
1115}
1116
1117
1118
1119
1120uint8 PsyAPI::queryCatalog(char** result, uint32 &resultsize, const char* name, const char* query, const char* operation, const char* data, uint32 datasize, uint32 timeout) {
1121 *result = NULL;
1122 if (!apiMutex.enter(1000, "Replying to query"))
1123 return QUERY_FAILED;
1124
1125 if (!currentTriggerSpec) {
1126 apiMutex.leave();
1127 return QUERY_FAILED;
1128 }
1129
1130 QuerySpec* querySpec = currentTriggerSpec->getQuerySpec(name);
1131 if (!querySpec) {
1132 apiMutex.leave();
1133 return QUERY_NAME_UNKNOWN;
1134 }
1135
1136 DataMessage* msg = new DataMessage();
1137
1138 msg->setString("Name", querySpec->name);
1139
1140 if (query && strlen(query))
1141 msg->setString("Query", query);
1142 if (data && datasize)
1143 msg->setData("Data", data, datasize);
1144 if (operation && strlen(operation))
1145 msg->setString("Operation", operation);
1146 else if (strlen(querySpec->operation))
1147 msg->setString("Operation", querySpec->operation);
1148
1149 if (strlen(querySpec->type))
1150 msg->setString("Type", querySpec->type);
1151 if (strlen(querySpec->ext))
1152 msg->setString("Ext", querySpec->ext);
1153 if (strlen(querySpec->subdir))
1154 msg->setString("Subdir", querySpec->subdir);
1155 if (strlen(querySpec->key))
1156 msg->setString("Key", querySpec->key);
1157 if (strlen(querySpec->value))
1158 msg->setString("Value", querySpec->value);
1159 if (querySpec->binary)
1160 msg->setString("Binary", "yes");
1161
1162 if (strlen(querySpec->hostName)) {
1163 // This is a query for another system
1164 if (!querySpec->ipHost) {
1165 if (!utils::LookupIPAddress(querySpec->hostName, querySpec->ipHost)) {
1166 apiMutex.leave();
1168 }
1169 }
1170 if (!querySpec->ipPort)
1171 querySpec->ipPort = 10000;
1172 // now we have all the info we need
1174 msg->setFrom(currentCompID);
1175 msg->setTo(0);
1176 msg->setString("INTERSYSTEM_SOURCENAME", querySpec->sourceName);
1177 msg->setInt("INTERSYSTEM_ADDRESS", querySpec->ipHost);
1178 msg->setInt("INTERSYSTEM_PORT", querySpec->ipPort);
1179 }
1180 else {
1182 msg->setFrom(currentCompID);
1183 msg->setTo(querySpec->source);
1184 }
1185
1186 apiMutex.leave();
1187 DataMessage* resultMsg = NULL;
1188 uint8 status = space->query(msg, &resultMsg, timeout);
1189 delete(msg);
1190
1191 if (resultMsg) {
1192 *result = resultMsg->getDataCopy("ReplyData", resultsize);
1193 delete(resultMsg);
1194 }
1195
1196 return status;
1197}
1198
1199bool PsyAPI::queryReply(uint32 id, uint8 status, char* data, uint32 size, uint32 count) {
1200 DataMessage* msg = NULL;
1201 if (data && size) {
1202 msg = new DataMessage(PsyAPI::CTRL_QUERY_REPLY, currentCompID);
1203 msg->setData("ReplyData", data, size);
1204 msg->setInt("ReplyCount", count);
1205 // decide on EOL ###################
1206 }
1207 bool res = queryReply(id, status, msg);
1208 //delete(msg);
1209 return res;
1210}
1211
1212bool PsyAPI::queryReply(uint32 id, uint8 status, DataMessage* msg) {
1213 if (!apiMutex.enter(1000, "Replying to query"))
1214 return false;
1215 bool res = space->queryReply(id, status, msg);
1216 apiMutex.leave();
1217 return res;
1218}
1219
1220bool PsyAPI::logPrint(int level, const char *formatstring, ... ) {
1221 char* str;
1222 uint32 lenStr;
1223 va_list args;
1224 va_start(args, formatstring);
1225 str = utils::StringFormatVA(lenStr, formatstring, args);
1226 va_end(args);
1227 if (!str || !lenStr) {
1228 free(str);
1229 return false;
1230 }
1231
1232 char* name = new char[256];
1233 if (!space->manager->componentMemory->getComponentName(currentCompID, name, 255)) {
1234 delete [] name;
1235 free(str);
1236 return false;
1237 }
1238
1239 uint32 lenNewStr;
1240 char* newStr = utils::StringFormat(lenNewStr, "[%s] %s", name, str);
1241 // delete[] for `name` (new char[256] at the top of this function), free() for
1242 // `str` and `newStr` (StringFormat returns a vasprintf/malloc'd buffer,
1243 // Utils.cpp:7644). The two allocators sit two lines apart here, which is
1244 // exactly how this function ended up mismatched in the first place.
1245 delete [] name;
1246 free(str);
1247
1248 LogEntry* entry = (LogEntry*) malloc(sizeof(LogEntry)+lenNewStr+1);
1249 entry->size = sizeof(LogEntry)+lenNewStr+1;
1250 entry->cid = LOGENTRYID;
1251 entry->time = GetTimeNow();
1252 entry->source = currentCompID;
1253 entry->subject = LOG_COMPONENT;
1254 entry->level = (uint8)level;
1255 entry->type = LOGPRINT;
1256 entry->setText(newStr, lenNewStr);
1257 free(newStr);
1258
1259 return space->logEntry(entry);
1260// return LogPrint(this->currentCompID, LOG_COMPONENT, level, str);
1261}
1262
1263} // 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:540
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:380
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:864
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:767
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:980
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:570
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:703
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:1199
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:512
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:735
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:1120
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:546
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:829
DataMessage * waitForNewMessage(uint32 ms)
Wait for the next trigger message from the component's input queue.
Definition PsyAPI.cpp:371
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:1064
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:1220
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:376
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:899
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:795
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:7497
char * StringFormatVA(uint32 &size, const char *format, va_list args)
va_list core used by the other StringFormat overloads.
Definition Utils.cpp:8007
bool LookupIPAddress(const char *name, uint32 &address)
Resolve a hostname to an IPv4 address.
Definition Utils.cpp:6787
std::string StringFormat(const char *format,...)
printf into a std::string.
Definition Utils.cpp:8067
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.