Home > Articles > Operating Systems, Server > Linux/UNIX/Open Source

This chapter is from the book

7.4 System Clock: Of Time and Timers

For scheduling, the kernel uses the system clock to know how long a task has been running. We already covered the system clock in Chapter 5 by using it as an example for the discussion on interrupts. Here, we explore the Real-Time Clock and its uses and implementation; but first, let’s recap clocks in general.

The clock is a periodic signal applied to a processor, which allows it to function in the time domain. The processor depends on the clock signal to know when it can perform its next function, such as adding two integers or fetching data from memory. The speed of this clock signal (1.4GHz, 2GHz, and so on) has historically been used to compare the processing speed of systems at the local electronics store.

At any given moment, your system has several clocks and/or timers running. Simple examples include the time of day displayed in the bottom corner of your screen (otherwise known as wall time), the cursor patiently pulsing on a cluttered desktop, or your laptop screensaver taking over because of inactivity. More complicated examples of timekeeping include audio and video playback, key repeat (holding a key down), how fast communications ports run, and, as previously discussed, how long a task can run.

7.4.1 Real-Time Clock: What Time Is It?

The Linux interface to wall clock time is accomplished through the /dev/rtc device driver ioctl() function. The device for this driver is called a Real-Time Clock (RTC). The RTC9 provides timekeeping functions with a small 114-byte user NVRAM. The input to this device is a 32.768KHz oscillator and a connection for battery backup. Some discrete models of the RTC have the oscillator and battery built in, while other RTCs are now built in to the peripheral bus controller (for example, the Southbridge) of a processor chipset. The RTC not only reports the time of day, but it is also a programmable timer that is capable of interrupting the system. The frequency of interrupts varies from 2Hz to 8,192Hz. The RTC can also interrupt daily, like an alarm clock. Here, we explore the RTC code:

–----------------------------------------------------------------------
/include/linux/rtc.h

/*
 * ioctl calls that are permitted to the /dev/rtc interface, if
 * any of the RTC drivers are enabled.
 */

70 #define RTC_AIE_ON  _IO(’p’, 0x01) /* Alarm int. enable on */
71 #define RTC_AIE_OFF  _IO(’p’, 0x02) /* ... off  */
72 #define RTC_UIE_ON  _IO(’p’, 0x03) /* Update int. enable on */
73 #define RTC_UIE_OFF  _ IO(’p’, 0x04) /* ... off  */
74 #define RTC_PIE_ON  _IO(’p’, 0x05) /* Periodic int. enable on */
75 #define RTC_PIE_OFF  _IO(’p’, 0x06) /* ... off  */
76 #define RTC_WIE_ON  _IO(’p’, 0x0f) /* Watchdog int. enable on */
77 #define RTC_WIE_OFF  _IO(’p’, 0x10) /* ... off  */

78 #define RTC_ALM_SET  _IOW(’p’, 0x07, struct rtc_time) /* Set alarm time */
79 #define RTC_ALM_READ _IOR(’p’, 0x08, struct rtc_time) /* Read alarm time*/
80 #define RTC_RD_TIME  _IOR(’p’, 0x09, struct rtc_time) /* Read RTC time */
81 #define RTC_SET_TIME _IOW(’p’, 0x0a, struct rtc_time) /* Set RTC time */
82 #define RTC_IRQP_READ _IOR(’p’, 0x0b, unsigned long) /* Read IRQ rate*/
83 #define RTC_IRQP_SET _IOW(’p’, 0x0c, unsigned long) /* Set IRQ rate */
84 #define RTC_EPOCH_READ _IOR(’p’, 0x0d, unsigned long) /* Read epoch */
85 #define RTC_EPOCH_SET _IOW(’p’, 0x0e, unsigned long) /* Set epoch */
86 
87 #define RTC_WKALM_SET _IOW(’p’, 0x0f, struct rtc_wkalrm)/*Set wakeupalarm*/
88 #define RTC_WKALM_RD _IOR(’p’, 0x10, struct rtc_wkalrm)/*Get wakeupalarm*/
89 
90 #define RTC_PLL_GET  _IOR(’p’, 0x11, struct rtc_pll_info) /* Get PLL correction */
91 #define RTC_PLL_SET  _IOW(’p’, 0x12, struct rtc_pll_info) /* Set PLL correction */ 
-----------------------------------------------------------------------

