Q1: “It” is wake_up
. It wakes up all tasks that are waiting for the disk data. If they weren't waiting for that data, they wouldn't be waiting on that queue.
Q2: I'm not sure I understand the question. Each wake queue entry contains a pointer to the task. try_to_wake_up
receives a pointer to the task that it's supposed to wake up. It is called once per function.
Q3: There are lots of wait queues. There's one for every event that can happen. The disk driver sets up a wait queue for each request to the disk. For example, when the filesystem driver wants the content of a certain disk block, it asks the disk driver for that block, and then the request starts with the task that made the filesystem request. Other entries may be added to the wait queue if another request for the same block comes in while this one is still outstanding.
When an interrupt happens, the disk driver determines which disk has data available from the information passed by the hardware and looks up the data structure that contains the kernel data for this disk to find which request was to be filled. In this data structure, among others, are the location where the data is to be written and the corresponding wake queue indicating what to do next.
Q4: The process makes a system call, let's say to read a file. This triggers some code in the filesystem driver which determines that the data needs to be loaded from the disk. That code makes a request to the disk driver and adds the calling process to the request's wait queue. (There are actually more layers than that, but you get the idea.) When the disk read completes, the wait queue event triggers, and the process is thus removed from the disk's wait queue. The code triggered by the wait queue event is a function supplied by the filesystem driver, which copies the data to the process's memory and causes the read
system call to return.
From a task_struct
perspective, a process’s threads have the same thread group leader (group_leader
in task_struct
), whereas child processes have a different thread group leader (each individual child process).
This information is exposed to user space via the /proc
file system. You can trace parents and children by looking at the ppid
field in /proc/${pid}/stat
or .../status
(this gives the parent pid); you can trace threads by looking at the tgid
field in .../status
(this gives the thread group id, which is also the group leader’s pid). A process’s threads are made visible in the /proc/${pid}/task
directory: each thread gets its own subdirectory. (Every process has at least one thread.)
In practice, programs wishing to keep track of their own threads would rely on APIs provided by the threading library they’re using, instead of using OS-specific information. Typically on Unix-like systems that means using pthreads.
Best Answer
You can get a lot of internal information about processes, the scheduler, and other components of the OS and the hardware by using
where ... can be many things. For instance, it could be a process ID, followed by a lot of specific information request, or scheduler debug information request, for example:
To see the whole list of options, type
ls /proc
. You will see a long list of process ID numbers, but also a few interesting names, such as sched_debug, cpuinfo, meminfo, uptime, and more.All this is available thanks to the virtual file system procfs You can read more about it here.
Another useful command is:
This will show a real time information about how the processes are scheduled, memory usage, and more.