blob: c733ce1648b4e7c449ca6a4ced36556aec3685a7 [file] [log] [blame]
Ernesto Posse8a4f2962015-05-12 13:28:46 -04001// umlrtcontroller.cc
2
3/*******************************************************************************
4* Copyright (c) 2014-2015 Zeligsoft (2009) Limited and others.
5* All rights reserved. This program and the accompanying materials
6* are made available under the terms of the Eclipse Public License v1.0
7* which accompanies this distribution, and is available at
8* http://www.eclipse.org/legal/epl-v10.html
9*******************************************************************************/
10
11// UMLRTController is the main controller-class.
12
13#include "basedebug.hh"
14#include "basefatal.hh"
15#include "umlrtapi.hh"
16#include "umlrtcontroller.hh"
17#include "umlrtcapsule.hh"
18#include "umlrtslot.hh"
19#include "umlrtcapsuletocontrollermap.hh"
20#include "umlrtcapsulerole.hh"
21#include "umlrtcapsulepart.hh"
22#include "umlrtcommsport.hh"
23#include "umlrtcommsportfarend.hh"
24#include "umlrtcommsportrole.hh"
25#include "umlrtcontrollercommand.hh"
26#include "umlrtframeservice.hh"
27#include "umlrtmessage.hh"
28#include "umlrtobjectclass.hh"
29#include "umlrtprotocol.hh"
30#include "umlrttimer.hh"
31#include "umlrttimespec.hh"
32#include "umlrtqueue.hh"
33#include <stdlib.h>
34#include <stdio.h>
35#include <sys/select.h>
36#include <string.h>
37#include <stdarg.h>
38
39// The application-wide free message pool.
40/*static*/ UMLRTMessagePool * UMLRTController::messagePool = NULL;
41
42// The application-wide free signal pool.
43/*static*/ UMLRTSignalElementPool * UMLRTController::signalElementPool = NULL;
44
45// The application-wide free timer pool.
46/*static*/ UMLRTTimerPool * UMLRTController::timerPool = NULL;
47
48// Error codes to string
49static const char * errorToString[] = UMLRTCONTROLLER_ERROR_CODE_TO_STRING;
50
51
52UMLRTController::UMLRTController(const char * name_, size_t numSlots_, const UMLRTSlot slots_[])
53 : UMLRTBasicThread(name_), name(name_), incomingQueue(name), capsuleQueue(name), numSlots(numSlots_), slots(slots_), lastError(E_OK)
54{
55 // Register the controller with the capsule-to-controller map.
56 UMLRTCapsuleToControllerMap::addController(name, this);
57}
58
59bool UMLRTController::cancelTimer( const UMLRTTimerId id )
60{
61 if (id.isValid())
62 {
63 const UMLRTTimer * timer = id.getTimer();
64
65 char buf[UMLRTTimespec::TIMESPEC_TOSTRING_SZ];
66 BDEBUG(BD_TIMER, "cancel timer(%p) destPort(%s) isInterval(%d) priority(%d) payloadSize(%d) due(%s)\n",
67 timer, timer->destPort->role()->name, timer->isInterval, timer->signal.getPriority(), timer->signal.getPayloadSize(),
68 timer->isInterval ? timer->due.toStringRelative(buf, sizeof(buf)) : timer->due.toString(buf, sizeof(buf)));
69 }
70 return timerQueue.cancel(id);
71}
72
73/*static*/ bool UMLRTController::deallocateMsgMatchCompare( UMLRTMessage * msg, UMLRTSlot * slot )
74{
75 return !msg->isCommand && msg->destSlot == slot;
76}
77
78/*static*/ void UMLRTController::deallocateMsgMatchNotify( UMLRTMessage * msg, UMLRTSlot * slot )
79{
80 BDEBUG(BD_DESTROY, "Purging message destined for slot %s\n", slot->name);
81
82 umlrt::MessagePutToPool(msg);
83}
84
85// Callback to purge timers for a condemned slot.
86/*static*/ bool UMLRTController::deallocateTimerMatchCompare( UMLRTTimer * timer, UMLRTSlot * slot )
87{
88 return timer->destSlot == slot;
89}
90
91// Callback when a timer is being deleted.
92/*static*/ void UMLRTController::deallocateTimerMatchNotify( UMLRTTimer * timer, UMLRTSlot * slot )
93{
94 BDEBUG(BD_DESTROY, "Purging timer destined for slot %s\n", slot->name);
95
96 umlrt::TimerPutToPool(timer);
97}
98
99void UMLRTController::deallocateSlotResources( UMLRTSlot * slot )
100{
101 if (slot == NULL)
102 {
103 FATAL("attempting to deallocate the NULL slot.");
104 }
105 BDEBUG(BD_DESTROY, "Remove messages and timers for slot %s\n", slot->name);
106
107 incomingQueue.remove( (UMLRTQueue::match_compare_t)deallocateMsgMatchCompare, (UMLRTQueue::match_notify_t)deallocateMsgMatchNotify, slot );
108 capsuleQueue.remove( (UMLRTQueue::match_compare_t)deallocateMsgMatchCompare, (UMLRTQueue::match_notify_t)deallocateMsgMatchNotify, slot );
109 timerQueue.remove( (UMLRTQueue::match_compare_t)deallocateTimerMatchCompare, (UMLRTQueue::match_notify_t)deallocateTimerMatchNotify, slot );
110}
111
112// Deliver a signal to the destination port.
113bool UMLRTController::deliver ( const UMLRTCommsPort * destPort, const UMLRTSignal &signal, size_t srcPortIndex )
114{
115 // Assumes global RTS lock acquired.
116
117 UMLRTMessage * msg = umlrt::MessageGetFromPool();
118 bool ok = false;
119
120 if (!msg)
121 {
122 signal.getSrcPort()->slot->controller->setError(E_SEND_NO_MSG_AVL);
123 }
124 else if (destPort == NULL)
125 {
126 FATAL("Message from slot %s (port %s) has destination port NULL.", signal.getSrcPort()->slot->name, signal.getSrcPort()->role()->name);
127 }
128 else
129 {
130 // Look up sapIndex0 so receiver knows which index in their replicated port the message was received on.
131 msg->sapIndex0 = signal.getSrcPort()->farEnds[srcPortIndex].farEndIndex;
132 msg->signal = signal;
133 msg->destPort = destPort;
134 msg->destSlot = destPort->slot;
135 msg->srcPortIndex = srcPortIndex;
136 msg->isCommand = false;
137
138 // Source port may not exist.
139 BDEBUG(BD_SIGNALALLOC, "%s: deliver signal-qid[%d] id(%d) -> %s(%s[%d]) payloadSize(%d)\n",
140 name,
141 msg->signal.getQid(),
142 msg->signal.getId(),
143 msg->destPort->slot->name, msg->destPort->role()->name, msg->sapIndex0,
144 msg->signal.getPayloadSize());
145
146 if (isMyThread())
147 {
148 // If this is me delivering the message, I can deliver directly to my capsule queues.
149 capsuleQueue.enqueue(msg);
150 }
151 else
152 {
153 // Otherwise, I deliver to the remote capsule's incoming queue.
154 incomingQueue.enqueue(msg);
155 }
156 ok = true;
157 }
158 return ok;
159}
160
161void UMLRTController::enqueueAbort()
162{
163 UMLRTControllerCommand command;
164
165 // Explicitly reset unused command contents.
166 command.capsule = NULL;
167 command.isTopSlot = false;
168 command.serializedData = NULL;
169 command.sizeSerializedData = 0;
170 command.slot = NULL;
171
172 // Format command and enqueue it.
173 command.command = UMLRTControllerCommand::ABORT;
174 enqueueCommand(command);
175}
176
177void UMLRTController::enqueueCommand( const UMLRTControllerCommand & command )
178{
179 UMLRTMessage *msg = umlrt::MessageGetFromPool();
180
181 msg->signal.initialize(sizeof(UMLRTControllerCommand), UMLRTSignalElement::PRIORITY_SYSTEM);
182 uint8_t * payload;
183
184 BDEBUG(BD_SIGNALALLOC, "%s: deliver signal-qid[%d] as command %d\n",
185 name,
186 msg->signal.getQid(),
187 command.command);
188
189 if ((payload = msg->signal.getPayload()) == NULL)
190 {
191 FATAL("initialized signal had no payload.");
192 }
193 memcpy( payload, &command, sizeof(command));
194 msg->isCommand = true;
195
196 if (isMyThread())
197 {
198 // If this is me delivering the message, I can deliver directly to my capsule queues.
199 capsuleQueue.enqueue(msg);
200 }
201 else
202 {
203 // Otherwise, I deliver to the remote capsule's incoming queue.
204 incomingQueue.enqueue(msg);
205 }
206}
207
208void UMLRTController::enqueueDebugOutputModel()
209{
210 UMLRTControllerCommand command;
211
212 // Explicitly reset unused command contents.
213 command.capsule = NULL;
214 command.isTopSlot = false;
215 command.serializedData = NULL;
216 command.sizeSerializedData = 0;
217 command.slot = NULL;
218
219 // Format command and enqueue it.
220 command.command = UMLRTControllerCommand::DEBUG_OUTPUT_MODEL;
221
222 enqueueCommand(command);
223}
224
225void UMLRTController::enqueueDeport( UMLRTSlot * slot )
226{
227 UMLRTControllerCommand command;
228
229 // Explicitly reset unused command contents.
230 command.capsule = NULL;
231 command.isTopSlot = false;
232 command.serializedData = NULL;
233 command.sizeSerializedData = 0;
234
235 // Format command and enqueue it.
236 command.command = UMLRTControllerCommand::DEPORT;
237 command.slot = slot;
238
239 enqueueCommand(command);
240}
241
242void UMLRTController::enqueueDestroy( UMLRTSlot * slot, bool isTopSlot )
243{
244 UMLRTControllerCommand command;
245
246 // Explicitly reset unused command contents.
247 command.capsule = NULL;
248 command.serializedData = NULL;
249 command.sizeSerializedData = 0;
250
251 // Format command and enqueue it.
252 command.command = UMLRTControllerCommand::DESTROY;
253 command.slot = slot;
254 command.isTopSlot = isTopSlot;
255
256 enqueueCommand(command);
257}
258
259void UMLRTController::enqueueImport( UMLRTSlot * slot, UMLRTCapsule * capsule )
260{
261 UMLRTControllerCommand command;
262
263 // Explicitly reset unused command contents.
264 command.isTopSlot = false;
265 command.serializedData = NULL;
266 command.sizeSerializedData = 0;
267
268 // Format command and enqueue it.
269 command.command = UMLRTControllerCommand::IMPORT;
270 command.slot = slot;
271 command.capsule = capsule;
272
273 enqueueCommand(command);
274}
275
276void UMLRTController::enqueueIncarnate( UMLRTCapsule * capsule, const void * userData, const UMLRTObject_class * type )
277{
278 UMLRTControllerCommand command;
279
280 // May be called from within the context of another controller thread.
281
282 // Explicitly reset unused command contents.
283 command.isTopSlot = false;
284 command.slot = NULL;
285
286 // Format command and enqueue it.
287 command.command = UMLRTControllerCommand::INCARNATE;
288 command.capsule = capsule;
289
290 serializeIncarnateData( userData, type, &command.sizeSerializedData, &command.serializedData);
291 // Controller frees serialized data buffer back to the heap.
292
293 command.sizeSerializedData = 0;
294 command.serializedData = NULL;
295
296 // Notification to destination controller occurs as a result of this enqueue.
297 enqueueCommand(command);
298}
299
300// Return true if abort was received.
301bool UMLRTController::executeCommand( UMLRTMessage * msg )
302{
303 bool abort = false;
304 UMLRTControllerCommand * command = (UMLRTControllerCommand *)msg->signal.getPayload();
305
306 if (command != NULL)
307 {
308 switch (command->command)
309 {
310 case UMLRTControllerCommand::ABORT:
311 BDEBUG(BD_COMMAND, "%s: ABORT command received\n", getName());
312 abort = true;
313 break;
314
315 case UMLRTControllerCommand::DEBUG_OUTPUT_MODEL:
316 BDEBUG(BD_COMMAND, "%s: DEBUG_OUTPUT_MODEL command received\n", getName());
317 debugOutputModel();
318 break;
319
320 case UMLRTControllerCommand::DEPORT:
321 BDEBUG(BD_COMMAND, "%s: DEPORT from slot %s command received\n", getName(), command->slot->name);
322 UMLRTFrameService::controllerDeport(command->slot, false/*synchronous*/, false/*lockAcquired*/);
323 break;
324
325 case UMLRTControllerCommand::DESTROY:
326 BDEBUG(BD_COMMAND, "%s: DESTROY from slot %s (is %stop slot) command received\n", getName(), command->slot->name, command->isTopSlot ? "" : "NOT ");
327 UMLRTFrameService::controllerDestroy(command->slot, command->isTopSlot, false/*synchronous*/, false/*lockAcquired*/);
328 break;
329
330 case UMLRTControllerCommand::IMPORT:
331 BDEBUG(BD_COMMAND, "%s: IMPORT capsule %s to slot %s command received\n", getName(), command->capsule->getName(), command->slot->name);
332 UMLRTFrameService::controllerImport(command->slot, command->capsule, false/*synchronous*/, false/*lockAcquired*/);
333 break;
334
335 case UMLRTControllerCommand::INCARNATE:
336 BDEBUG(BD_COMMAND, "%s: INCARNATE capsule %s (size data %d) command received\n", getName(), command->capsule->getName(), command->sizeSerializedData);
337 UMLRTFrameService::controllerIncarnate(command->capsule, command->sizeSerializedData, command->serializedData);
338 break;
339
340 case UMLRTControllerCommand::UNDEFINED:
341 default:
342 FATAL("%s:unknown controller (%d) command received", getName(), command->command);
343 }
344 }
345 return abort;
346}
347
348// Initialize the free pools.
349/*static*/ void UMLRTController::initializePools( UMLRTSignalElementPool * signalElementPool_, UMLRTMessagePool * messagePool_,
350 UMLRTTimerPool * timerPool_ )
351{
352 signalElementPool = signalElementPool_;
353 messagePool = messagePool_;
354 timerPool = timerPool_;
355}
356
357// Wait for the controller thread to die.
358void UMLRTController::join()
359{
360 UMLRTBasicThread::join();
361}
362
363// Get the system-wide signal pool.
364/*static*/ UMLRTSignalElementPool * UMLRTController::getSignalElementPool()
365{
366 return signalElementPool;
367}
368
369// Get the system-wide message pool.
370/*static*/ UMLRTMessagePool * UMLRTController::getMessagePool()
371{
372 return messagePool;
373}
374
375// Get the system-wide timer pool.
376/*static*/ UMLRTTimerPool * UMLRTController::getTimerPool()
377{
378 return timerPool;
379}
380
381bool UMLRTController::isMyThread()
382{
383 return UMLRTBasicThread::isMyThread();
384}
385
386// Output an error containing a user-defined message and the 'strerror()' string.
387void UMLRTController::perror( const char * fmt, ...) const
388{
389 va_list ap;
390 va_start(ap, fmt);
391 vprintf(fmt, ap);
392 printf(": %s\n", strerror());
393 va_end(ap);
394}
395
396// Deliver a signal to the destination port.
397void UMLRTController::recall( UMLRTMessage * msg, bool front )
398{
399 capsuleQueue.enqueue(msg, front);
400}
401
402// Main loop
403void * UMLRTController::run( void * args )
404{
405 printf("Controller \"%s\" running.\n", getName());
406
407 for (size_t i = 0; i < numSlots; ++i)
408 {
409 if (slots[i].controller == this)
410 {
411 if ((slots[i].capsule != NULL) && (!slots[i].condemned))
412 {
413 if ( (slots[i].role() == NULL)
414 || ((slots[i].role()->optional == 0) && (slots[i].role()->plugin == 0)))
415 {
416 BDEBUG(BD_INSTANTIATE, "%s: initialize capsule %s (class %s).\n", getName(), slots[i].name, slots[i].capsuleClass->name );
417
418 UMLRTFrameService::initializeCapsule(slots[i].capsule, 0, NULL);
419 }
420 }
421 }
422 }
423
424 bool abort = false;
425 while (!abort)
426 {
427 // Queue messages associated with all timed-out timers.
428 capsuleQueue.queueTimerMessages(&timerQueue);
429
430 // Transfer all incoming messages to capsule queues.
431 capsuleQueue.moveAll(incomingQueue);
432
433 // Inject all available messages, highest priority msgs first.
434 UMLRTMessage * msg;
435 while (!abort && (msg = capsuleQueue.dequeueHighestPriority()) != NULL)
436 {
437 if (msg->isCommand)
438 {
439 abort = executeCommand(msg);
440 }
441 else if (msg->destSlot->capsule == NULL)
442 {
443 FATAL("%s: signal id(%d) to slot %s (no capsule instance) should not occur\n",
444 getName(), msg->signal.getId(), msg->destSlot->name);
445 }
446 else
447 {
448 if (msg->destSlot->condemned)
449 {
450 // Drop messages to a condemned slot.
451 BDEBUG(BD_INJECT, "%s: dropping signal-qid[%d] id(%d) to slot %s (slot condemned)\n",
452 getName(), msg->signal.getQid(), msg->signal.getId(), msg->destSlot->name);
453 }
454 else
455 {
456 // Source port may no longer exist.
457 BDEBUG(BD_INJECT, "%s: inject signal-qid[%d] into %s {%s[%d]} id %d\n",
458 getName(), msg->signal.getQid(), msg->destSlot->capsule->getName(), msg->destPort->role()->name, msg->sapIndex0, msg->signal.getId());
459
460 base::debugLogData( BD_SIGNALDATA, msg->signal.getPayload(), msg->signal.getPayloadSize());
461
Barry Maherf9252612015-05-31 11:33:20 -0400462 // Set capsule message for this inject.
463 msg->destPort->slot->capsule->msg = msg;
464
Ernesto Posse8a4f2962015-05-12 13:28:46 -0400465 // Inject the signal into the capsule.
466 msg->destPort->slot->capsule->inject((UMLRTMessage)*msg);
467 }
468 }
469 // Put the message back in the pool (handles signal allocation also).
470 umlrt::MessagePutToPool(msg);
471 }
472 // Wait on the incoming queue or a timeout.
473 if (!abort)
474 {
475 wait();
476 }
477 }
478 // Leave this output in here for now.
479 printf("Controller %s is aborting.\n", getName());
480
481 // Bug 215 - must destroy owned capsules + slots here.
482
483 return(NULL);
484}
485
486/*static*/ void UMLRTController::serializeIncarnateData( const void * userData, const UMLRTObject_class * type, size_t * sizeSerializedDataP, void * * serializedDataP )
487{
488 (*sizeSerializedDataP) = 0;
489 (*serializedDataP) = NULL;
490
491 if (userData != NULL)
492 {
493 if (type == NULL)
494 {
495 FATAL("Type descriptor missing. Has been previously checked.");
496 }
497 // Define data pointer and size.
498 if (((*serializedDataP) = malloc((*sizeSerializedDataP) = type->getSize(type))) == NULL)
499 {
500 FATAL("could not allocate memory for serialized data.");
501 }
502 // Encode the data.
503 type->encode(type, userData, (*serializedDataP));
504 }
505 // The controller frees the serialized data buffer after it's been copied to the initialize message.
506}
507
508// Set the error code.
509void UMLRTController::setError( Error error )
510{
511 lastError = error;
512 if ((error != E_OK) && (base::debugGetEnabledTypes() & (1 << BD_ERROR)) != 0)
513 {
514 BDEBUG(BD_ERROR, "Controller %s setError(%d):'%s'\n", getName(), lastError, strerror());
515 }
516}
517
518// Start the controller thread.
519void UMLRTController::spawn()
520{
521 // No arguments for this thread.
522 start(NULL);
523}
524
525// See umlrtcontroller.hh.
526const char * UMLRTController::strerror( ) const
527{
528 Error error = getError();
529 if ((error < 0) || (error >= E_MAX))
530 {
531 SWERR("error code(%d) out of range max(%d)", error, E_MAX);
532 return "unknown error code";
533 }
534 else
535 {
536 return errorToString[error];
537 }
538}
539
540void UMLRTController::startTimer( const UMLRTTimer * timer )
541{
542 char buf[UMLRTTimespec::TIMESPEC_TOSTRING_SZ];
543 BDEBUG(BD_TIMER, "start timer(%p) destPort(%s) isInterval(%d) priority(%d) payloadSize(%d) due(%s)\n",
544 timer, timer->destPort->role()->name, timer->isInterval, timer->signal.getPriority(), timer->signal.getPayloadSize(),
545 timer->isInterval ? timer->due.toStringRelative(buf, sizeof(buf)) : timer->due.toString(buf, sizeof(buf)));
546
547 timerQueue.enqueue(timer);
548}
549
550// Wait on an external message or a timeout.
551void UMLRTController::wait()
552{
553 // Linux-specific implementation for the time-being.
554
555 // If there is a timer running, this holds the remaining time as the timeout of the select.
556 struct timeval remainTimeval;
557
558 // We default to 'wait forever', unless a timer is running.
559 struct timeval * selectTimeval = NULL;
560
561 bool wait = true; // Set this false if a timer is due or an incoming message appeared.
562
563 // Get the time remaining on the first timer in the queue (if one exists).
564 if (!timerQueue.isEmpty())
565 {
566 UMLRTTimespec remainTimespec = timerQueue.timeRemaining();
567
568 if (remainTimespec.isZeroOrNegative())
569 {
570 // The timer is due - don't wait.
571 wait = false;
572 BDEBUG(BD_TIMER, "%s:timer is due\n", name);
573 }
574 else
575 {
576 // A timer is waiting but is not yet due. Set up the timeout. Will be non-zero.
577 remainTimeval.tv_sec = remainTimespec.tv_sec;
578 remainTimeval.tv_usec = remainTimespec.tv_nsec / 1000;
579
580 char tmbuf[UMLRTTimespec::TIMESPEC_TOSTRING_SZ];
581 BDEBUG(BD_TIMER, "%s: timer is not due - remain(%s)\n", name, remainTimespec.toStringRelative(tmbuf, sizeof(tmbuf)));
582
583 // Select will not wait forever.
584 selectTimeval = &remainTimeval;
585 }
586 }
587 if (!incomingQueue.isEmpty())
588 {
589 BDEBUG(BD_CONTROLLER, "%s: incoming q non-empty\n", name);
590 wait = false;
591 }
592 if (wait)
593 {
594 // selectTimeval remains NULL if no timers are running. In that case, select will wait
595 // forever until a message is delivered or a new timer is added to the timer-queue.
596
597 // Get the queue notification file descriptors.
598 int msgNotifyFd = incomingQueue.getNotifyFd();
599 int timerFd = timerQueue.getNotifyFd();
600
601 fd_set fds;
602
603 FD_ZERO(&fds);
604 FD_SET(msgNotifyFd, &fds);
605 FD_SET(timerFd, &fds);
606
607 // select wants to know the highest-numbered fd + 1.
608 int nfds = msgNotifyFd + 1;
609 if (timerFd > msgNotifyFd)
610 {
611 nfds = timerFd + 1;
612 }
613
614 // TODO - Bug 238 - DEBUG - remove this later.
615 if (!selectTimeval)
616 {
617 // DEBUG - the intent is to wait forever until notification, since no timer is pending.
618 // However, we wake the process up every 10 seconds during debugging.
619 // No harm in doing that - the controller returns here if it finds nothing to do.
620 remainTimeval.tv_sec = 10;
621 remainTimeval.tv_usec = 0;
622 selectTimeval = &remainTimeval;
623 }
624 // end DEBUG - remove this later
625
626 BDEBUG(BD_CONTROLLER, "%s: call select msgfd(%d) timeout[%d,%d]\n",
627 name,
628 msgNotifyFd,
629 selectTimeval ? selectTimeval->tv_sec : -1,
630 selectTimeval ? selectTimeval->tv_usec : -1);
631
632
633 if ((select(nfds, &fds, NULL, NULL, selectTimeval)) < 0)
634 {
635 FATAL_ERRNO("select");
636 }
637 if (FD_ISSET(msgNotifyFd, &fds))
638 {
639 // Clear message notify-pending.
640 incomingQueue.clearNotifyFd();
641 }
642 if (FD_ISSET(timerFd, &fds))
643 {
644 // Clear message notify-pending.
645 timerQueue.clearNotifyFd();
646 }
647 }
648}
649
650/*static*/ void UMLRTController::debugOutputModelPortDeferQueueWalk( const UMLRTMessage * msg, void *userData )
651{
652 BDEBUG(BD_MODEL, " msg: id(%d) data [%d]\n",
653 msg->signal.getId(),
654 *(int *)msg->signal.getPayload());
655}
656
657void UMLRTController::debugOutputModelPortDeferQueue( const UMLRTCommsPort * port )
658{
659 if (port != NULL)
660 {
661 if (port->deferQueue != NULL)
662 {
663 if (!port->deferQueue->isEmpty())
664 {
665 BDEBUG(BD_MODEL,
666 " defer queue:\n");
667 port->deferQueue->walk( (UMLRTQueue::walk_callback_t)debugOutputModelPortDeferQueueWalk, NULL);
668 }
669 }
670 }
671}
672
673void UMLRTController::debugOutputModelPort( const UMLRTCommsPort * port, size_t index )
674{
675 if (!port)
676 {
677 BDEBUG(BD_MODEL,
678" port [%u]: (null)\n", index);
679 }
680 else
681 {
682 BDEBUG(BD_MODEL,
683" %s[%u] (id %d) %s%s %s%s%s%s%s%s%s%s%s%s%s%s%s\n",
684 port->role()->name,
685 port->role()->numFarEnd,
686 port->role()->id,
687 port->role()->protocol,
688 port->role()->conjugated ? "~" : "",
689 port->proxy ? "(proxy)" : "",
690 port->spp ? "(SPP " : "",
691 port->spp ? ((port->registeredName == NULL) ? "?" : port->registeredName) : "",
692 port->spp ? ")" : "",
693 port->sap ? "(SAP " : "",
694 port->sap ? ((port->registeredName == NULL) ? "?" : port->registeredName) : "",
695 port->sap ? ")" : "",
696 port->automatic ? "(auto)" : "",
697 port->notification ? "(notify)" : "",
698 (port->unbound) ? "('unbound')" : "",
699 port->relay ? "(relay)" : "",
700 port->wired ? "(wired)" : "",
701 port->locked ? "(locked)" : "");
702
703 for (size_t j = 0; j < port->numFarEnd; ++j)
704 {
705 const char * farEndSlotName = "(none)";
706 const char * farEndPortName = "(none)";
707 const char * farEndSlotNoInstance = "(no instance)";
708 size_t farEndIndex = 0;
709 if (port->farEnds[j].port != NULL)
710 {
711 farEndSlotName = port->farEnds[j].port->slot->name;
712 farEndPortName = port->farEnds[j].port->role()->name;
713 farEndIndex = port->farEnds[j].farEndIndex;
714 if (port->farEnds[j].port->slot->capsule != NULL)
715 {
716 farEndSlotNoInstance = "";
717 }
718 }
719 BDEBUG(BD_MODEL, " farEnd[%u] : -> { slot %s, port %s[%u] %s}\n",
720 j, farEndSlotName, farEndPortName, farEndIndex, farEndSlotNoInstance );
721 }
722 debugOutputModelPortDeferQueue(port);
723 }
724}
725
726void UMLRTController::debugOutputModelPortsArray( size_t numPorts, const UMLRTCommsPort * ports )
727{
728 if (numPorts == 0)
729 {
730 BDEBUG(BD_MODEL,
731" ports : (none)\n");
732 }
733 for (size_t i = 0; i < numPorts; ++i)
734 {
735 debugOutputModelPort(&ports[i], i);
736 }
737}
738
739void UMLRTController::debugOutputModelPortsList( size_t numPorts, const UMLRTCommsPort * * ports )
740{
741 if (numPorts == 0)
742 {
743 BDEBUG(BD_MODEL,
744" ports : (none)\n");
745 }
746 for (size_t i = 0; i < numPorts; ++i)
747 {
748 debugOutputModelPort(ports[i], i);
749 }
750}
751
752void UMLRTController::debugOutputClassInheritance( const UMLRTCapsuleClass * capsuleClass )
753{
754 const UMLRTCapsuleClass * parent = capsuleClass->super;
755
756 if (parent == NULL)
757 {
758 BDEBUG(BD_MODEL, "(none)");
759 }
760 while (parent != NULL)
761 {
762 BDEBUG(BD_MODEL, "-> %s ", parent->name);
763 parent = parent->super;
764 }
765 BDEBUG(BD_MODEL,"\n");
766}
767
768void UMLRTController::debugOutputSlots( const UMLRTSlot * slot )
769{
770 BDEBUG(BD_MODEL,
771" %s:\n", slot->name);
772 BDEBUG(BD_MODEL,
773" capsule instance : %-30s (%p)\n", slot->capsule ? slot->capsule->getName() : "(none)", slot->capsule);
774 if (slot->role() == NULL)
775 {
776 BDEBUG(BD_MODEL,
777" role : (none)\n");
778 }
779 else
780 {
781 BDEBUG(BD_MODEL,
782" role : %-30s [%d..%d] %s %s\n",
783 slot->role()->name,
784 slot->role()->multiplicityLower,
785 slot->role()->multiplicityUpper,
786 slot->role()->optional ? "optional " : "",
787 slot->role()->plugin ? "plugin " : "");
788
789 }
790 BDEBUG(BD_MODEL,
791" index : %d\n", slot->capsuleIndex);
792 BDEBUG(BD_MODEL,
793" class : %-30s (# sub-capsule roles : %u) (# border ports : %u) (# internal ports : %u)\n",
794 slot->capsuleClass->name,
795 slot->capsuleClass->numSubcapsuleRoles,
796 slot->capsuleClass->numPortRolesBorder,
797 slot->capsuleClass->numPortRolesInternal);
798 BDEBUG(BD_MODEL,
799" class inheritance : ");
800 debugOutputClassInheritance(slot->capsuleClass);
801 BDEBUG(BD_MODEL,
802" controller : %s\n", slot->controller->getName());
803 if (slot->slotToBorderMap == NULL)
804 {
805 BDEBUG(BD_MODEL,
806" slot to border map : (none)\n");
807 }
808 else
809 {
810 BDEBUG(BD_MODEL,
811" slot to border map :");
812 for (size_t i = 0; i < slot->role()->capsuleClass->numPortRolesBorder; ++i)
813 {
814 BDEBUG(BD_MODEL, " [sl %lu=cp %d]", i, slot->slotToBorderMap[i]);
815 }
816 BDEBUG(BD_MODEL,"\n");
817 }
818 if (slot->numPorts == 0)
819 {
820 BDEBUG(BD_MODEL,
821" slot ports : (none)\n");
822 }
823 else
824 {
825 BDEBUG(BD_MODEL,
826" slot ports :\n");
827 debugOutputModelPortsArray(slot->numPorts, slot->ports);
828 }
829 const UMLRTCommsPort * portlist;
830 const UMLRTCommsPort * * borderPorts;
831 if (slot->capsule == NULL)
832 {
833 BDEBUG(BD_MODEL,
834" capsule border ports : (none - no instance running in slot)\n");
835 }
836 else if ((borderPorts = slot->capsule->getBorderPorts()) == NULL)
837 {
838 BDEBUG(BD_MODEL,
839" capsule border ports : (no border ports)\n");
840 }
841 else if (slot->capsuleClass->numPortRolesBorder == 0)
842 {
843 BDEBUG(BD_MODEL,
844" capsule border ports : (class has no border ports)\n");
845 }
846 else
847 {
848 BDEBUG(BD_MODEL,
849" capsule border ports : \n");
850 debugOutputModelPortsList(slot->capsuleClass->numPortRolesBorder, borderPorts);
851 }
852 if (slot->capsule == NULL)
853 {
854 BDEBUG(BD_MODEL,
855" capsule internal ports : (none)\n");
856 }
857 else if ((portlist = slot->capsule->getInternalPorts()) == NULL)
858 {
859 BDEBUG(BD_MODEL,
860" capsule internal ports : (none)\n");
861 }
862 else
863 {
864 BDEBUG(BD_MODEL,
865" capsule internal ports :\n");
866 debugOutputModelPortsArray(slot->capsuleClass->numPortRolesInternal, portlist);
867 }
868 // recurse into parts.
869 if (slot->capsuleClass->numSubcapsuleRoles == 0)
870 {
871 BDEBUG(BD_MODEL,
872" # sub-capsule parts : (none)\n");
873 }
874 else
875 {
876 BDEBUG(BD_MODEL,
877" # sub-capsule parts : %d\n", slot->numParts);
878
879 for (size_t i = 0; i < slot->numParts; ++i)
880 {
881 BDEBUG(BD_MODEL,
882" role [%u]: %s [%d..%d] %s %s\n",
883 i,
884 slot->parts[i].role()->name,
885 slot->parts[i].role()->multiplicityLower,
886 slot->parts[i].role()->multiplicityUpper,
887 (slot->parts[i].role()->optional) ? "optional " : "",
888 (slot->parts[i].role()->plugin) ? "plugin " : "");
889 }
890 }
891 // Recurse into sub-structure outputing slot info.
892 for (size_t i = 0; i < slot->numParts; ++i)
893 {
894 for (size_t j = 0; j < slot->parts[i].numSlot; ++j)
895 {
896 debugOutputSlots(slot->parts[i].slots[j]);
897 }
898 }
899}
900
901void UMLRTController::debugOutputSlotContainment( const UMLRTSlot * slot, size_t nesting )
902{
903 for (size_t i = 0; i < nesting; ++i)
904 {
905 BDEBUG(BD_MODEL, " ");
906 }
907 BDEBUG(BD_MODEL, "{ %s, %s, %p, %s }\n",
908 slot->name,
909 (slot->capsule == NULL) ? "(none)" : slot->capsule->getName(),
910 slot->capsule,
911 slot->capsuleClass->name);
912 for (size_t i = 0; i < slot->numParts; ++i)
913 {
914 for (size_t j = 0; j < slot->parts[i].numSlot; ++j)
915 {
916 debugOutputSlotContainment(slot->parts[i].slots[j], nesting + 1);
917 }
918 }
919}
920
921void UMLRTController::debugOutputModel()
922{
923 // Acquire global RTS lock for this.
924 UMLRTFrameService::rtsLock();
925
926 char timebuf[UMLRTTimespec::TIMESPEC_TOSTRING_SZ];
927 UMLRTTimespec tm;
928
929 UMLRTTimespec::getClock(&tm);
930 BDEBUG(BD_MODEL, "Model structure at time %s:\n", tm.toString(timebuf, sizeof(timebuf)));
931
932 UMLRTCapsuleToControllerMap::debugOutputControllerList();
933
934 UMLRTCapsuleToControllerMap::debugOutputCapsuleList();
935
936 UMLRTProtocol::debugOutputServiceRegistration();
937
938 const UMLRTCapsule * top = UMLRTCapsuleToControllerMap::getCapsuleFromName("Top");
939
940 if (top == NULL)
941 {
942 BDEBUG(BD_MODEL, "ERROR: no 'Top' capsule found - no slot containment output.\n");
943 }
944 else
945 {
946 const UMLRTSlot * slot = top->getSlot();
947 BDEBUG(BD_MODEL, "Slot containment: { <slot>, <capsule name>, <capsule instance address>, <capsule class> } \n");
948 debugOutputSlotContainment( slot, 1 );
949 }
950 if (top == NULL)
951 {
952 BDEBUG(BD_MODEL, "ERROR: no 'Top' capsule found - no slot list output.\n");
953 }
954 else
955 {
956 const UMLRTSlot * slot = top->getSlot();
957 BDEBUG(BD_MODEL, "Slot list:\n");
958 debugOutputSlots( slot );
959 }
960 UMLRTFrameService::rtsUnlock();
961}