The ioctl() control functions are listed in include/linux/rtc.h. At this writing, not all the ioctl() calls for the RTC are implemented for the PPC architecture. These control functions each call lower-level hardware-specific functions (if implemented). The example in this section uses the RTC_RD_TIME function.

The following is a sample ioctl() call to get the time of day. This program simply opens the driver and queries the RTC hardware for the current date and time, and prints the information to stderr. Note that only one user can access the RTC driver at a time. The code to enforce this is shown in the driver discussion.

–----------------------------------------------------------------------
Documentation/rtc.txt
/*
 * Trimmed down version of code in /Documentation/rtc.txt
 *
 */


int main(void) {

int fd, retval = 0;
//unsigned long tmp, data;
struct rtc_time rtc_tm;

fd = open ("/dev/rtc", O_RDONLY);


/* Read the RTC time/date */
retval = ioctl(fd, RTC_RD_TIME, &rtc_tm);

/* print out the time from the rtc_tm variable */

close(fd);
return 0;

} /* end main */
------------------------------------------------------------------------

This code is a segment of a more complete example in /Documentation/ rtc.txt. The two main lines of code in this program are the open() command and the ioctl() call. open() tells us which driver we will use (/dev/rtc) and ioctl() indicates a specific path through the code down to the physical RTC interface by way of the RTC_RD_TIME command. The driver code for the open() command resides in the driver source, but its only significance to this discussion is which device driver was opened.

7.4.2 Reading the PPC Real-Time Clock

At kernel compile time, the appropriate code tree (x86, PPC, MIPS, and so on) is inserted. The source branch for PPC is discussed here in the source code file for the generic RTC driver for non-x86 systems:

