Valgrind/Helgrind and STL string

I am trying to track down a thread-safety problem in one of my programs. Valgrind when run as “valgrind –tool=helgrind ./thread-test” claims that there is a problem with the following program (the Valgrind errors are at the end of the post). The SGI documents state [1]: “The SGI implementation of STL is thread-safe only in the sense that simultaneous accesses to distinct containers are safe, and simultaneous read accesses to to shared containers are safe. If multiple threads access a single container, and at least one thread may potentially write, then the user is responsible for ensuring mutual exclusion between the threads during the container accesses. “.

My interpretation of the SGI document is that different STL strings can be manipulated independently. When I have two threads running I have two stacks, so strings that are allocated on the stack will be “distinct containers“. So this looks like a bug in the STL or a bug in Valgrind. I am hesitant to file a bug report because I remember the advice that a wise programmer once gave me: “the people who develop compilers and tool chains are much better at coding than you, any time you think there’s a bug in their code there is probably a bug in yours“. I know that my blog is read by some really great programmers. I look forward to someone explaining what is wrong with my code or confirming that I have found a bug in Valgrind or the STL.

#define NUM_THREADS 2
#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>
#include <string>

using namespace std;

void whatever()
{
string str;
str.erase();
}

struct thread_data
{
int thread_id;
};

void *do_work(void *data)
{
struct thread_data *td = (struct thread_data *)data;
printf("%d:stack:%X\n", td->thread_id, &td);
while(1)
  whatever();
}

int main(int argc, char **argv)
{
pthread_t *thread_info = (pthread_t *)calloc(NUM_THREADS, sizeof(thread_info));
pthread_attr_t attr;
if(pthread_attr_init(&attr) || pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) || pthread_attr_setstacksize(&attr, 32*1024))
  fprintf(stderr, "Can't set thread attributes.\n");

int t;
struct thread_data td[NUM_THREADS];
for(t = 0; t < NUM_THREADS; t++)
{
  printf("created thread %d\n", t);
  td[t].thread_id = t;
  int p = pthread_create(&thread_info[t], &attr, do_work, (void *)&td[t]);
  if(p)
  {
  fprintf(stderr, "Can't create thread %d\n", t);
  exit(1);
  }
}
pthread_attr_destroy(&attr);
void *value_ptr;
for(t = 0; t < NUM_THREADS; t++)
  pthread_join(thread_info[t], &value_ptr);
free(thread_info);

return 0;
}

