4 * @brief Daemon for Xmem. Built on top of libxmem.
8 * @date Created on 11/03/2005
10 * @version 1.1 Emilio G. Cota 23/01/2009
12 * @version 1.0 Julian Lewis
21 #include <sys/ioctl.h>
22 #include <sys/types.h>
31 #include <XmemDaemon.h>
37 static XmemEventMask log_mask
= XmemEventMaskMASK
; /* Events to be logged */
38 static XdEventLogEntries
*event_log
= NULL
;
39 static XdEventLogEntries
*result
= NULL
;
41 int VmicDaemonWait(int timeout
);
42 void VmicDaemonCall();
46 * TimeToStr - Convert time to a standard string
48 * @param tod: time to convert
52 * Thu-18/Jan/2001 08:25:14
54 * day-dd/mon/yyyy hh:mm:ss
56 * @return pointer to a static string
58 char *TimeToStr(time_t tod
)
60 static char tbuf
[128];
63 char *yr
, *ti
, *md
, *mn
, *dy
;
65 bzero((void *)tbuf
, 128);
66 bzero((void *)tmp
, 128);
88 sprintf (tbuf
, "%s-%s/%s/%s %s", dy
, md
, mn
, yr
, ti
);
90 sprintf(tbuf
, "--- Zero ---");
97 * GetEventLogTable - Get the event log table in shared memory
101 * @return a pointer to the acquired shared memory segment
103 XdEventLogEntries
*GetEventLogTable()
111 smemky
= XmemGetKey(EVENT_LOG_NAME
);
112 smemid
= shmget(smemky
, sizeof(XdEventLogEntries
), 0666);
115 result
= (XdEventLogEntries
*)shmat(smemid
, (char *)0, 0);
117 if ((int)result
!= -1)
123 if (errno
== ENOENT
) {
124 /* a shared memory identifier does not exist; create it */
125 smemid
= shmget(smemky
, sizeof(XdEventLogEntries
),
131 result
= (XdEventLogEntries
*)shmat(smemid
, (char *)0, 0);
133 if ((int)result
== -1)
136 /* clear the acquired segment and return */
137 bzero((void *)result
, sizeof(XdEventLogEntries
));
142 XmemErrorCallback(XmemErrorSYSTEM
, errno
);
148 * CallbackToStr - Print out a callback structure
150 * @param cbs: Callback structure to be printed out
152 * @return pointer to the static string @str
154 char *CallbackToStr(XmemCallbackStruct
*cbs
)
156 static char str
[128];
161 bzero((void *)str
, 128);
165 case XmemEventMaskTIMEOUT
:
166 sprintf(str
, "Timeout");
169 case XmemEventMaskUSER
:
170 sprintf(str
, "User event:%d From node:%s",
171 (int)cbs
->Data
, XmemGetNodeName(cbs
->Node
));
174 case XmemEventMaskSEND_TABLE
:
175 sprintf(str
, "Send table:%s From node:%s",
176 XmemGetTableName(cbs
->Table
),
177 XmemGetNodeName(cbs
->Node
));
180 case XmemEventMaskTABLE_UPDATE
:
181 sprintf(str
, "Update table:%s From node:%s",
182 XmemGetTableName(cbs
->Table
),
183 XmemGetNodeName(cbs
->Node
));
186 case XmemEventMaskINITIALIZED
:
187 sprintf(str
, "Initialized:%d From node:%s",
188 (int)cbs
->Data
, XmemGetNodeName(cbs
->Node
));
191 case XmemEventMaskKILL
:
192 sprintf(str
, "Kill daemon received");
195 case XmemEventMaskIO
:
196 sprintf(str
, "IO error:%s", XmemErrorToString(cbs
->Data
));
199 case XmemEventMaskSYSTEM
:
200 sprintf(str
, "System error:%d", (int)cbs
->Data
);
203 case XmemEventMaskSOFTWARE
:
204 if (cbs
->Data
== XmemErrorSUCCESS
)
205 sprintf(str
, "Information:");
207 sprintf(str
, "Software error:%s",
208 XmemErrorToString(cbs
->Data
));
220 * LogEvent - Log an event in the log file
222 * @param cbs: callback struct with the information to log
223 * @param text: text to log
225 * This routine writes EVENT_LOG_ENTRIES events into a log file each time it
226 * has collected enough events.
228 * @return 1 on success; 0 otherwise
230 int LogEvent(XmemCallbackStruct
*cbs
, char *text
)
236 XdEventLogEntry
*evp
;
238 if (event_log
== NULL
)
241 idx
= event_log
->NextEntry
;
242 evp
= &event_log
->Entries
[idx
];
250 strncpy(evp
->Text
, text
, EVENT_MESSAGE_SIZE
- 1);
251 fprintf(stderr
, "%s XmemDaemon: %s\n", TimeToStr(tod
), text
);
255 if (cbs
&& log_mask
& cbs
->Mask
) {
257 // fprintf(stderr, "XmemDaemon: %s %s\n",
258 // TimeToStr(tod),CallbackToStr(cbs));
265 if (++idx
>= EVENT_LOG_ENTRIES
) {
266 /* event_log filled up; write to the file */
268 elog
= XmemGetFile(EVENT_LOG
);
269 fp
= fopen(elog
, "w");
272 perror("XmemDaemon");
274 "XmemDaemon: Error: Can't OPEN:%s for WRITE\n",
276 bzero((void *)event_log
, sizeof(XdEventLogEntries
));
280 evp
= &event_log
->Entries
[idx
];
281 cnt
= fwrite(event_log
, sizeof(XdEventLogEntries
), 1, fp
);
284 perror("XmemDaemon");
285 fprintf(stderr
, "XmemDaemon: Error: Can't WRITE:%s\n",
289 bzero((void *) event_log
, sizeof(XdEventLogEntries
));
294 bzero((void *) event_log
, sizeof(XdEventLogEntries
));
299 event_log
->NextEntry
= idx
;
305 * __flush_startup is only called by the callback handler when handling a
306 * pending initialisation; it alleviates an already bloated callback handler.
308 void __flush_startup(unsigned long *longs
, XmemNodeId
*nodes
,
309 unsigned long *user
, XmemNodeId me
, XmemNodeId init_node
)
311 #ifdef FLUSH_ON_STARTUP
318 atids
= XmemGetAllTableIds();
320 for (i
= 0; i
< XmemMAX_TABLES
; i
++) {
325 XmemGetTableDesc(msk
, longs
, nodes
, user
);
329 acnds
= XmemGetAllNodeIds() & *nodes
;
330 /* only the highest node ID issues the write */
331 if ((~me
& acnds
) > me
)
334 XmemSendTable(msk
, NULL
, 0, 0, 1);
336 sprintf(txt
, "Flushed table: %s For initialized node: %s",
337 XmemGetTableName(msk
),
338 XmemGetNodeName(init_node
));
346 * callback - callback handler
348 * @param cbs: callback struct delivered to the callback
351 void callback(XmemCallbackStruct
*cbs
)
354 unsigned long msk
, user
, longs
;
358 XmemNodeId nodes
, acnds
;
363 unsigned long *smemad
;
373 err
= XmemGetTableDesc(tid
, &longs
, &nodes
, &user
);
374 if (err
!= XmemErrorSUCCESS
)
384 for (i
= 0; i
< XmemEventMASKS
; i
++) {
386 if (! (cbs
->Mask
& msk
))
389 switch ((XmemEventMask
) msk
) {
391 case XmemEventMaskSEND_TABLE
:
393 if ((!tid
|| cbs
->Node
== me
) && !symp
)
398 if (user
& IN_SHMEM
) {
399 smemad
= XmemGetSharedMemory(tid
);
403 XmemSendTable(tid
, smemad
, longs
, 0, 1);
405 "Written table: %s For requesting node: %s",
406 XmemGetTableName(tid
),
407 XmemGetNodeName(cbs
->Node
));
411 XmemSendTable(tid
, NULL
, 0, 0, 1);
413 "Flushed table: %s For requesting node: %s",
414 XmemGetTableName(tid
),
415 XmemGetNodeName(cbs
->Node
));
420 case XmemEventMaskTABLE_UPDATE
:
421 if ((!tid
|| cbs
->Node
== me
) && !symp
)
423 if (! (user
& IN_SHMEM
))
426 smemad
= XmemGetSharedMemory(tid
);
428 /* read from reflective memory */
429 XmemRecvTable(tid
, smemad
, longs
, 0);
432 "Received table: %s From updating node: %s",
433 XmemGetTableName(tid
),
434 XmemGetNodeName(cbs
->Node
));
437 if (user
& ON_DISC
&& nodes
& me
) {
438 acnds
= XmemGetAllNodeIds() & nodes
;
439 /* only the highest node ID issues the write */
440 if ((~me
& acnds
) > me
)
443 XmemWriteTableFile(tid
);
445 "Disc file updated for table: %s For requesting node: %s",
446 XmemGetTableName(tid
),
447 XmemGetNodeName(cbs
->Node
));
452 case XmemEventMaskINITIALIZED
:
453 if (cbs
->Data
== XmemInitMessageRESET
) {
454 /* Acknowledge Init and send tables */
455 mess
.MessageType
= XmemMessageTypeINITIALIZE_ME
;
456 mess
.Data
= XmemInitMessageSEEN_BY
;
457 XmemSendMessage(XmemALL_NODES
, &mess
);
459 __flush_startup(&longs
, &nodes
, &user
,
462 if (cbs
->Data
!= XmemInitMessageSEEN_BY
)
466 case XmemEventMaskKILL
:
467 sprintf(txt
, "Received a Kill, EXIT: Deamon is DEAD");
472 case XmemEventMaskUSER
:
473 sprintf(txt
, "User message received");
477 case XmemEventMaskTIMEOUT
:
478 case XmemEventMaskIO
:
479 case XmemEventMaskSYSTEM
:
480 case XmemEventMaskSOFTWARE
:
491 * __init_coldstart() reads the tables for the node from memory.
493 void __init_coldstart()
496 unsigned long msk
, longs
, user
;
498 XmemNodeId me
, nodes
;
506 tid
= XmemGetAllTableIds();
508 for (i
= 0; i
< XmemMAX_TABLES
; i
++) {
513 XmemGetTableDesc(msk
, &longs
, &nodes
, &user
);
516 if (! (user
& IN_SHMEM
&& user
& ON_DISC
))
519 sprintf(txt
, "Reading table:%s id:%d from disc",
520 XmemGetTableName((XmemTableId
)msk
), (int)msk
);
523 err
= XmemReadTableFile(msk
);
524 if (err
== XmemErrorSUCCESS
)
527 LogEvent(NULL
, "WARNING: Failed to read table from disc");
535 * @param argc: argument counter
536 * @param char *argv[]: arguments' values
538 * The daemon initialises the segments (it can be a warm/cold start), then
539 * registers the callback handler, and waits in an infinite loop.
541 * @return if there's an error, main will exit with an appropriate error code.
543 int main(int argc
, char *argv
[])
550 event_log
= GetEventLogTable();
552 err
= XmemInitialize(XmemDeviceANY
);
553 if (err
!= XmemErrorSUCCESS
) {
554 LogEvent(NULL
, "Can't initialize library");
558 XmemUnBlockCallbacks();
561 LogEvent(NULL
, "Can't get: EVENT_LOG shared memory segment");
565 emsk
= XmemEventMaskMASK
;
566 /* subscribe the daemon to XmemEventMaskMASK */
567 err
= XmemRegisterCallback(callback
, emsk
);
568 if (err
!= XmemErrorSUCCESS
) {
569 LogEvent(NULL
, "Can't register callback");
573 warmst
= XmemCheckForWarmStart();
575 LogEvent(NULL
,"Warm Start: Begin ...");
576 /* Tell the world I exist */
577 mes
.MessageType
= XmemMessageTypeINITIALIZE_ME
;
578 mes
.Data
= XmemInitMessageSEEN_BY
;
579 XmemSendMessage(XmemALL_NODES
, &mes
);
580 /* ...it might be interesting to do this in a loop */
583 LogEvent(NULL
, "Cold Start: Initialize Tables: Begin ...");
584 /* For cold starts, read tables from disc */
586 /*Tell the world to send me their tables and that I exist */
587 mes
.MessageType
= XmemMessageTypeINITIALIZE_ME
;
588 mes
.Data
= XmemInitMessageRESET
;
589 XmemSendMessage(XmemALL_NODES
, &mes
);
593 * ...start-up finished.
595 LogEvent(NULL
, "XmemDaemon: Running OK");
598 * This is the infinite wait-loop of the daemon
601 if (VmicDaemonWait(1000)) {
602 XmemBlockCallbacks();
605 XmemUnBlockCallbacks();
609 LogEvent(NULL
, "Fatal Error: Daemon Teminated");