–----------------------------------------------------------------------
/drivers/char/genrtc.c 
276 static int gen_rtc_ioctl(struct inode *inode, struct file *file,
277  unsigned int cmd, unsigned long arg)
278 {
279  struct rtc_time wtime;
280  struct rtc_pll_info pll;
281 
282  switch (cmd) {
283 
284  case RTC_PLL_GET:
... 
290  case RTC_PLL_SET:
...
298  case RTC_UIE_OFF: /* disable ints from RTC updates. */
...
302  case RTC_UIE_ON: /* enable ints for RTC updates. */
...
305  case RTC_RD_TIME: /* Read the time/date from RTC */
306  
307  memset(&wtime, 0, sizeof(wtime));
308  get_rtc_time(&wtime);
309 
310  return copy_to_user((void *)arg,&wtime,sizeof(wtime)) ? -EFAULT:0;
311
312  case RTC_SET_TIME: /* Set the RTC */
313  return -EINVAL;
314  }
...
353 static int gen_rtc_open(struct inode *inode, struct file *file)
354 {
355  if (gen_rtc_status & RTC_IS_OPEN)
356  return -EBUSY;
357  gen_rtc_status |= RTC_IS_OPEN;
------------------------------------------------------------------------

This code is the case statement for the ioctl command set. Because we made the ioctl call from the user space test program with the RTC_RD_TIME flag, control is transferred to line 305. The next call is at line 308, get_rtc_time(&wtime) in rtc.h (see the following code). Before leaving this code segment, note line 353. This allows only one user to access, via open(), the driver at a time by setting the status to RTC_IS_OPEN:

–----------------------------------------------------------------------
include/asm-ppc/rtc.h
045 static inline unsigned int get_rtc_time(struct rtc_time *time)
046 {
047  if (ppc_md.get_rtc_time) {
048   unsigned long nowtime;
049  
050  nowtime = (ppc_md.get_rtc_time)();
051  
052   to_tm(nowtime, time);
053  
054   time->tm_year -= 1900;
055 time->tm_mon -= 1; /* Make sure userland has a 0-based month */
056  }
057  return RTC_24H;
058 }
------------------------------------------------------------------------

The inline function get_rtc_time() calls the function that the structure variable pointed at by ppc_md.get_rtc_time on line 50. Early in the kernel initialization, this variable is set in chrp_setup.c:

–----------------------------------------------------------------------
arch/ppc/platforms/chrp_setup.c
447 chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
448 unsigned long r6, unsigned long r7)
449 {
...
477  ppc_md.time_init = chrp_time_init;
478  ppc_md.set_rtc_time = chrp_set_rtc_time;
479  ppc_md.get_rtc_time = chrp_get_rtc_time;
480  ppc_md.calibrate_decr = chrp_calibrate_decr;
------------------------------------------------------------------------

The function chrp_get_rtc_time() (on line 479) is defined in chrp_time.c in the following code segment. Because the time information in CMOS memory is updated on a periodic basis, the block of read code is enclosed in a for loop, which rereads the block if the update is in progress:

–----------------------------------------------------------------------
arch/ppc/platforms/chrp_time.c
122 unsigned long __chrp chrp_get_rtc_time(void)
123 {
124  unsigned int year, mon, day, hour, min, sec;
125  int uip, i;
... 
141  for ( i = 0; i<1000000; i++) {
142  uip = chrp_cmos_clock_read(RTC_FREQ_SELECT);
143  sec = chrp_cmos_clock_read(RTC_SECONDS);
144  min = chrp_cmos_clock_read(RTC_MINUTES);
145  hour = chrp_cmos_clock_read(RTC_HOURS);
146  day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH);
147  mon = chrp_cmos_clock_read(RTC_MONTH);
148  year = chrp_cmos_clock_read(RTC_YEAR);
149  uip |= chrp_cmos_clock_read(RTC_FREQ_SELECT);
150  if ((uip & RTC_UIP)==0) break;
151  }
152  if (!(chrp_cmos_clock_read(RTC_CONTROL)
153  & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
154  {
155  BCD_TO_BIN(sec);
156  BCD_TO_BIN(min);
157  BCD_TO_BIN(hour);
158  BCD_TO_BIN(day);
159  BCD_TO_BIN(mon);
160  BCD_TO_BIN(year); 
161  }
...
054 int __chrp chrp_cmos_clock_read(int addr)
055 {  if (nvram_as1 != 0)
056  outb(addr>>8, nvram_as1);
057  outb(addr, nvram_as0);
058  return (inb(nvram_data));
059 }
------------------------------------------------------------------------

Finally, in chrp_get_rtc_time(), the values of the individual components of the time structure are read from the RTC device by using the function chrp_cmos_clock_read. These values are formatted and returned in the rtc_tm structure that was passed into the ioctl call back in the userland test program.

7.4.3 Reading the x86 Real-Time Clock

The methodology for reading the RTC on the x86 system is similar to, but somewhat more compact and robust than, the PPC method. Once again, we follow the open driver /dev/rtc, but this time, the build has compiled the file rtc.c for the x86 architecture. The source branch for x86 is discussed here:

–----------------------------------------------------------------------
drivers/char/rtc.c 
...
352 static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
353 {
...
switch (cmd) {
...
482 case RTC_RD_TIME: /* Read the time/date from RTC */
483 {
484  rtc_get_rtc_time(&wtime);
485  break;
486 }
...
1208 void rtc_get_rtc_time(struct rtc_time *rtc_tm)
1209 {
...
1238  spin_lock_irq(&rtc_lock);
1239  rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
1240  rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
1241  rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
1242  rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
1243  rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
1244  rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
1245  ctrl = CMOS_READ(RTC_CONTROL);
...
1249 spin_unlock_irq(&rtc_lock);
1250
1251 if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
1252 {
1253  BCD_TO_BIN(rtc_tm->tm_sec);
1254  BCD_TO_BIN(rtc_tm->tm_min);
1255  BCD_TO_BIN(rtc_tm->tm_hour);
1256  BCD_TO_BIN(rtc_tm->tm_mday);
1257  BCD_TO_BIN(rtc_tm->tm_mon);
1258  BCD_TO_BIN(rtc_tm->tm_year);
1259 }
------------------------------------------------------------------------

The test program uses the ioctl() flag RTC_RD_TIME in its call to the driver rtc.c. The ioctl switch statement then fills the time structure from the CMOS memory of the RTC. Here is the x86 implementation of how the RTC hardware is read:

–----------------------------------------------------------------------
include/asm-i386/mc146818rtc.h 
...
018 #define CMOS_READ(addr) ({ \
019  outb_p((addr),RTC_PORT(0)); \
020  inb_p(RTC_PORT(1)); \
021 })
-----------------------------------------------------------------------

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020