==30622== Possible data race during write of size 4 at 0x414FED0
==30622==    at 0x40FAD9A: std::string::_Rep::_M_set_sharable() (basic_string.h:201)
==30622==    by 0x40A945E: _ZNSs4_Rep26_M_set_length_and_sharableEj@@GLIBCXX_3.4.5 (basic_string.h:206)
==30622==    by 0x40FD6B6: std::string::_M_mutate(unsigned, unsigned, unsigned) (basic_string.tcc:471)
==30622==    by 0x40FDBEE: std::string::erase(unsigned, unsigned) (basic_string.h:1133)
==30622==    by 0x8048AA8: whatever() (thread-test.cpp:16)
==30622==    by 0x8048B0A: do_work(void*) (thread-test.cpp:29)
==30622==    by 0x402641B: mythread_wrapper (hg_intercepts.c:193)
==30622==    by 0x40464BF: start_thread (in /lib/i686/cmov/libpthread-2.7.so)
==30622==    by 0x42696DD: clone (in /lib/i686/cmov/libc-2.7.so)
==30622==  Old state: shared-readonly by threads #2, #3
==30622==  New state: shared-modified by threads #2, #3
==30622==  Reason:    this thread, #3, holds no consistent locks
==30622==  Location 0x414FED0 has never been protected by any lock
==30622==
==30622== Possible data race during write of size 4 at 0x414FEC8
==30622==    at 0x40A9465: _ZNSs4_Rep26_M_set_length_and_sharableEj@@GLIBCXX_3.4.5 (basic_string.h:207)
==30622==    by 0x40FD6B6: std::string::_M_mutate(unsigned, unsigned, unsigned) (basic_string.tcc:471)
==30622==    by 0x40FDBEE: std::string::erase(unsigned, unsigned) (basic_string.h:1133)
==30622==    by 0x8048AA8: whatever() (thread-test.cpp:16)
==30622==    by 0x8048B0A: do_work(void*) (thread-test.cpp:29)
==30622==    by 0x402641B: mythread_wrapper (hg_intercepts.c:193)
==30622==    by 0x40464BF: start_thread (in /lib/i686/cmov/libpthread-2.7.so)
==30622==    by 0x42696DD: clone (in /lib/i686/cmov/libc-2.7.so)
==30622==  Old state: shared-readonly by threads #2, #3
==30622==  New state: shared-modified by threads #2, #3
==30622==  Reason:    this thread, #3, holds no consistent locks
==30622==  Location 0x414FEC8 has never been protected by any lock
==30622==
==30622== Possible data race during write of size 1 at 0x414FED4
==30622==    at 0x40A9012: std::char_traits<char>::assign(char&, char const&) (char_traits.h:246)
==30622==    by 0x40A9488: _ZNSs4_Rep26_M_set_length_and_sharableEj@@GLIBCXX_3.4.5 (basic_string.h:208)
==30622==    by 0x40FD6B6: std::string::_M_mutate(unsigned, unsigned, unsigned) (basic_string.tcc:471)
==30622==    by 0x40FDBEE: std::string::erase(unsigned, unsigned) (basic_string.h:1133)
==30622==    by 0x8048AA8: whatever() (thread-test.cpp:16)
==30622==    by 0x8048B0A: do_work(void*) (thread-test.cpp:29)
==30622==    by 0x402641B: mythread_wrapper (hg_intercepts.c:193)
==30622==    by 0x40464BF: start_thread (in /lib/i686/cmov/libpthread-2.7.so)
==30622==    by 0x42696DD: clone (in /lib/i686/cmov/libc-2.7.so)
==30622==  Old state: owned exclusively by thread #2
==30622==  New state: shared-modified by threads #2, #3
==30622==  Reason:    this thread, #3, holds no locks at all

Finding Thread-unsafe Code

