Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.

Channels ▼

Al Williams

Dr. Dobb's Bloggers

Time On Your Side

July 05, 2013

The gap between embedded systems and desktop systems is lessening. Sure, there are often bits of high-performance code in an embedded system (although, desktop systems are getting pretty performance oriented on audio and video processing). Many embedded systems are turning to Linux to handle networking, GUIs, and other tasks usually found on desktop systems. The popularity of low-cost Linux platforms like the Raspberry Pi and the Beagle Bone hasn't hurt either. There's even an increase in interest in AMP (Asymmetric Multiprocessing), where a multicore processor will run Linux on some cores and some traditional RTOS on the others.

To paraphrase an old Army saying, when you want to get something done, there's the right way, the wrong way, and the UNIX way. If you aren't an experienced UNIX/Linux user, you may wind up reinventing the wheel when you need to perform some task. That's why I wanted to talk a little about how things work on a typical system that might be of use in an embedded Linux system.

What brought this to mind was a piece of code I recently was asked to examine. There was nothing wrong with it per se, but it wasn't necessarily very efficient. The program needed to do something every 15 minutes. It didn't have to be that precise, either. It just needed to wake up periodically and take a few data samples to send over the network.

The programmer simply put the program in a loop watching the time. That works, of course, but it does eat up resources unnecessarily. Sleeping would have been a little better since the operating system would suspend the calling process until it was time to run.

However, you can do even better that. The key is to use the cron facility provided by nearly all UNIX and Linux systems. The idea behind cron is simple: Each user has a protected file (a crontab) that has a line for each job the system should launch at a particular time.

The file is hidden away in the system, so you can't edit it directly as a regular user. Instead, you should use one of the following commands:

crontab file
crontab –e

The first command replaces your current crontab with a new one. The second lets you edit the file interactively. If you want to see what's already there you can use the –l option and to remove your crontab, you can use –r.

If the /etc/cron.allow file exists, your user ID has to appear there or you won't be able to use cron. There is also (possibly) an /etc/cron.deny file, which lists users who are not allowed to use cron. Of course, root can always use cron regardless.

A crontab file can have two kinds of active lines. You can assign environment variables in the way you expect:


This is just like setting an environment variable. However, note that you don't get any replacement like you do in the shell, so the following command won't behave the way you expect:


The other type of line that can appear are lines with six fields separated by spaces or tabs. The fields are in this order: minute, hour, day of month, month, day of week, and command.

It might seem odd that you'd specify the day of the month and the day of the week. In reality, you'd rarely specify both (if you do, the command runs when either field matches, which isn't usually very useful). You can use an asterisk for any field to indicate that any value matches. For example:

0 12 1 * * dayone_command

This line runs dayone_command at 12:00 on the first of every month. You can also specify lists and ranges:

0,5,10 0-4 * * * a_command

This rule runs a_command between midnight and 4am at 0 minutes after the hour, 5 minutes after the hour, and 10 minutes after the hour. There are some other special rules. For example, you could rewrite "0,5,10" as 0-10/5. You can use the same trick after an asterisk. For example "*/2" in the hour field indicates every two hours.

Month and day of week can also handle names (but not lists or ranges of names). So you can say, "Jan" for January (or, for that matter, you can spell it out — cron only looks at the first three letters). If you use numbers for the day of the week, both 0 and 7 represent Sunday.

The command runs all the way to the end of the line. If you need to use multiple lines, the percent character (%) stands in for a newline (unless you escape it with a backslash; then it is just a percent sign).

Cron also takes some special strings that stand in for the first five fields if you want to use them: @reboot, @yearly, @annually, @monthly, @weekly, @daily, @midnight, and @hourly. These all mean what you think (well, @reboot means when cron starts) and all except @reboot can be duplicated by using the right values in the regular fields.

Like most Linux files, the # character indicates a comment. There is a system-wide crontab at /etc/crontab that uses almost the exact syntax except the 6th field is a user name and then the command to run. Many systems have default entries in this crontab that will run scripts hourly, daily, weekly, and monthly if they appear in /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly, and /etc/cron.monthly, respectively. Having a program write a script into these directories is an easy way to use cron from a program.

The system crontab that sets these up looks like this:


# m h dom mon dow user  command
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )

Remember, these have the user name because it is a system-wide crontab. Modern versions of cron also look for system crontabs in /etc/cron.d.

There is also a similar program called anacron that can be used instead of cron (although it relies on cron, so it doesn't actually replace it). This is very similar to cron, but it understands that the system may not be on continuously. The rules use a delay form instead of an absolute runtime and can't run tasks any faster than once a day, so the file format isn't the same as cron. There are other cron replacements, including fcron, dcron, cronie, and Vixiecron.

Another alternative, if you are interested, is the possibility of using a remote cron job to cause an action on your system via the network. You could use a "cloud-based" service like https://www.setcronjob.com/, http://www.onlinecronjobs.com/, or http://www.easycron.com/ or you could use cron on a remote Linux box and have it execute commands on the embedded system using ssh or some other mechanism.

If you want to try cron, you might enjoy the cron translator, which converts a cron date/time specification to English or this site, which takes the same input and shows you the next few dozen times a cron job would run given a particular date/time specification.

So while my friend's code worked by looping for 15 minutes, he might have been better off writing a simple program to do the job he needed and exiting. Then cron would launch the program every 15 minutes. If you have enough resources, of course, it probably doesn't matter at all. However, if you are fighting to squeeze features into a tiny embedded system, you have a trade to make. If you need cron anyway, the incremental cost of using it will be tiny, if not zero. The cost of having a process running or even sleeping for a long duration will probably be higher. If you could convince yourself you don't need to run the cron daemon, then that might be a different decision, depending on your overall system.

Related Reading

More Insights

Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.