Lab4 Scheduling
Lab4 Scheduling
Lab 4
Multi-tasking and Scheduler activations
Course: Operating Systems
April 1, 2024
Goal This lab helps the student practice scheduler activation in multi-tasking context (process or thread
based implementation), and figure out why we need the multi-task management framework.
Contents In detail, this lab requires the student practice experiments using scheduler activation to
provide the multi-tasking environment:
• CPU scheduler
• Dispatcher
Besides, the practices include the implementation of self-setup multi-tasking framework called bktpool
(BK task pool). In addition to support implicit threading technique, we might cover further model of
creation and management of threads i.e. fork-join, OpenMP (or CUDA), Grand Central Dispatch, Thread
Building Block etc.
Result After doing this lab, student can understand the framework of multi-tasking using the techniques
above to provide the scheduling feature.
1
CONTENTS CONTENTS
Contents
1 Background 3
1.1 Multi-tasking environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Scheduling subsystem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2 Programming Interfaces 6
2.1 Multi-task programming interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.1.1 fork() API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.1.2 pthread create API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.1.3 clone() API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.2 Signal handler API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.2.1 kill and tkill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.2.2 sigwait() API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2.3 sigaction() API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.3 BK TaskPool API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.3.1 Task declaration API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.3.2 Task Pool Usage API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.4 A Linux Scheduler - Cron . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.4.1 Introduction to Cron . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.4.2 Crontab . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.4.3 Crontab Syntax and Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.4.4 Linux Crontab Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3 Practices 13
3.1 Multitasking framework illustration BK TPool . . . . . . . . . . . . . . . . . . . . . . . . 13
3.1.1 Create a set of resource entities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.1.2 CPU scheduler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.1.3 Dispatcher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.1.4 Finalize task pool and resource worker . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.2 Practice with CronTab . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
4 Exercise 20
2
1 BACKGROUND
1 Background
1.1 Multi-tasking environment
Multicore or multiprocessor systems putting pressure on programmers, challenges include:
• Dividing activities
• Balance
• Data splitting
• Data dependency
The task is an abstract entity to quantitize the CPU computation power. We can implement it using
the both concepts introduced in the first few chapter of Operating System course include process creating
with fork system call or thread creating with thread library such as POSIX Thread (aka pthread). Despite
of the comfortable of using the provided library, thread has a long history of development from userspace
(down) to kernel space.
When the thread are placed in userspace or the legacy code, the mapping model is N:1 in which
multiple thread is mapped in to one kernel thread and the scheduler has to decide which user thread are
dispatch to take owner the computation resource. In this work, we deal with the same problem as the
legacy thread library. We develop a scheduling subsystem to deploy multi-task on top a limit hardware
computation resource.
Control using Signals are used in UNIX systems to notify a process that a particular event has
occurred.
Multithreading model
• Example system GNU Portable Thread (Few system currently use this model)
3
1.2 Scheduling subsystem 1 BACKGROUND
Mnay-to-many Allows many user level threads to be mapped to many kernel threads
• Example system: Windows with the ThreadFiber package (Otherwise not very common)
• Signal handling
– Asynchronous or deferred
• Thread-local storage
• Scheduler Activations
4
1.2 Scheduling subsystem 1 BACKGROUND
Dispatcher module gives control of the CPU to the process selected by the short-term scheduler; this
involves:
5
2 PROGRAMMING INTERFACES
2 Programming Interfaces
2.1 Multi-task programming interface
2.1.1 fork() API
creates a new process by duplicating the calling process. The new process, referred to as the child, is an
exact duplicate of the calling process, referred to as the parent
#include <u n i s t d . h>
p i d t f o r k ( void )
The system call is the backend for both fork() API and pthread create() API. clone() creates a new
process, in a manner similar to fork(2). It is actually a library function layered on top of the underlying
clone() system call. The superior of system call clone is the backend to provide a thread creation inside
a thread. Pthread create() is so-called a wrapper of system call clone().
CLONE THREAD (since Linux 2.4.0-test8) If CLONE THREAD is set, the child is placed in the
same thread group as the calling process. To make the remainder of the discussion of CLONE THREAD
more readable, the term ”thread” is used to refer to the processes within a thread group. Thread groups
were a feature added in Linux 2.4 to support the POSIX threads notion of a set of threads that share
a single PID. Internally, this shared PID is the so-called thread group identifier (TGID) for the thread
group.
#define GNU SOURCE
#include <s c h e d . h>
6
2.3 BK TaskPool API 2 PROGRAMMING INTERFACES
The tgkill() system call sends the signal sig to the thread with the thread ID tid in the thread group
tgid. The tkill() is an obsolete predecessor to tgkill(). It allows only the target thread ID to be specified,
which may result in the wrong thread being signaled if a thread terminates and its thread ID is recycled.
Avoid using this system call.
#include <s i g n a l . h>
int s y s c a l l ( S Y S t k i l l , p i d t t i d , int s i g ) ;
-----------------------------------------
#include <s i g n a l . h>
int t g k i l l ( p i d t t g i d , p i d t t i d , int s i g ) ;
The function suspends execution of the calling thread until one of the signals specified in the signal set
set becomes pending. The function accepts the signal (removes it from the pending list of signals), and
returns the signal number in sig.
#include <s i g n a l . h>
The system call is used to change the action taken by a process on receipt of a specific signal.
#include <s i g n a l . h>
Task definition requires a job execution function. We share almost the same API with other library by
defining task init include the 2 information of what function task will be executed and the argument to
passing to the function.
int b k t a s k i n i t ( int ∗ t a s k i d , void ∗ ( ∗ s t a r t r o u t i n e ) ( void ∗ ) , void ∗ a r g ) ;
7
2.3 BK TaskPool API 2 PROGRAMMING INTERFACES
return 0 ;
}
int main ( )
{
...
id [ 0 ] = 1; b k t a s k i n i t (& t i d [ 0 ] , &func , ( void ∗ )& i d [ 0 ] ) ;
id [ 1 ] = 2; b k t a s k i n i t (& t i d [ 0 ] , &func , ( void ∗ )& i d [ 1 ] ) ;
id [ 2 ] = 5; b k t a s k i n i t (& t i d [ 0 ] , &func , ( void ∗ )& i d [ 2 ] ) ;
...
}
int b k w r k g e t w o r k e r ( ) ;
-------------------
int b k t a s k a s s i g n w o r k e r ( int b k t a s k i d , int wrkid ) ;
-------------------
int b k w r k d i s p a t c h w o r k e r ( int wrkid ) ;
b k w r k d i s p a t c h w o r k e r ( wid [ 1 ] ) ;
...
}
8
2.4 A Linux Scheduler - Cron 2 PROGRAMMING INTERFACES
Cron is a scheduling daemon that executes tasks at specified intervals. These tasks are called cron jobs
and are mostly used to automate system maintenance or administration.
For example, we can set up a cron job to automate repetitive tasks such as backing up databases or
data, updating the system with the latest security patches, checking disk space usage, sending emails, etc.
The cron jobs can be scheduled to run by a minute, hour, day of the month, month, day of the week, or
any combination of these. For Ubuntu, we can inspect the cron service by running the following command:
In the case there is an error of "command not found", you need to check and install the package from
the repository
# Verify the existance of the required package
$ sudo dpkg - l | grep systemd
i i libpam - systemd : amd64 system and s e r v i c e manager - PAM module
i i libsystemd - daemon0 : amd64 systemd u t i l i t y l i b r a r y
i i libsystemd - login0 : amd64 systemd login u t i l i t y l i b r a r y
i i systemd - s e r v i c e s systemd runtime s e r v i c e s
i i systemd - shim shim for systemd
9
2.4 A Linux Scheduler - Cron 2 PROGRAMMING INTERFACES
2.4.2 Crontab
Crontab (cron table) is a text file that specifies the schedule of cron jobs. There are two types of crontab
files. The system-wide crontab files and individual user crontab files. Users’ crontab files are named ac-
cording to the user’s name, and their location is at the /var/spool/cron/crontabs directory on Ubuntu.
The /etc/crontab file and the scripts inside the /etc/cron.d directory are system-wide crontab files
that can be edited only by the system administrators.
Fgure 4 describes the cron cycle. Cron will inspect the user defined cron jobs and execute them if
needed. It will also inspect the crontab file where several default cron jobs are defined by default.
Those default cron jobs are scripts that instructs your host to verify every minute, every hour, every
day and every week specific folders and to execute the scripts that are inside them.
10
2.4 A Linux Scheduler - Cron 2 PROGRAMMING INTERFACES
Finally, the cron.d directory is inspected. The cron.d may contain custom cron files and it also
contains a very important file which is the anacron cron file.
Each line in the user crontab file contains six fields separated by a space followed by the command to be
run:
∗ ∗ ∗ ∗ ∗ command( s ) output
- - - - -
| | | | |
| | | | - - - - - Day of week (0 - 7) (Sunday=0 or 7) (Mon - Sun)
| | | - - - - - - - Month (1 - 12)
| | - - - - - - - - - Day of month (1 - 31)
| - - - - - - - - - - - Hour (0 - 23)
- - - - - - - - - - - - - Minute (0 - 59)
• The first five fields * * * * * specify the time/date and recurrence of the job.
• In the second section, the command specifies the location and script you want to run.
• The final segment output is optional. It defines how the system notifies the user of the job comple-
tion. Cron will issue an email if there is any output from the cron job. Cron jobs are meant to not
produce any output if everything is ok.
The first five fields may contain one or more values, separated by a comma or a range of values
separated by a hyphen.
• “*” - The asterisk operator means any value or always. If you have the asterisk symbol in the Hour
field, it means the task will be performed each hour.
• “,” - The comma operator allows you to specify a list of values for repetition. For example, if you
have 1,3,5 in the Hour field, the task will run at 1 am, 3 am, and 5 am.
• ”-” The hyphen operator allows you to specify a range of values. If you have 1-5 in the Day of the
week field, the task will run every weekday (From Monday to Friday).
• “/” - The slash operator allows you to specify values that will be repeated over a certain interval
between them. For example, if you have */4 in the Hour field, it means the action will be performed
every four hours. It is same as specifying 0,4,8,12,16,20. Instead of an asterisk before the slash
operator, you can also use a range of values, 1-30/10 means the same as 1,11,21.
There are several special Cron schedule macros used to specify common intervals. We can use these
shortcuts in place of the five-column date specification:
• @yearly (or @annually) - Run the specified task once a year at midnight (12:00 am) of the 1st of
January. Equivalent to 0 0 1 1 *.
11
2.4 A Linux Scheduler - Cron 2 PROGRAMMING INTERFACES
• @monthly - Run the specified task once a month at midnight on the first day of the month. Equiv-
alent to 0 0 1 * *.
• @weekly - Run the specified task once a week at midnight on Sunday. Equivalent to 0 0 * * 0.
• @hourly - Run the specified task once an hour at the beginning of the hour. Equivalent to 0 * *
* *.
Example:
1. 10 10 1 * * /path/to/script.sh: A cron job that executes every 10:10 AM each month on the
first day.
The crontab command allows you to install, view, or open a crontab file for editing:
• crontab -i - Remove your current crontab file with a prompt before removal.
• crontab -u <username> - Edit other user crontab file. This option requires system administrator
privileges.
• The default path is set to PATH=/usr/bin:/bin. If the command you are executing is not present
in the cron-specified path, you can either use the absolute path to the command or change the cron
PATH variable. You can’t implicitly append PATH as you would do with a regular script.
• The default shell is set to /bin/sh. To change to a different shell, use the SHELL variable.
• Cron invokes the command from the user’s home directory. The HOME variable can be set in the
crontab.
12
3 PRACTICES
3 Practices
In this section, we work on step by step building up a multi-task framework.
#d e f i n e GNU SOURCE
#include <l i n u x / s c h e d . h>
#include <s y s / s y s c a l l . h> /∗ D e f i n i t i o n o f SYS ∗ c o n s t a n t s ∗/
#include <u n i s t d . h>
#d e f i n e INFO
#d e f i n e WORK THREAD
sigset t set ;
int s ;
s i g e m p t y s e t (& s e t ) ;
s i g a d d s e t (& s e t , SIGQUIT ) ;
s i g a d d s e t (& s e t , SIGUSR1 ) ;
s i g p r o c m a s k ( SIG BLOCK , &s e t , NULL ) ;
/∗ S t a c k g r o w down - s t a r t a t t o p ∗/
void ∗ s t a c k t o p = c h i l d s t a c k + STACK SIZE ;
w r k i d t i d [ i ] = c l o n e (& bk w r k w o rk e r , s t a c k t o p ,
CLONE VM| CLONE FILES ,
( void ∗ ) &i ) ;
#i f d e f INFO
f p r i n t f ( s t d e r r , ” b k w r k c r e a t e w o r k e r g o t w o r k e r %u\n” , wrkid tid [ i ] ) ;
#e n d i f
usleep (100);
#e l s e
int bkwrk create worker ( )
{
unsigned i n t i ;
sigset t set ;
int s ;
s i g e m p t y s e t (& s e t ) ;
s i g a d d s e t (& s e t , SIGQUIT ) ;
s i g a d d s e t (& s e t , SIGUSR1 ) ;
s i g p r o c m a s k ( SIG BLOCK , &s e t , NULL ) ;
/∗ S t a c k g r o w down - s t a r t a t t o p ∗/
void ∗ s t a c k t o p = c h i l d s t a c k + STACK SIZE ;
w r k i d t i d [ i ] = c l o n e (& bk w r k w o rk e r , s t a c k t o p ,
CLONE VM| CLONE FILES ,
( void ∗ ) &i ) ;
#i f d e f INFO
f p r i n t f ( s t d e r r , ” b k w r k c r e a t e w o r k e r g o t w o r k e r %u\n” , wrkid tid [ i ] ) ;
#e n d i f
13
3.1 Multitasking framework illustration BK TPool 3 PRACTICES
usleep (100);
#e l s e
Step 3.1.1 Create resoruce instance using thread or process technique. The two kinds of instance can
be initialized using the system call clone() or the wrapped library function fork() and pthread create().
Step 3.1.2 Set up the control signal masking with allowance of the two signal SIGQUIT or SIGUSR1.
int b k w r k g e t w o r k e r ( )
{
w r k i d b u s y [ 1 ] != 0 ;
return 1 ;
/∗ TODO Implement t h e s c h e d u l e r t o s e l e c t t h e r e s o u r c e e n t i t y ∗/
}
3.1.3 Dispatcher
struct b k t a s k t ∗ t s k = b k t a s k g e t b y i d ( b k t a s k i d ) ;
i f ( t s k == NULL)
return - 1 ;
/∗ A d v e r t i s e I AM WORKING ∗/
w r k i d b u s y [ wrkid ] = 1 ;
14
3.1 Multitasking framework illustration BK TPool 3 PRACTICES
/∗ I n v a l i d t a s k ∗/
i f ( worker [ wrkid ] . f u n c == NULL)
return - 1 ;
#i f d e f DEBUG
f p r i n t f ( s t d e r r , ” brkwrk d i s p a t c h wrkid %d - send s i g n a l %u \n” , wrkid , t i d ) ;
#endif
s y s c a l l ( S Y S t k i l l , t i d , SIG DISPATCH ) ;
#e l s e
/∗ TODO: Implement f o r k v e r s i o n t o s i g n a l worker p r o c e s s h e r e ∗/
#endif
}
#define MAXWORKER 10
/∗ Task ID i s u n i q u e non - d e c r e a s i n g i n t e g e r ∗/
int t a s k i d s e e d ;
int w r k i d t i d [MAXWORKER] ;
15
3.1 Multitasking framework illustration BK TPool 3 PRACTICES
int w r k i d b u s y [MAXWORKER] ;
int w r k i d c u r ;
struct b k t a s k t {
void ( ∗ f u n c ) ( void ∗ a r g ) ;
void ∗ a r g ;
unsigned int b k t a s k i d ;
struct b k t a s k t ∗ t n e x t ;
} ∗ b k ta s k ;
int b k t a s k s z ;
struct b k w o r k e r t {
void ( ∗ f u n c ) ( void ∗ a r g ) ;
void ∗ a r g ;
unsigned int wrkid ;
unsigned int b k t a s k i d ;
};
/∗
∗ From b k t p o o l . c
∗/
#include ” b k t p o o l . h”
int b k t p o o l i n i t ( )
{
return b k w r k c r e a t e w o r k e r ( ) ;
}
Resource worker Take a loop of waiting for incoming control signal and do its job. After finishing the
task work, it backs to waiting state to catch the next event.
16
3.1 Multitasking framework illustration BK TPool 3 PRACTICES
s i g e m p t y s e t (& s e t ) ;
s i g a d d s e t (& s e t , SIGUSR1 ) ;
s i g a d d s e t (& s e t , SIGQUIT ) ;
#i f d e f DEBUG
f p r i n t f ( s t d e r r , ” worker %i s t a r t l i v i n g t i d %d \n” , i , g e t p i d ( ) ) ;
fflush ( stderr );
#endif
while ( 1 )
{
/∗ w a i t f o r s i g n a l ∗/
s = s i g w a i t (& s e t , &s i g ) ;
i f ( s != 0 )
continue ;
#i f d e f INFO
f p r i n t f ( s t d e r r , ” worker wake %d up\n” , i ) ;
#endif
/∗ Busy running ∗/
i f ( wrk ->f u n c != NULL)
wrk ->f u n c ( wrk ->a r g ) ;
/∗ A d v e r t i s e I DONE WORKING ∗/
wrkid busy [ i ] = 0 ;
worker [ i ] . f u n c = NULL;
worker [ i ] . a r g = NULL;
worker [ i ] . b k t a s k i d = - 1 ;
}
}
17
3.2 Practice with CronTab 3 PRACTICES
s i g a d d s e t (& s e t , SIGQUIT ) ;
#i f d e f DEBUG
f p r i n t f ( s t d e r r , ” worker %i s t a r t l i v i n g t i d %d \n” , i , g e t p i d ( ) ) ;
fflush ( stderr );
#endif
while ( 1 )
{
/∗ w a i t f o r s i g n a l ∗/
s = s i g w a i t (& s e t , &s i g ) ;
i f ( s != 0 )
continue ;
#i f d e f INFO
f p r i n t f ( s t d e r r , ” worker wake %d up\n” , i ) ;
#endif
/∗ Busy running ∗/
i f ( wrk ->f u n c != NULL)
wrk ->f u n c ( wrk ->a r g ) ;
/∗ A d v e r t i s e I DONE WORKING ∗/
wrkid busy [ i ] = 0 ;
worker [ i ] . f u n c = NULL;
worker [ i ] . a r g = NULL;
worker [ i ] . b k t a s k i d = - 1 ;
}
}
Don’t forget to make the script executable by using the chmod command. Then we define our job in
the CronTab. To open the crontab configuration file for the current user, enter the following command:
$ crontab - e
We can add any number of scheduled tasks, one per line. In this case, we want to make our job run
every minute, so we will add the following command (please change the user of the absolute path to your
Linux username):
18
3.2 Practice with CronTab 3 PRACTICES
Wait for some minutes and verify our cron job by checking the content of our output file:
$ cat date - out . txt
Practice
19
4 EXERCISE
4 Exercise
PROBLEM 1 Implement the FIFO scheduler policy to bkwrk get worker() in section 3.1.2.
$ . / mypool
b k w r k c r e a t e w o r k e r g o t worker 7593
b k w r k c r e a t e w o r k e r g o t worker 7594
b k w r k c r e a t e w o r k e r g o t worker 7595
b k w r k c r e a t e w o r k e r g o t worker 7596
b k w r k c r e a t e w o r k e r g o t worker 7597
b k w r k c r e a t e w o r k e r g o t worker 7598
b k w r k c r e a t e w o r k e r g o t worker 7599
b k w r k c r e a t e w o r k e r g o t worker 7600
b k w r k c r e a t e w o r k e r g o t worker 7601
b k w r k c r e a t e w o r k e r g o t worker 7602
A s s i g n t s k 0 wrk 0
worker wake 0 up
Task f u n c - H e l l o from 1
A s s i g n t s k 1 wrk 0 >>>>>>>>>> A c t i v a t e a s y n c h r o n o u s l y
A s s i g n t s k 2 wrk 1 >>>>>>>>>> A c t i v a t e a s y n c h r o n o u s l y
worker wake 0 up
Task f u n c - H e l l o from 2
worker wake 1 up
Task f u n c - H e l l o from 5
PROBLEM 2 In section 3.1.1 You are provided a thread based implementation of task worker in the
function bkwrk create worker(). Try to implement another version of the worker using more common
fork() API.
PROBLEM 3 Base on the provided material of multi-task programming and signal control, develop
your own framework of Fork-Join in theory.
20
Revision History 4 EXERCISE
Revision History
21