Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Sauermann J.Realtime operating systems.Concepts and implementation of microkernels for embedded systems.1997.pdf
Скачиваний:
27
Добавлен:
23.08.2013
Размер:
1.32 Mб
Скачать

102

5.4 Monitor Implementation

 

 

5.4Monitor Implementation

The different monitor commands and menus are contained in a class Monitor, see Section A.19 for details. The monitor is included in the system by creating a task for the monitor in setupApplicationStart() and setting the channels MonitorIn and MonitorOut to the desired serial channel, in our case SERIAL_1.

1 // ApplicationStart.cc

...

22void setupApplicationTasks()

23{

24MonitorIn = SERIAL_1;

25MonitorOut = SERIAL_1;

26ErrorOut = SERIAL_1;

27GeneralOut = SERIAL_1;

29Monitor::setupMonitorTask();

30}

With Monitor::setupMonitorTask(), the monitor task is created:

1 // Monitor.cc

...

13void Monitor::setupMonitorTask()

14{

15

MonitorTask = new Task

(

16

monitor_main,

// function

17

2048,

// user stack size

18

16,

// message queue size

19

240,

// priority

20

"Monitor Task");

21

}

 

Function setupMonitorTask() creates a task with main function monitor_main, a user stack of 2048 bytes, a message queue for 16 messages (which is actually not used), a task name of “Monitor Task”, and a priority of 240. The monitor should have a priority higher than that of all other tasks. This allows the monitor to display all tasks even if some task (of lower priority) is in busy wait (e.g by mistake) of some kind and to identify such tasks.

Function monitor_main(), which is the code executed by the monitor task, prints a message that the task has started and creates an instance of class Monitor using MonitorIn and MonitorOut as channels for the serial port and enters the main menu of the monitor.

1 // Monitor.cc

...

23void Monitor::monitor_main()

24{

25SerialOut::Print(GeneralOut,

26

"\nMonitor started on channel %d.",

27

MonitorOut);

5. An Application

103

 

 

28

29Monitor Mon(MonitorIn, MonitorOut);

30Mon.MonitorMainMenu();

31}

The constructor for class Monitor creates a SerialIn object si for its input channel. In contrast, the output channel is merely stored, but no SerialOut object is created. As a result, the input channel is reserved for the monitor forever, while the output channel can be used by other tasks as well. This explains why ErrorOut and GeneralOut could have been set to SERIAL_1 as well. The remaining data members of class Monitor are used to remember the state of submenus even if the monitor returns from the menus.

1 // Monitor.hh

...

11class Monitor

12{

13public:

14Monitor(Channel In, Channel Out)

15: si(In), channel(Out), currentChannel(0), last_addr(0) {};

...

48};

The code for the menus is straightforward and basically the same for all menus. For instance, the main menu prints a prompt, receives the next character (command), and calls the function corresponding to the command (if any).

1 // Monitor.cc

...

59//-----------------------------------------------------------------

60void Monitor::MonitorMainMenu()

61{

62SerialOut::Print(channel, "\nType H or ? for help.");

63SerialOut::Print(channel, "\nMain Menu [D I M T H]\n");

64

 

 

65

for (;;)

switch(getCommand("Main"))

66{

67case 'h': case 'H': case '?':

68

{

 

69

SerialOut so(channel);

 

70

so.Print("\nD - Duart Menu");

 

71

so.Print("\nI - Info Menu");

 

72

so.Print("\nM - Memory Menu");

73

so.Print("\nT - Task Menu");

 

74

}

 

75

continue;

 

76

 

 

77

case 'd': case 'D': DuartMenu();

continue;

78

case 'i': case 'I': InfoMenu();

continue;

79

case 'm': case 'M': MemoryMenu();

continue;

80

case 't': case 'T': TaskMenu();

continue;

81}

82}

104

5.4 Monitor Implementation

 

 

The same ??? structure/code ??? applies for all other menus. However, we should focus on an interesting situation in the duart menu: here, the user can toggle the duart channel to which the commands of the duart menu apply with the command C; i.e. toggle between channels SERIAL_0 and SERIAL_1. The actual channel chosen is displayed as the prompt of the duart menu. Now consider the T command, which reads a character to transmit (in hex), prints the character to be transmitted, and finally transmits the character on the duart channel selected. A naive implementation would be the following:

case 't': case 'T':

{

SerialOut so(channel); currentChar = si.Gethex(so);

so.Print("\nSending 0x%2X", currentChar & 0xFF);

Channel bc;

 

if (currentChannel)

bc = SERIAL_1;

else

bc = SERIAL_0;

SerialOut::Print(bc, "%c", currentChar);

}

continue;

Function getCurrentChannel() simply returns SERIAL_0 or SERIAL_1, depending on what has been selected with the C command. This works fine if SERIAL_0 is selected. But what happens otherwise, i.e. if getCurrentChannel() returns SERIAL_1? In this case, we have already created a SerialOut object so for channel (which is SERIAL_1), and we are about to perform a

SerialOut::Print(bc,...) with bc set to SERIAL_1 as well. This print will try to create another SerialOut object for SERIAL_1. As we are already using SERIAL_1, the task blocks itself forever, because it claims a resource it already owns. This is a nice example of a deadlock. The proper way of handling the situation is as follows:

226

case 't': case 'T':

 

227

{

 

228

SerialOut so(channel);

 

229

currentChar = si.Gethex(so);

230

 

 

231

so.Print("\nSending 0x%2X", currentChar & 0xFF);

232

}

 

233

{

 

234

Channel bc;

 

235

 

 

236

if (currentChannel)

bc = SERIAL_1;

237

else

bc = SERIAL_0;

238

 

 

239

SerialOut::Print(bc, "%c", currentChar);

240

}

 

241

continue;

 

5. An Application

105

 

 

The lifetime of the so object is simply limited to merely getting the parameter and printing the message about the character that is about to be transmitted. The so object is then destructed, making channel so available again. The SerialOut::Print(bc, ...) can then use channel bc (whether it happens to be SERIAL_1 or not) without deadlocking the monitor task.