Hi list, I am pondering a heartbeat functionality implementation. Currently, I have a patch that adds a few line to the timer interrupt to switch the led on and off when appropriate. On the list, there were opinions that switching the led on and off would be best done via userspace. While I in principle agree, I have some considerations: - The heartbeat frequency is calculated dynamically as a function of the current load. While this is available e.g. via /proc/loadavg, there is the effect that a daemon serving the led would need more cpu on high loads (led is blinking faster), even though it is less likely to be scheduled. This leads the heartbeat idea ad absurdum. - Can real time scheduling of the heartbeat daemon avoid the effect described above? - If so, is locking some pages of memory and a real time process still more adequate than a few lines in the timer interrupt? For a discussion base I've attached my current idea of an heartbeatd. (The DEBUG define might help those without an ibook to get something running ;-) Curous for any comments, Joerg /* * heartbeatd 2005-03-14 Joerg Dorchain * led code taken from ibook-led Nico Schottelius (nico-linux@schottelius.org) 2005-02-18 v0.3 * * might replace the kernel heartbeat code in arch/.../time.c * */ /* open() */ #include #include #include /* write */ #include /* fopen.. */ #include /* exit */ #include /* nanosleep..*/ #include /* sigaction */ #include /* HZ */ #include /* ioctl */ #include /* realtime scheduling */ #include /* mlockall */ #include /* Linux */ #define FSHIFT 11 #define ADB_DEVICE "/dev/adb" #define LOADAVG "/proc/loadavg" #define PIDFILE "/var/run/heartbeatd.pid" #undef DEBUG #ifdef DEBUG #undef LOADAVG #define LOADAVG "/tmp/loadavg" #endif int adbfd; inline void heartbeat_init(void) { #ifndef DEBUG /* open /dev/adb */ if((adbfd = open(ADB_DEVICE,O_RDWR)) == -1) exit(1); #endif } inline void heartbeat(int i) { char adb_on[5] = {0x06, 0xee, 0x04, 0x00, 0x01}; char adb_off[5] = {0x06, 0xee, 0x04, 0x00, 0x00}; #ifndef DEBUG if (i) write(adbfd, adb_on, 5); else write(adbfd, adb_off, 5); #else if (i) printf("pump\r"); else printf(" \r"); fflush(stdout); #endif } inline unsigned int period_calc(void) { FILE *lf; unsigned int ldint, ldfrac, load; if (( lf = fopen(LOADAVG, "r")) == NULL) exit(1); fscanf(lf, "%u.%u", &ldint, &ldfrac); fclose(lf); load = (ldint << FSHIFT) + (ldfrac << FSHIFT) / 100; return ((672<= 0) { ioctl(fd, TIOCNOTTY); close(fd); } /* make pidfile and remove once done */ if ((pidf = fopen(PIDFILE,"w+")) != NULL) { fprintf(pidf, "%d\n", getpid()); fclose(pidf); sa.sa_handler = cleanup; sigemptyset(&sa.sa_mask); sa.sa_flags= SA_ONESHOT; sigaction(SIGHUP, &sa, NULL); sigaction(SIGQUIT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); } /* get priority */ if (nice(-19) != 0) perror("nice"); if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0) perror("mlockall"); sp.sched_priority=10; if (sched_setscheduler(0, SCHED_RR, &sp) != 0) perror("sched_setscheduler"); #endif heartbeat_init(); while (1) { period = period_calc(); ts0.tv_sec = 0; ts0.tv_nsec = 7*(1000000000/HZ); ts1.tv_sec = 0; ts1.tv_nsec = (period/4)*(1000000000/HZ) - ts0.tv_nsec; ts2.tv_sec = 0; ts2.tv_nsec = (period/4+7)*(1000000000/HZ) - ts0.tv_nsec - ts1.tv_nsec; ts3.tv_sec = 0; ts3.tv_nsec = (period)*(1000000000/HZ) - ts0.tv_nsec - ts1.tv_nsec - ts2.tv_nsec; heartbeat(1); nanosleep(&ts0,NULL); heartbeat(0); nanosleep(&ts1,NULL); heartbeat(1); nanosleep(&ts2,NULL); heartbeat(0); nanosleep(&ts3,NULL); } }