Before Upstart came along, the state of the art of init daemon replacements were the dependency-based init daemons. The two most well-known at the time was the Service Management Facility (SMF) of Solaris, and initng on Linux.
The easiest way to understand how a dependency-based init daemon works is to look at another dependency-based system you’re probably more familiar with: the package manager of your Linux distribution.
When you want to install a package, for example the Apache Web Server, you tell the package manager to do that. The Apache package will list additional dependencies that it requires to be installed, and those in turn will list additional dependencies, and so on. The package manager will walk this dependency tree, eliminating those that you already have installed, and it will then flatten the remaining tree to get an order in which those remaining can be safely installed.
To put it simply: you say that you want Apache installed, but you may get more than that installed to ensure that Apache works.
A dependency-based init daemon works in fundamentally the same way. When you say that you want Apache started, it looks at the configuration for that service for the list of dependency services, and builds up a similar tree. Eliminating those already running, and flattening the tree, gives you a list of services that must be started in an order that they should be safe to start in.
You say you want Apache running, but you may get more than Apache running as a result.
Booting a system with a dependency-based init daemon, however, is a little strange. They need to know the target set of services that must be running, otherwise they would start nothing. SMF simply started all services that were not in manual start mode, initng had the concept of goal services whose dependencies were those that should be running — and used these to define the runlevels.
Once you have that list of goal services, you work out the dependency trees, and flatten them as normal – and thus you get an order that all services on the system should be started in.
Dependency-based init daemons work, but I believed there was a better way to do things. I invented the event-based init daemon instead.
An event-based init daemon isn’t really a great leap from a dependency-based init daemon, it simply does everything backwards. A simplistic view says that instead of starting Apache’s dependencies because Apache is started, it starts Apache because its dependencies are now running.
But it’s much more interesting than that, and much more flexible. Most people don’t get the epiphany.
A better description might be that services are started and stopped due to external influences on them. Those external influences can be anything, for example: hardware coming and going; changes in the time; and not least, other services.
The events represent changes in the system state, and services define the states in which they can be running, and the system reacts accordingly.
I’m still convinced this is the best way to work, not in the least because you can implement a dependency-based system with an event-based init daemon. Starting a service causes an event for each of its dependencies declaring a need for them, and the service waits for those events to complete; those events cause the dependencies to be started.
The other well-known init daemon out there is Apple’s launchd, of which Lennart’s recent systemd project is similar implementation in some ways but not in others.
launchd’s modus operandi is that it starts services on demand, and it does this on the assumption that all services communicate through sockets or through the Mach IPC model. For the socket-based services, launchd itself creates the listening sockets, and when it receives a connection it starts the service and hands off the listening socket to it.
This has a beautiful engineering elegance, and it’s easy to see why it appeals to us.
You don’t need to configure a service’s dependencies or requirements in the init daemon, instead the service causes its dependencies to be started through this on-demand activation. If the dependency isn’t ready to be started, the service simply blocks in the connect or open syscall until it is ready.
As launchd as matured, Apple have added support to watch for files on the disk and for cron-like schedule events. In many ways, this makes launchd kinda like an event-based init daemon, except with listening sockets.
systemd takes a similar approach with regard to the listening sockets, though my understanding so far is that it combines it with a dependency-based resolution procedure for other parts of the system, rather than an event-based one. I’m willing to be corrected on this though.
Upstart is an event-based init daemon; it’s taken a little while to develop because it’s the first pure example of its kind, and I only replaced the working sysvinit cautiously. I basically had to prove to myself, and others, that an event-based init daemon can really work. That’s why Ubuntu 9.10 and 10.04 were the first versions to really start taking advantage of it.
I also wanted to keep it relatively stable to encourage adoption by other distributions, and I believe this has also paid off given that Fedora, RedHat and OpenSuSE have all adopted it now.
I’ve proven it works, and it’s been adopted, now the fun development can begin!
Two of the main complains about Upstart are that the start on and stop on mechanism to define services is complicated and exposes far too much of the event model, and that it’s not very well documented. Ironically, these two complaints are entirely related.
The start on/stop on mechanism is basically just a debug interface, it allowed me during early development to access the raw event queue and find out what types of service model we really needed. Since it’s a debug interface, it wasn’t documented; I knew that future versions of Upstart would have a much better model.
So to correct a common misconception, the hideous start on lines are not a side-effect of event-based init daemons; they’re a side-effect of developing an event-based init daemon in a release early open-source way.
I’ve also mentioned that events can be just about anything, not just directly from other services. This includes on-demand activation; I don’t see any reason why Upstart should not be able to create sockets as launchd does, a connection on those sockets would simply be an event that would cause a service to be started.
Likewise, I fully intend Upstart to take over activation of system and session bus services from D-Bus, using an event from the D-Bus daemon to start and manage the service on its behalf.
This latter example neatly illustrates how start on will be replaced. Take a system bus service, you might declare such a service like this:
dbus system-bus org.freedesktop.UDisks
exec /usr/lib/udisks-daemon
That initial line replaces a whole slew of previous verbs. It tells Upstart that this service should be activated from the D-Bus system bus when a message for the given name has no destination in the bus. It also tells Upstart that this service should not be considered “ready” until it actually registers that name on the bus.
Finally it tells Upstart that the service can only be run while the D-Bus system bus service is running. You might think this superfluous, but remember from above that an event-based init daemon can work both ways; starting this service manually as a system administrator would start the message bus for you, if it wasn’t already running. This can be done with either an event or through the service connecting to the message bus via a known socket.
It’s this flexibility that still leaves me convinced that Upstart is a better all-round approach than the purity of launchd (or systemd).
Take another service, for example, the printing service: CUPS. At first glance, you might believe that it can be on-demand activated when something connects to its socket.
And that would certainly appear to work, you’d click Print in an application and the printer service would be started.
But that’s not the full picture; what if there was a job in the queue from before you shut down? You also need the service started if there are any files in the named queue directory.
And that’s still not the full picture; CUPS performs remote printer discovery, you most certainly don’t want to click Print and see no printers because CUPS hasn’t had time to discover them, having only just been started. Users have short attention spans to wait, I know I certainly do.
You need a combination of different conditions to start CUPS; it should be started on demand, it should be started if there are files in the print queue, and it should be still started on boot (just low-priority once the system is idle) to discover remote printers.
A pure on-demand daemon just doesn’t cut it, you need something more flexible.
The last point about user impatience is also my other major disagreement here. launchd supposes that you should always optimise for the minimum system footprint, at a cost to interaction performance.
It assumes that it’s ok to wait for a service to start when you click a button the first time, or bogusly that all services start immediately!
While this might be true in many situations, it’s also not true in many others. I’ve met very few system administrators who think that their web server should only ever be started on demand, and shut down again once there are no users browsing it.
And if you’re going to do always-running services like this, you do need to be able to encode their dependencies and requirements in the init-daemon configuration, which negates the engineering precision of avoiding doing so through on-demand activation.
]]>So I’d like to point out that Canonical are Hiring! and we have many open positions listed on our Employment page.
If you’d like to work on open source software, for a fun company with some of the smartest people you’ll ever work with, or you know someone who would, don’t hesitate to check it out.
]]>We are going to be doing the work to have btrfs as an installation option, and we have not ruled out making it the default.
I do stress the emphasis of that statement, a number of things would have to be true for us to take that decision:
It’s a tough gauntlet, and it would only made with the knowledge that production servers and desktops can be run on Lucid as a fully supported version of Ubuntu at the same time. I’d give it a 1-in-5 chance.
As you know, improvements to the boot process has been something that Ubuntu have been working on for a few years now and this led to the development of Upstart. We’re not the only ones working in this area, Intel have also been hard at work with different improvements of their own with the Moblin and MeeGo projects.
So it’s great to see some Fedora and OpenSuSE guys working on this too, and bringing some different ideas to the table!
I can’t say I disagree with some of Lennart’s observations about problems with Upstart, it’s certainly nowhere near perfect. Now that the stable period leading up to the release of Ubuntu 10.04 LTS is over, I’m looking forwards to getting back into the code and trying to address them.
It’s far too early to tell which approach is going to work out better in the end; but that’s one of the great things about Linux. The different distributions are able to develop in different directions, and we’re able to try out many different things.
On a personal note, I’m particularly pleased that Lennart has continued the punny naming scheme I began with Upstart. System D is a French concept that embraces responding to challenges when they happen, thinking fast and on your feet and adapting and improvising to get the job done.
]]>In fact, one of the most fundamental operations, setting the resolution and color depth we desire (aka. the Mode) can be different for each and every card, let alone each and every manufacturer.
Practically speaking, this means that there are only two things that know how to set the mode. The Video BIOS and the Graphics Driver. Historically, within Linux, the Graphics Driver has resided within the X Window System server.
There are lots of different places that we need to set the mode:
The two biggest problems here are switching from/to the X server VT, and resuming from suspend. In the former case, the biggest difficulty is actually switching between X servers on different VTs (e.g. user switching). The process ends up looking like this:
This leads to the black screen and flashing cursor between VT switches that everybody hates. In the resuming from suspend case, it’s really tricky; we don’t necessarily know the right video mode to restore, calling into the Video BIOS (even with VBE) is tricky, error-prone and doesn’t work if it wasn’t a VESA mode, and the X server’s mode setting code was never designed to be called externally. This means we used to basically rely on resuming into the X server and having that restore the mode for us.
All this changes with Kernel Mode Setting (KMS). Throughout the development of Lucid, you’ve probably seen that term mentioned a few times.
Simply put, Kernel Mode Setting is all about taking the bulk of the Graphics Driver code out of the X server and putting it into the Kernel. This means that the kernel has Graphics Drivers just like the kernel has Network Card Drivers, Wireless Drivers, USB Drivers, etc.
Most importantly, the kernel can set the mode whenever we need to and restore it on resume. The three most user-visible results of this are:
Behind the scenes there’s even more awesome waiting to be used in future releases.
Obviously most of the effort on writing these new drivers has gone to the “big three” graphics card vendors’ hardware. Intel themselves have contributed a large part of the KMS work, and their own drivers for it; nVidia owners are covered by the reverse-engineering effort that created the nouveau driver; and ATI owners are covered by the new radeon driver.
Those with graphics cards from other vendors are a little out in the cold here, but at least they’re no worse off than they were before. The biggest source of complaint comes from those with cards for which there is also a binary driver available (usually nVidia).
By switching from the in-kernel graphics driver (i.e. nouveau) to one supplied as a binary loaded into your X server (i.e. nvidia-glx), you will not have Kernel Mode Setting support and are effectively regressing your own system to Ubuntu 9.04 state.
I’m sure that nVidia users will be quick to point out that in Ubuntu 9.04, they had more than 16-colors for the splash screen, and that’s true.
One of the other changes made in 10.04 is the switch from using usplash to draw the splash screen to using Plymouth. Both had the ability to draw to frame buffers (basically kernel 2D graphics canvases), but Plymouth had much better support for multiple heads, native panel resolutions, and most importantly the smooth transition into X.
Supporting KMS properly for those using the open source drivers meant regressing slightly in prettyness for those who don’t.
usplash used to support higher colors and resolutions by using SVGAlib as a backend when a frame buffer was not available; writing a new Plymouth SVGAlib renderer was simply too much work on top of the existing integration worked that needed to happen for KMS. (If someone wanted to do it as a personal project though, go right ahead!)
An alternative to using SVGAlib would have been to at least set a better mode through VESA or VBE. There are two common ways to do this, firstly by using the VESA frame buffer (vesafb) or secondly by having the boot loader set the graphics mode and keep it set when running the kernel, triggering the use of the EFI frame buffer (efifb). The problem with both of these is resuming from suspend. As discussed in detail above, we don’t have the ability to restore this mode on resume.
So we picked the third alternative, which has the added attraction that it works on all hardware and doesn’t cause other issues. We use good, old, reliable 16-color VGA.
]]>A good approach to do this is to compare the directory with its parent directory, specifically the device ID as returned by the stat() system call.
The following code would work:
stat (path, &path_stat);
parent = dirname (path);
stat (parent, &parent_stat);
is_mountpoint = (path_stat.st_dev != parent_stat.st_dev);
If you want to know more information about the filesystem mounted there, you can use the statfs() system call. This returns, amongst other interesting details, the filesystem type.
if (statfs (path, &statfsbuf) == 0)
is_ext3 = statfsbuf.f_type == EXT3_SUPER_MAGIC;
I am gay.
That doesn’t really count as coming out though, if I am anything it’s openly gay. In fact a friend once joked that I manage to include a reference to my sexuality in every blog post or e-mail I write, and that every Twitter post of mine ends in “still gay”.
Maybe he’s right, but if it is, it’s probably subconsciously deliberate.
I confidently predict that there will be no surprise coming out statements this year from anybody in the public eye. Not even from those who don’t exactly do a good job of hiding it, yet deny it every time they are asked. You know who they are.
I think that’s quite sad.
I strongly believe that is the duty of those in the public eye to be open about their sexuality.
Firstly from a positive point of view, everybody needs role models. A young man or woman coming terms to their own sexuality will be able to do much easier knowing that there are public figures they respect who are comfortable with their own sexuality and open about it.
And from a negative point of view, every public figure who’s denying their sexuality is reinforcing the idea that you should not be comfortable with it and that being open about your sexuality will cause you problems.
Many celebrities, for example, claim that the reason they haven’t come out is because they’re afraid of what it will do to their careers. This is not only ironic, since they’re just perpetuating the problem, but clearly nonsense since there are a number of extremely well known and loved figures who are openly gay.
So this is why I’m open about it.
I want to make sure that any new members of our community who are coming to terms with their own sexuality can be assured that this is not going to cause them a problem.
(Still gay)
]]>Before I do, let me make one thing clear (as if it wasn’t already), I am a gay man.
Mark is a heterosexual man. In his LPC keynote he is accused of sexism because in his keynote he said that making Linux easier to understand would make it easier for him to explain what he does to girls.
Now, let’s pretend for a moment that I’d gave that keynote. Let’s pretend that I’d said that that making Linux easier would make it easier for me to explain what I did to boys.
Would there be this uproar?
Oh they’d be an uproar alright, but it wouldn’t be about sexism – the homophobic right of our community would be throwing their bibles out of their prams with vigour!
But nothing about sexism!
In fact the very people who are currently attacking Mark would be defending me as a gay man for right to say things like that. And if they didn’t I could cheerfully accuse them of homophobia.
And that’s why this bothers me.
If Mark was sexist, than he’s sexist for only being attracted to women and understandably caring what they think of him. That’s not sexism, that’s biology!
Sometimes a spade is just a spade.
Sometimes when a man says that he likes girls, HE LIKES GIRLS!
If your complaint is that he uses “girls” to mean “women” then you need to get (a) in touch with some mystical arbiter of the colloquial English language & (b) a grip.
I suspect this has ended my chances of ever being offered a Keynote (not that I ever have) and that Linux Today will now claim I should resign (I don’t work directly for mdz, but I have a tremendous amount of respect for him) then so be it.
And this is why the outcry bothers me.
]]>There’s been some press coverage of this already, and various comments from different people raising some questions about why Ubuntu is going down this route. Since this was largely my idea, I felt I should try and answer a few of the common ones.
rhgb was the “RedHat Graphical Boot” system they used in RedHat and Fedora until the most recent Fedora releases. It worked by starting an X Window System server and running the splash screen inside that.
This sounds very similar to xsplash, but with one key difference: the X server used by rhgb was shut down when boot finished, and a new X server started for the user to login with.
Instead, xsplash uses the same X server as the login window, and the same X server as your desktop. In fact, it’s started by the GNOME Display Manager while it starts the greeter or auto-logins your desktop alongside.
Plymouth is RedHat’s replacement for rhgb, instead of using an X server it relies on Kernel Mode Setting to provide a framebuffer in the panel’s native resolution and colour depth and draws directly to that. When the X server starts, the X server takes over the framebuffer without requiring a mode switch or a screen clear.
In many ways, Plymouth is simply a reimplementation of our original usplash. Indeed, I found it quite ironic that some people have accused us of “NIH”ing xsplash instead of adopting Plymouth, when technically Plymouth is an “NIH”d usplash.
So really the question as to why we don’t use Plymouth is the same as to why we don’t use usplash. We did actually consider replacing usplash with Plymouth since the implementation is rather cleaner, but Plymouth only supports Kernel Mode Setting drivers whereas usplash has a fall-back SVGA mode (it always had framebuffer support, thus KMS support, due to the Ubuntu PowerPC port).
(or Plymouth, see above)
One of our main goals for Ubuntu is boot performance. For Ubuntu 10.04 (that’s karmic+1) we’re targetting a 10s boot from the boot loader to a fully logged in desktop with idle disks. To boot this fast requires some prioritisation.
We need the X Window System server for just about everything. Until we’ve started the X server, we don’t have a display so can’t even start basic things like the underlying services and agents that run for a user’s login session.
Or, put another way, anything we do during boot that isn’t directly required to start the X server is delaying the boot.
The boot sequence must be setup in such a way that starting the X server is prioritised; once the X server is up, we can begin starting the user’s session (or the login screen session). We can also start all those other system services that weren’t dependencies of the X server.
This pretty much turns the current sequence on its head, where the X server is one of the last things started rather than one of the first.
If we started a splash screen such as usplash before the X server was up, we’d still have to wait for the Kernel Mode Setting driver to be loaded (or hardware to be sufficiently probed to know that we don’t have a Kernel Mode Setting driver for it). This is one of the primary dependencies of the X server too (the other is a mounted, writable filesystem), so in many cases we can start the X server at the same time!
Now, you could suggest that we do start the X server but also start the splash screen as well; and that the splash screen animates while the X server is running and the X server doesn’t paint to the screen until the desktop is logged in or the login screen is ready. Unfortunately this simply doesn’t appear to be possible, the X server “takes over” the framebuffer in such a way that the splash screen simply freezes at that point (we can prevent it clearing the screen). With an early X server start, it would spend more time frozen then it would animating.
This also wouldn’t work for the non-KMS case.
You could also argue that we could load the KMS drivers earlier, in the initramfs for example. While possible, this adds a significant time to the boot time for the extra loading and probing required. If we load the KMS driver in the initramfs, it takes about 8-10s to load the X server; if we load the KMS driver in the full system, it only takes about 6-8s to load the X server. Easy win.
But what if we have to check the filesystem, or enter a decryption passphrase to mount it? That’s why we still have usplash. In those cases we will start usplash to display the progress or request the key. The usplash theme will be themed such that when it finishes, and X starts up, it looks ok frozen for the short time until xsplash replaces it with an identical theme.
Patience, my friend. The 10s target is for Ubuntu 10.04 (karmic+1), not karmic (9.10).
That being said there are a number of updates planned for karmic that will boost the performance quite a bit, especially in terms of starting the X Window System server earlier. These have always been targetted to land between Feature Freeze and Beta, simply because it’s delicate work that needed a lot of testing first and that everyone else’s uploads prior to Feature Freeze kept throwing it off.
Look for a call for testing RSN.
]]>Its detractors will tell you how it takes much longer it takes to program anything in C. They’ll point at how much C code it takes to do something as simple as create a GObject sub-class compared to the equivalent in Python or C#. They’ll also probably complain that everything in C has to be compiled first, which takes even more time up.
No argument would be complete without them pointing out that C has no standard types for strings, let alone linked lists, binary trees, associative arrays, etc. and that you have to spend all that time implementing your own. They’ll probably make a point about how C’s static type system means that even if you have a array type, you need to know in advance what types you’re going to put into it and can’t just mix and match.
Don’t feel tempted at this point to counter with a discussion about how great and flexible pointers are. You’ll receive a lashing about how they’re even more evil than people who talk in the theatre. The rant about the C problems of uninitialised memory, out of bounds pointer errors and segmentation faults is a timeless classic. Especially when they get to the bit about how much time was lost debugging them.
And do you know what?
I simply do not agree with them.
I cannot think of a single project where the majority of time was wasted writing GObject header files compared to the single line of Python I needed. I can think of lots where I’ve sat for hours trying to figure out which class I needed to derive from, or reworking the code after I realised I derived from the wrong class to begin with. The high-level language doesn’t make this any easier.
As to the number of projects where I’ve needed to write a linked list or hash table implementation because C lacked a convenient dynamic array or associative array type like Python? If it takes you any time to write that kind of code, you’re doing it wrong. I’ve spent far more time realising that the structure is a performance bottleneck, and planning on the whiteboard a faster alternative. Neither language helps with this whiteboard time.
And all those pointer issues? This comes down to the tools that you’re using. If you’re writing in a language and not using its development environment properly, then it’s little surprise that you’re not being as efficient in it. gdb, valgrind, gprof and gcov are your friends. Use them well. I’ve spent just as much time dealing with other language-specific issues to make me believe that pointers aren’t any more evil as (for example) monkey patching.
The vast majority of my time on any new project is first of all spent thinking, and on a more mature project its figuring out what I did wrong and how I need to rework it.
Yes, the next biggest use of my time is working out what the best way is to express that. If I’m writing in C, that means I’m deciding whether it needs a linked list, or a hash table, or some other fancy structure. But if I’m writing in Python, believe me I spend just as much time normalising my class structure and coming up with all sorts of insane Pythonic ways of doing things.
If you’ve ever written in Perl and not lost a day or two to optimising your regular expressions, or eliminating code to arrive at the shortest possible expression, you’ve never written in Perl.
Refactoring takes you just as long in Python as it does in C. Just because when you do it to C code you end up setting segfaults doesn’t mean that when you do it to Python code, suddenly your class structures don’t match anymore.
Proponents of test-driven-development, AGILE, LEAN and ANEMIC programming methodologies will probably argue that it’s easier to practice their religion with a high-level language. I’m not buying that either, I’ve managed to write several large software projects in C that have a comprehensive test suite – including testing for allocation failures.
Ah, Rapid Application Development I hear you say? Well, the only people I’ve ever heard say how great RAD is are people who’ve never had to support the software that was written rapidly, or debug issues with it years later. RAD is great when v2 is going to be a complete rewrite, and v3 a complete rewrite again. Very few websites have upgrades without announcing a completely new codebase.
It’s certainly true that it’s faster to mash up some code in a high-level language. I use shell scripts and bits of Perl for this kind of thing all the time, and I frequently even do basic mock-ups or essays in Python. But ultimately it all tends to be throw-away code, that I don’t really ever intend to take seriously or attempt to support later on.
For larger projects, I just don’t see any difference in the time it takes to write.
I’d like to cite an example. The GIT and Bzr revision control systems are about the same age, one of them is written in C and one of them is written in Python. It hasn’t taken them any less time to write the one in Python than it’s taken the others to write the other in C. The one in Python doesn’t have extraordinary features that the one in C lacks.
C# fans would point out how much faster it is to UI code. Really? Then why isn’t Banshee that much dazzingly better than Rhythmbox? Sure they’re different, but there’s nothing there that suggests one language is better than the other.
And do you know what? I trust code written in C far more than I do any higher level language. No, that’s probably not fair. I trust C programmers far more than I do programmers of other languages. If you tell me I have the option of choosing a program or library written in C over one written in Python or C#, I’ll take the C one every time.
]]>