One problem that I have had on a number of occasions when developing Unix software is libraries that use non-reentrant code which are called from threaded programs. For example if a function such as strtok() is used which is implemented with a static variable to allow subsequent calls to operate on the same string then calling it from a threaded program may result in a SEGV (if for example thread A calls strtok() and then frees the memory before thread B makes a second call to strtok(). Another problem is that a multithreaded program may have multiple threads performing operations on data of different sensitivity levels, for example a threaded milter may operate on email destined for different users at the same time. In that case use of a library call which is not thread safe may result in data being sent to the wrong destination.

One potential solution is to use a non-threaded programming model (IE a state machine or using multiple processes). State machines don’t work with libraries based on a callback model (EG libmilter), can’t take advantage of the CPU power available in a system with multiple CPU cores, and require asynchronous implementations of DNS name resolution. Multiple processes will often give less performance and are badly received by users who don’t want to see hundreds of processes in ps output.

So the question is how to discover whether a library that is used by your program has code that is not reentrant. Obviously a library could implement it’s own functions that use static variables – I don’t have a solution to this. But a more common problem is a library that uses strtok() and other libc functions that aren’t reentrant – simply because they are more convenient. Trying to examine the program with nm and similar tools doesn’t seem viable as libraries tend to depend on other libraries so it’s not uncommon to have 20 shared objects being linked in at run-time. Also there is the potential problem of code that isn’t called, if library function foo() happens to call strtok() but I only call function bar() from that library then even though it resolves the symbol strtok at run-time it shouldn’t be a problem for me.

So the obvious step is to use a LD_PRELOAD hack to override all the undesirable functions with code that will assert() or otherwise notify the developer. Bruce Chapman of Sun did a good job of this in 2002 for Solaris [1]. His code is very feature complete but has a limited list of unsafe functions.

Instead of using his code I wrote a minimal implementation of the same concept which searches the section 3 man pages installed on the system for functions which have a _r variant. In addition to that list of functions I added some functions from Bruce’s list which did not have a _r variant. That way I got a list of 72 functions compared to the 40 that Bruce uses. Of course with my method the number of functions that are intercepted will depend on the configuration of the system used to build the code – but that is OK, if the man pages are complete then that will cover all functions that can be called from programs that you write.

Now there is one significant disadvantage to my code. That is the case where unsafe functions are called before child threads are created. Such code will be aborted even though in production it won’t cause any problems. One thing I am idly considering is writing code to parse the man pages for the various functions so it can use the correct parameters for proxying the library calls with dlsym(RTLD_NEXT, function_name). The other option would be to hand code each of the 72 functions (and use more hand coding for each new library function I wanted to add).

To run my code you simply compile the shared object and then run “LD_PRELOAD=./thread.so ./program_to_test” and the program will abort and generate a core dump if the undesirable functions are called.

Here’s the source to the main program:

#!/bin/bash
cat > thread.c << END
#undef NDEBUG
#include <assert.h>
END
OTHERS="getservbyname getservbyport getprotobyname getnetbyname getnetbyaddr getrpcbyname getrpcbynumber getrpcent ctermid tempnam gcvt getservent"
for n in $OTHERS $(ls -1 /usr/share/man/man3/*_r.*|sed -e "s/^.*\///" -e "s/_r\..*$//"|grep -v ^lgamma|sort -u) ; do
  cat >> thread.c << END
void $n()
{
  assert(0);
}
END
done

Here is the Makefile, probably the tabs will be munged by my blog but I’m sure you know where they go:

all: thread.so

thread.c: gen.sh Makefile
./gen.sh

thread.so: thread.c
gcc -shared -o thread.so -fPIC thread.c

clean:
rm thread.so thread.c

Update:
Simon Josefsson wrote an interesting article in response to this [2].

Google Server Design

Cnet has an article on the design of the Google servers [1]. It seems that their main servers are 2RU systems with a custom Gigabyte motherboard that takes only 12V DC input. The PSUs provide 12V DC and each system has a 12V battery backup to keep things running before a generator starts in the event of a power failure. They claim that they get better efficiency with small batteries local to the servers than with a single large battery array.

From inspecting the pictures it seems that the parts most likely to fail are attached by velcro. The battery is at one end, the PSU is at the other, and the hard disks are at one side. It appears that it might be possible to replace the PSU or the battery while the server is operational and in the rack.

The hard disks are separated from the motherboard by what appears to be a small sheet of aluminium which appears to give two paths for air to flow through the system. The thermal characteristics of the motherboard (CPUs) and the hard drives are quite different to having separate air flows seems likely to allow warmer air to be used in cooling the system (thus saving power).

Google boast that their energy efficiency now matches what the rest of the industry aims to do by 2011!

The servers are described as taking up 2RU, which gives a density of one CPU per RU. This surprised me as some companies such as Servers Direct [2] sell 1RU servers that have four CPUs (16 cores). Rackable systems [3] (which just bought the remains of SGI) sells 2RU half-depth systems (which can allow two systems in 2RU of rack space) that have four CPUs and 16 cores (again 4 CPUs per RU). Rackable systems also has a hardware offering designed for Cloud Computing servers, those CloudRack [4] systems have a number of 1RU trays. Each CloudRack tray can have as many as two server boards that has two CPUs (4 CPUs in 1RU) and 8 disks.

While I wouldn’t necessarily expect that Google would have the highest density of CPUs per rack, it did surprise me to see that they have 1/4 the CPU density of some commercial offerings and 1/8 the disk density! I wonder if this was a deliberate decision to use more server room space to allow slower movement of cooling air and thus save energy.

It’s interesting to note that Google have been awarded patents on some of their technology related to the batteries. Are there no journalists reading the new patents? Surely anyone who saw such patents awarded to Google could have published most of this news before Cnet got it.

Now, I wonder how long it will take for IBM, HP, and Dell to start copying some of these design features. Not that I expect them to start selling their systems by the shipping crate.

Choosing a Server for CPU Intensive work

A client is considering some options for serious deployment of some CPU intensive work. The options that are being considered include cloud computing (Amazon EC2 [1]), virtual machines (Slicehost [2] and Linode [3]), and purchasing servers to install in racks at various locations. I can’t disclose the criteria that will determine when each of those three options will be used (I expect that we will end up using all of them). But my research on the prices of various servers will hopefully be useful to someone.

For the server vendor I chose Dell. I believe that HP offers slightly better quality hardware than Dell, but they cost more and are more difficult to deal with (I can’t even get a price online). For this project I will be using a bunch of redundant servers (in a similar concept to the Google server array) so I’m not going to be overly bothered about losing a server occasionally – therefore the slight benefit that HP offers for reliability does not make up for the expense.

Dell has some 1RU servers that have two CPU sockets and allow eight CPU cores. It seems that the best value that Dell offers for a server without RAID (the entire server is redundant) is a PowerEdge SC1435 that has two Opteron 2352 quad-core CPUs running at 2.1GHz, 4G of RAM, a 1TB SATA disk, and a Broadcom PCIe Gig-e card for $3,816.50. That machine gives an option of 2.3GHz CPUs for an extra $621.50, I am not sure that increasing the clock speed by almost 10% for a 16% increase in system price is a good idea.

The second best option was a PowerEdge 1950 III that has two Xeon E5420 2.5GHz quad-core CPUs with 12M of cache, 4G of RAM and a 1TB SATA disk for $4,302.30. The Intel option has 3 years of support included while the AMD option included 1 year of support and needed at least an extra $990 for 3 years of support. So it seems that if 3 years of support is desired then the Intel based server becomes significantly cheaper and is probably a better option.

Dell’s 2RU and 4RU servers are of no interest if you want CPU performance. The 2RU servers only support two processors and the 4RU servers only support four processors. So it’s a ratio of 2 processors per RU for 1RU servers vs one processor per RU for 2RU and 4RU servers, and the 2RU and 4RU servers are a lot more expensive too.

I am investigating the Dell blade server. Blade servers are great for CPU density and good for management. The Dell blade enclosure M1000e takes 10RU of space and supports 16 half-height blades or 8 full-height blades. The Dell M905 blade supports four AMD quad-core processors for a total of 128 cores in 10RU, there are also half-height blades that support two quad-core processors for the same CPU density.

So in terms of CPU density it’s an average of 12.8 cores per RU for the blade server vs 8 cores per RU for 1RU servers. While I haven’t got a complete price yet, it seems that four CPUs suitable for the M905 will cost about as much as four 1RU servers. So the 1RU systems are definitely better value for money than the blade server. The difference is the management cost. N servers that have two CPUs will be more work than N/2 servers that have four CPUs, but on the other hand blade servers require some specialised skills to run them (which I don’t have) and that might also cause problems. I don’t think that blades will be part of this project.

Question about a “Secure Filesystem”

I have just been asked for advice about “secure filesystem” and decided to blog my answers.

The first issue is what is meant by “secure filesystem, that could either mean the ability to restrict file access (EG by supporting SE Linux security contexts and using SE Linux for file access control) or the ability to encrypt data in case the machine is stolen. For access control I recommend SE Linux of course. For encryption on a local machine I mostly use dm-crypt which is configured with the cryptsetup utility. I encrypt at the LVM logical volume level as it is common that there are some LVs that don’t need to be encrypted. For files that need extra encryption or files that are shared between machines I use GPG.

A question was asked about kernel vs user-space filesystem encryption. AES is in the kernel so there is no lack in terms of strong encryption there. Also performance is pretty good (in most cases the CPU is fast enough that the hard drive is the bottleneck). For fine grained encryption (such as some of the experimental filesystems that encrypt data separately for each user) user-space is probably the only way to go.

If you want servers to be “high-security level” and protected from “hackers or unauthorised people” then it’s difficult to offer any advice that is smaller than a text book. I suggest that if you have such questions then you should do one of two things. If you are running a corporate IT department then hire an expert who can help with determine your specific requirements and meet them. If you want to learn about computer security and run your own systems in the best way possible then read as much from the experts as possible.

If you are looking for a project to contribute to related to security then if you choose SE Linux I could offer some specific advice on things that need work. I suggest not deciding on whether to do “kernel level or user level” work up front, but decide first which area of security you want to work on and then select a project which fits – then you should be able to determine whether your skills are best suited to kernel or user space coding. As for whether developing a new filesystem is necessary, I will note that SE Linux works well on Ext3 and XFS, it has just become usable on JFFS2, and it will work on other newer filesystems in the near future. Adding SE Linux support to a filesystem is not a difficult task if the filesystem supports XATTRs. I believe that there is a lot of scope for other access control systems to be developed which use XATTRs for security labels.

I can’t advise on e-books. I generally don’t read books, I read blogs and papers. Anything that I read which I consider to be worth recommending will probably have a link from my blog.

Why Cyrus Sucks

I’m in the middle of migrating a mail server away from the Cyrus mail store [1]. Cyrus provides a POP and IMAP server, a local delivery agent (accepting mail via LMTP). It is widely believed that Cyrus will give better performance than other mail stores, but according to a review by linux-magazin.de Dovecot and Courier deliver comparable (and sometimes better) performance [2].

The biggest problem with Cyrus is that it is totally incompatible with the Unix way. This wouldn’t be a problem if it would just work and if it would display reasonable error messages when it failed, but it doesn’t. It often refuses to work as desired, gives no good explanation, and it’s data structures can’t be easily manipulated. Dovecot [3] and Courier [4] use the Maildir++ format [5] (as well as many other programs). I have set up a system with Courier Maildrop and Dovecot for the IMAP server [6] and it works well – it’s good to have a choice! But also Maildir++ is reasonably well documented and is an extension to the well known Maildir format. This means that it’s easy to manipulate things if necessary, I can use mv to rename folders and rm to remove them.

Cyrus starts with a database (Berkeley DB file) of all folders in all mailboxes. Therefore it is not possible to move a user from one back-end server to another by merely copying all the files across and changing the LDAP (or whatever else contains the primary authentication data) to point to the new one. It also makes it impossible to add or remove folders by using maildirmake or rm -rf. The defined way of creating, deleting, and modifying mailboxes is through IMAP. One of the problems with this is that copying a mailbox from one server to another requires writing a program to open IMAP connections to both servers at once (tar piped through netcat is much faster and easier). Also if you need to rename a mailbox that contains many gigabytes of mail then it will be a time consuming process (as opposed to a fraction of a second for mv).

Cyrus has a tendency to break while Dovecot is documented as being self-healing and Cyrus also seems to cope well in the fact of a corrupted mail store. Even manually repairing problems with Cyrus is a painful exercise. The Cyrus mail store is also badly designed – and it’s design was worse for older filesystems (which were common when it was first released) than it is for modern ones. The top level of a Cyrus maildir contains all the messages in the INBOX stored one per file, as well as three files containing Cyrus indexes and sub-directories for each of the sub-folders. So if I want to discover what sub-folders a mailbox has then I can run ls and wait for it to stat every file in the directory or I can use an IMAP client (which takes more configuration time). As opposed to a Maildir++ store where every file that contains a message is stored in a folder subdirectory named “new“, “cur“, or “tmp” which means that I can run ls on the main directory of the mail store and get a short (and quick) result. Using tools such as ls to investigate the operation of a server is standard practice for a sysadmin, it should work well!

A finall disadvantage of Cyrus seems to have many small and annoying bugs (such as the reconstruct program not correctly recursing the sub folders). I guess it’s because not many people use Cyrus that such things don’t get fixed.

One trivial advantage of Cyrus is that by default it splits users into different sub-directories for the first letter of the account name. Dovecot supports using a hash of the user-name this is better than splitting by first-letter for performance (it gives a more equal distribution) but will make it slightly more difficult to manipulate the mail store by script. Ext3 can give decent performance without a two level directory structure for as many as 31,998 sub-directories (the maximum that it will support) due to directory indexing and Linux caching of dentries. There may be some other advantages of Cyrus, but I can’t think of them at the moment.

Here is a script I wrote to convert Cyrus mail boxes to Maildir++. To make this usable for a different site would require substituting a different domain name for example.com (or writing extra code to handle multiple domains) and inserting commands to modify a database or directory with the new server name. There is no chance of directly using this script on another system, but it should give some ideas for people performing similar tasks.
Continue reading “Why Cyrus Sucks”

Maildrop, IMAP, and Postfixadmin

I have recently configured my mail server to use IMAP. I started doing this when I was attending Linux.conf.au so that I could read urgent mail using my EeePC while at the conference and then be able to deal with the more complex stuff using my laptop later on.

The next logical step is to have mail delivered to different folders in the IMAP account. While there are ways of doing this via the Subject and other header fields, my needs are not that great. All I need to do is to support user+extension@example.com going to a folder named extension in the user’s mail store. While changing my mail server I decided to install Postfixadmin at the same time.

My first attempt to use Maildrop was to put the following in the /etc/postfix/main.cf file:
mailbox_command = /usr/bin/maildrop -d mail -f “$SENDER” “$DOMAIN” “$USER” “$EXTENSION”

That seems to only work when you have local accounts, so I ended up setting fallback_transport = maildrop and then putting the following in /etc/postfix/master.cf:

maildrop unix – n n – – pipe flags=DRhu user=vmail argv=/usr/bin/maildrop -d vmail ${nexthop} ${user} ${extension}

Where vmail is a Unix account I created for storing mail. Then I added the following to /etc/postfix/main.cf. Some of these are probably redundant (such as the virtual_mailbox_base). The recipient limit is set to 1 because there are no command-line parameters for maildrop to support two recipients for the same message.
virtual_alias_maps = mysql:/etc/postfix/mysql_virtual_alias_maps.cf
virtual_mailbox_domains = mysql:/etc/postfix/mysql_virtual_domains_maps.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf
virtual_gid_maps = static:2000
virtual_uid_maps = static:2000
virtual_mailbox_base = /mail
vmaildir_destination_recipient_limit = 1
virtual_transport = maildrop
maildrop_destination_recipient_limit = 1

The files /etc/postfix/mysql* all have fields user=, password=, hosts=, and dbname=. The queries in each of the files are as follows:
mysql_virtual_alias_maps.cf:query = SELECT goto FROM alias WHERE address='%s' AND active = 1
mysql_virtual_domains_maps.cf:query = SELECT domain FROM domain WHERE domain='%s'
mysql_virtual_mailbox_maps.cf:query = SELECT maildir FROM mailbox WHERE username='%s' AND active = 1

The /etc/courier/maildroprc file has the following contents:

# log the maildrop actions
logfile "/var/log/maildrop.log"
#
# parameters 1, 2, and 3 are the domain, user, and extension
DOMAIN=tolower("$1")
USER=tolower("$2")
EXTENSION=tolower("$3")
DEFAULT="/mail/$DOMAIN/$USER"
#
# try making a backup (cc) copy of the mail but do not abort if it fails
exception {
  cc "$DEFAULT/.backup/"
}
#
# try delivering to the extension folder but do not abort if it fails
exception {
  if(length("$EXTENSION") != 0 && "$EXTENSION" ne "backup")
  {
    to "$DEFAULT/.$EXTENSION/"
  }
}
#
# deliver to the main inbox if there is no folder matching the extension or if no extension is specified
to "$DEFAULT/"

Installing Postfixadmin [1] was another challenge entirely. One of the complications of this is that there is no Debian package for Lenny (it seems that there will be one in Squeeze – Lenny+1).

I found David Goodwin’s tutorial on installing Postfixadmin and lots of other things on Debian/Etch [2] to be a very useful resource. I look forward to seeing a Lenny version of that document.

Please let me know if you can think of any way to improve this.

SE Linux Lenny Status Update

I previously described four levels of SE Linux support on the desktop [1].

Last night I updated my APT repository of SE Linux packages for Lenny (as described on my document about installing SE Linux [2]). I included a new policy package that supports logging in to a graphical session via gdm in either unconfined_t or user_t. This covers all the functionality I described as target 2 (some restricted users). I have tested this to a moderate degree.

Target 3 was having all users restricted and no unconfined_t domain (the policy module unconfined.pp not being linked into the running policy). I had previously done a large part of the work towards that goal in preparation for running a SE Linux Play Machine (with public root password) [3] on Lenny – but until last night I had not published it. The combination of the policy needed to run with no unconfined_t domain and the policy to allow logging in as user_t via gdm should mean that a desktop system with gdm for graphical login that has no unconfined_t domain will work – but I have not tested this. So target 3 is likely to have been achieved, if testing reveals any problems in this regard then I’ll release another policy update.

So now the only remaining target is MLS.

Also I have been setting up a mail server with a MySQL database for user account data and using Courier-Maildrop for delivery, so I’ve written policy for that and also made some other improvements to the policy regarding complex mail servers.

Netbook Thermal Issues

Recently there has been increasing attention paid to thermal issues. The power used by computers not only impacts the electricity bill (and battery life for a portable device) but is a cooling problem. The waste heat from desktop systems and servers costs energy (and therefore money) to remove by the air-conditioning system and the heat produced by small devices can impact where they may be used.

It seems that a temperature of 40C can cause burns if applied to the human body for any period of time. As it doesn’t immediately hurt this can happen without people noticing. A friend recently reported getting a large blister on his arm after drinking a moderate amount of alcohol and falling asleep next to his EeePC.

I have noticed that my EeePC 701 has an unpleasant pattern of heat dissipation. It appears to use only one small vent in the side to vent most of the heat (with some vents in the base for air intake) and the base is all plastic. Apparently such a machine draws 14W from the wall when in active use compared to my measurements of 20W for a Thinkpad T41p. The Thinkpad however has a significantly greater size, this means bigger vents (and therefore lower temperatures of the vented air). Also the fan inside the Thinkpad makes much less noise so I guess it’s larger.

If I am working in the lounge and leave my Thinkpad on the couch it doesn’t seem to have any thermal issues. But if I leave my EeePC sitting in a normal manner the vents on the base are partially blocked and it becomes unpleasantly hot. If I leave my EeePC upside-down with the lid closed (so that the vents in the base are exposed to the air) then the screen gets very hot, I am not sure whether this is heat from the CPU going through the keyboard to the screen and then being prevented from going further by the insulating cushion or whether heat is generated in the screen (although it is supposed to be powered down when the lid is closed).

One suggestion I have received is to place a laptop on a metal baking tray. The flat tray preserves the airflow underneath it and the metal conducts heat reasonably well. Baking trays seem to be made of aluminium or thin steel, they don’t conduct heat well – but a lot better than a cushion.

It seems to me that one factor which will limit the development of NetBook class machines is the ratio of heat dissipation to either area or volume (I’m not sure which is more important). For use similar to mine providing the same compute power as an EeePC 701 with less heat dissipation would be ideal – and technically should not be difficult to achieve. Unfortunately I think that people will want to run Windows on NetBook class machines so we will see the development of machines with faster CPUs and GPUs which have worse ratios of heat to heat dissipation potential which will lead to more heat induced shutdowns and low temperature burns.

It’s a pity that no-one makes a netbook with the CPU power of an iPaQ. A 400MHz ARM CPU is all I need for my portable computing and my iPaQs don’t have cooling vents.

SE-LAPP

On Tuesday afternoon I gave a talk on behalf of KaiGai Kohei about SE Linux and the LAPP (Linux Apache, PostgreSQL, PHP/Perl) stack. KaiGai has blogged about this [1], unfortunately Google Translation does a poor job of Japanese and has particular problems with KaiGai’s work (could anyone who knows Japanese and English well please submit some tips to Google). KaiGai’s post is useful for links to his notes which are good background reading.

My talks about SE-LAPP and SE-PostgreSQL have been getting some notice, Bob Edwards referenced SE-PostgreSQL in his talk about database security.

It’s good to see KaiGai’s great work getting the notice that it deserves. I hope that it becomes a standard feature of the PostgreSQL code base in the near future!

Also Casey Schaufler, James Morris, and I have bought KaiGai a present of some Tasmanian wine, in recognition of his great work.