There are a variety of issues surrounding ACPI on XP workstations. XP is tied very tightly in to ACPI. The immediate result is, by default, Microsoft’s support for ACPI saves the world a lot of electricity. That is, the information economy kills a lot less wildlife and puts less toxins in the air that we then breathe. This is a significant accomplishment, considering the vast array of hardware manufacturers out there.
For more info on Microsoft’s ACPI support see OnNow and Power Management. Intel, certainly has much to do with this as well, but ACPI would be nothing if Microsoft did not support it (IMHO). For more info on Intel’s ACPI support, see Instantly Available Technology – ACPI.
One problem with ACPI is that the hardware needs to correctly support it. It is all well and good to put out a spec on how ACPI functions, but everybody will implement it slightly differently. There are a variety of tools to determine how well XP (and Windows 2000) supports the particular ACPI hardware you have. The coolest tools for XP that we ran across were in the Microsoft Windows XP Driver Development Kit.
You have to order the CD for the MS XP DDK online, but the only cost is for shipping/handling. (Sigh… Mozilla won’t work well with MS, so use your Windows box or Vmware to order the DDK). After you install the DDK, check out sleeper and pmte in the /winnddk/2600/tools/acpi directory. You can trigger different sleep modes and do comprehensive tests on your hardware’s ACPI support. Another useful tool is apmstat, which is available on the Windows 2000 Server CD as part of the support tools.
This is all good stuff, but there is one problem with automation. You have to be able to wake up your machine to run tasks. The settings tab in Control Panel/Scheduled Tasks has an option to wake up the computer to perform the task. What is really fun is that if you have a BIOS that supports it, XP will set a timer on the PC to wake up from full hibernation. If that doesn’t work, you can Always try a Wake On Lan utility or software to remotely trigger the PC to wake up.
Are you ready for something really suprising? From what we can tell, the task scheduler in XP is broken, at least for machines that are not plugged into a LAN. We suspect that this has something to do with ACPI, since the interrupts on the LAN adapter may be tickling something in the kernel that makes the task scheduler work. We even wrote a program that kept the PC awake, but still tasks would fail to run *sometimes* if the PC was unplugged from the LAN.
Simply plugging the PC back into the LAN would cause the task scheduler to work again. We assumed that ACPI was to blame, and hence we learned all about ACPI.
We are certain that this will be fixed with some service pack. We did see other people having similar problems. Do a search on Google Groups for “task scheduler xp” sometime for a good read. Most of the time, people are realizing that they need to enter a user account and password to get a scheduled task to run, but there are some references to the bugs we have seen, too. We have seen scheduled tasks run for days at a time, but then scheduler will fail. It is just plain broken.
OK. If you want to do any automation on your XP Pro desktop at night, you are SOL if you aren’t on a LAN. What do you do? Well, you could write your own task scheduler. That is the twist.
The easiest way we found to do this was to write a C program for this using Cygwin that kept the computer awake and ran tasks at the appropriate time (yes, yes, this is a strange way to deal with XP.
Since many of our readers, we guess, aren’t particularly used to writing C programs, we will present the scheduler program as a wee tutorial. There are a lot of C tutorials on the web. The first two books we recommend you purchase are Kernighan and Ritchie’s The C Programming Language, and C for Dummies Vol. 1/2. The author of this article (Agatha), taught herself C in 1983 using the Kernighan/Ritchie book, and has never had any formal C training, so there are probably much more elegant ways to do this.
The first program is always Hello World, right? Well, here is a hello world program:
#include <stdio.h> int main(){ printf("Hello World\n"); } |
The stdio.h is a library that provides, well, standard I/O, which includes printf. Now, this example happens to be on Linux, but all of these programs work just as well under Cygwin. To compile and run:
[u-1@srv-1 nat]$ gcc hello.c [u-1@srv-1 nat]$ ./a.out Hello World [u-1@srv-1 nat]$ |
So far so good. Now, if we want to write a task scheduler, we want to be able to sleep for awhile, then wake up, and perform a task. If we simply do a loop without sleeping, we will take up a lot of time. This is nasty. Luckily, there are C Libraries that can help with stuff like this. A library is just a collection of standard functions that your programs can call. One of the most widely used C Libraries is the GNU C Library. The particular function that we want to use is sleep. Here is the sleep source, and here is the sleep man page. Way too much nastiness in sleep.c for us to code. Aren’t you happy that there are Libraries to do this stuff? Another function that is useful is the localtime function. Here is the localtime man page. To use sleep and localtime together to list the time every second, here is another program. This program will run as long as 6 does not equal 9. Now, Jimi may not mind if a 6 turns out to be a 9, but if it ever does, this program will not work. The function asctime just converts the time to an ASCII value. Here is the output of the above program:
Wed Apr 24 05:39:24 2002 Wed Apr 24 05:39:25 2002 Wed Apr 24 05:39:26 2002 Wed Apr 24 05:39:27 2002 |
Every second this program does one iteration.
Finally, if we want to schedule something to happen we need to trim out the time part and compare it to the scheduled time. To do this we use the strtok funcion. This function extracts tokens from a string. Here is the man page for strtok. The strtok function is used iteratively by using a for look to grab the correct token. We use the string library for the strcmp and strcpy commands (compare and copy). Here is the completed task scheduler program:
#include <stdio.h> #include <unistd.h> #include <time.h> #include <string.h> int main(){ char *timetoken; char currtime[7]; char schedtime[7]; int i; struct tm *localtimeptr; strcpy(schedtime,"06:13:30"); while(6!=9){ time_t lt; sleep(1); lt =time(NULL); localtimeptr = localtime(<); timetoken = strtok(asctime(localtimeptr)," "); for(i=1;i<5;i++) { timetoken = strtok('\0', " "); if (i == 3){ strcpy(currtime,timetoken); } } printf("The current time is: %s\n",currtime); printf("We are waiting for: %s\n",schedtime); if(!strcmp(currtime,schedtime)){ printf("Time to do stuff\n"); system("ls /bin/mo*"); } } } |
Here is the output:
We are waiting for: 06:13:30 The current time is: 06:13:30 We are waiting for: 06:13:30 Time to do stuff /bin/more /bin/mount The current time is: 06:13:31 We are waiting for: 06:13:30 The current time is: 06:13:32 We are waiting for: 06:13:30 |
Again, you could just as easily do this with Cygwin. Just put /cygdrive/c/nameofbat.bat in instead of the ls command above.
If you schedule the above program to run at system startup in Task scheduler, it will run all the time, and it really will start the task in the system line at the right time.