I am implementing system call that will return the current time of the day (for learning purpose).
I have looked at implementations of gettimeofday() on Linux 3.19.2
from the books I checked I got that
The current time of day (the wall time) is defined in kernel/time/timekeeping.c:
struct timespec xtime;
[Linux kernel development Rober Love]
however I couldn't able to get the xtime variable definition in that file.
where is the xtime variable declared in the Linux kernel and how can I access it from my module or my function?
what are the headers I should include?
That reference is obsolete. Recent kernels no longer have xtime. Though there are still some fields in the kernel timekeeping structure with a prefix of xtime_ that I assume are descended from it. See, for example, struct timekeeper in include/linux/timekeeper_internal.h.
You would probably want to stick to the slightly more stable functions defined in include/linux/timekeeping.h
Related
Why does libc_nonshared.a exist? What purpose does it serve? I haven't been able to find a good answer for its existence online.
As far as I can tell it provides certain symbols (stat, lstat, fstat, atexit, etc.). If someone uses one of these functions in their code, it will get linked into the final executable from this archive. These functions are part of the POSIX standard and are pretty common so I don't see why they wouldn't just be put in the shared or static libc.so.6 or libc.a, respectively.
It was a legacy mistake in glibc's implementing extensibility for the definition of struct stat before better mechanisms (symbol redirection or versioning) were thought of. The definitions of the stat-family functions in libc_nonshared.a cause the version of the structure to bind at link-time, and the definitions there call the __xstat-family functions in the real shared libc, which take an extra argument indicating the desired structure version. This implementation is non-conforming to the standard since each shared library ends up gettings its own copy of the stat-family functions with their own addresses, breaking the requirement that pointers to the same function evaluate equal.
Here's the problem. Long ago, members of the struct stat structure had different sizes than they had today. In particular:
uid_t was 2 bytes (though I think this one was fixed in the transition from libc5 to glibc)
gid_t was 2 bytes
off_t was 4 bytes
blkcnt_t was 4 bytes
time_t was 4 bytes
also, timespec wasn't used at all and there was no room for nanosecond precision.
So all of these had to change. The only real solution was to make different versions of the stat() system call and library function and you get the version you compiled against. That is, the .a file matches the header files. These things didn't all change at once, but I think we're done changing them now.
You can't really solve this by a macro because the structure name is the same as the function name; and inline wasn't mandated to exist in the beginning so glibc couldn't demand everybody use it.
I remember there used to be this thing O_LARGEFILE for saying you could handle files bigger than 4GB; otherwise things just wouldn't work. We also used to have to define things like _LARGEFILE_SOURCE and _LARGEFILE64_SOURCE but it's all handled automatically now. Back in the day, if you weren't ready for large file support yet, you didn't define these and you didn't get the 64-bit version of the stat structure; and also worked on older kernel versions lacking the new system calls. I haven't checked; it's possible that 32-bit compilation still doesn't define these automatically, but 64-bit always does.
So you probably think; okay, fine, just don't franken-compile stuff? Just build everything that goes into the final executable with the same glibc version and largefile-choice. Ever use plugins such as browser plugins? Those are pretty much guaranteed to be compiled in different places with different compiler and glibc versions and options; and this didn't require you to upgrade your browser and replace all its plugins at the same time.
I've heard filldir()/filldir64() lets the kernel specify the "dirent" (directory entry) layout depending on the binary type. Why do differing binary types matter?
I am also confused about dir_context, I assume filldir64() can be defined by other filesystems and implemented differently? So is that why there is an actor member?
filldir64(): https://elixir.bootlin.com/linux/latest/source/fs/readdir.c#L307
dir_context: https://elixir.bootlin.com/linux/latest/source/include/linux/fs.h#L1776
The reason for this is to run old binaries. The ABI of the readdir() system call has changed a few times. The way this works is each system call number calls a different function. There's a common implementation of the filldir loop that dispatches to the filesystem-specific calls to read directory entires, and again dispatches to the appropriate filldir() implementation.
dir_context is defined by the specific implementation of filldir() to retain some state between calls. Desipite being written in C, the filesystem is object-oriented code. When you see stuff like this, start thinking virtual method dispatch, becasue effectively that's what it is. But since it's done in C, the this pointer has to be passed manually as the first argument.
I see the following code in some OS kernel. But I don't understand the way __section is used, and don't know what does this code mean.
#define KEEP_PAGER(sym) \
extern const unsigned long ____keep_pager_##sym; \
const unsigned long ____keep_pager_##sym \
__section("__keep_meta_vars_pager") = (unsigned long)&sym
It's specific linux kernel C macro definition wrapped around a GCC extension, specifying an atttribute to use for an object. It's a shorter way of writing the section attribute definition
Historically the linux kernel has been written specifically for building with the GCC compiler, and makes extensive use of low level extensions to do specific hardware operations and optimisations.
The section attribute specifically is used to determine the storage location of the object tagged with it. ELF binary format arranges the object file into named sections, and using the attribute like this allows the programmer to more precisely specify where the information for the tagged object will be placed in the target object
Over the years, there's been work put in to increasing the compatibility of these compiler extensions between different compilers, as well as making linux compilable with alternative compilers (if you look at the linux header file where the macro is defined you'll see that it is full of conditional directives for various compiler features). Macros like this can be a useful way to have a portable internal API for low level features across different compiler implementations.
Kernel and kernel driver C code is atypically concerned with direct specifics of physical hardware implementation, and needs to be explicit about the compiler binary output in a way that application level C code rarely will.
One example of why the linux kernel uses named sections is in the init handling - functions and data that are only used during bootup are grouped into one section of memory that can be easily released once startup is complete - you may be familiar with the boot message along the lines of 'freeing unused kernel memory:...' towards the end of the linux boot sequence
It is hard to tell what that __section is exactly without its definition, but it might be a variable "section" attribute. It is used to make compiler place variable into a section different from "bss" or "data". See GCC documentation for details.
Why is the difference between oldolduname and uname?
I have been reading the man pages and I don't get the subtlety.
First of all, if you call uname from userspace, you do not need to care about the difference, and there should be no need to use olduname or oldolduname. From userspace, you use struct utsname and you call the uname() function.
From the man page:
Over time, increases in the size of the utsname structure have led to
three successive versions of uname(): sys_olduname() (slot
__NR_oldolduname), sys_uname() (slot __NR_olduname), and sys_newuname() (slot __NR_uname). The first one used length 9 for all
fields; the second used 65; the third also uses 65 but adds the
domainname field. The glibc uname() wrapper function hides these
details from applications, invoking the most recent version of the
system call provided by the kernel.
So, throughout history the sizes and content of struct utsname has changed slightly, and the kernel has kept 3 different versions around to keep compatibility with userspace, you can see the different versions that the kernel handles here: http://lxr.free-electrons.com/source/include/linux/utsname.h?v=2.6.38#L24 . However glibc, or any C library on linux hides all this from you.
uname is the function called by user code.
It calls one of the kernel functions sys_newuname, sys_uname, or sys_olduname, depending on the version of the Linux kernel. The difference between these is the lengths of the name fields (9 characters in sys_olduname, 65 characters in the other two), and sys_newuname adds an additional domainname field to the structure.
I'm currently migrating some of my code from Cocoa (Apple's Objective-C API) to C, in order to make it available for other operating systems, such as GNU/Linux.
In Cocoa, there were many great things like creating NSTimeZone objects from their string descriptors using timeZoneWithAbbreviation:. This allowed me to use values like "Europe/Paris" to easily create NSTimeZone objects.
Another important method for me was secondsFromGMTForDate: because it automatically considers DST rules for you.
Right now, the closest thing to NSTimeZone I've found for C is the struct timezone (see here). However, I do not see how I can easily get the GMT "offset" in seconds for a specific time and timezone. Neither do I understand how to get timezone structs if you only have a description like "Europe/Paris".
The following is my understanding and may be wrong...
I'm not sure how OS X does it, but on Linux, the standard C timezone functions use the Olson database, which is really quite powerful (since it has a full list of locale descriptions and keeps track of historical time zone rules as well as current rules).
To set a time zone, call tzset. This function is automatically called by other time-related functions, but you can manually specify a different time zone from the system default by setting the TZ environment variable then calling tzset. For example:
int main(int argc, char *argv[]) {
time_t t = time(NULL);
printf("%s\n", ctime(&t));
setenv("TZ", "America/Chicago", 1);
printf("%s\n", ctime(&t));
return 0;
}
Calling tzset also sets the timezone global variable, which you can use to find the GMT offset in seconds for the current time zone.
These functions only let you use one time zone at a time, and although all of this (except for possibly the timezone global variable) should be standard C, platforms other than Linux may not have the full support for lists of locales, daylight savings time changes, etc. If you find that this doesn't meet your needs, then you can try using third-party libraries, such as the code distributed with the [Olson database] or ICU's TimeZone class (also usable from C).
Unfortunately, you are treading into difficult territory. There isn't a good, widely available time zone library not attached to other major projects. You can look at the code that comes with the Olson Database (of time zones), and you can look at ICU (Internationalization Components for Unicode).