In the post "Creating an ioctl command in linux " we saw the basics of ioctl, and how we can create our own ioctl commands. The functions used to create ioctls have undergone a change from the kernel version 2.6.39,and the previous functions are no longer valid.
Before 2.6.39, the ioctl calls would lock the BKL (Big kernel lock) and then execute the required functions. This was unnecessary with the new fine grained locking available in the kernel. Thus to improve the implementation of ioctl, a new operation called unlocked_ioctl was introduced and all the existing ioctls were migrated to this new implementation.
Thus stating 2.6.39 the older implementation is no longer available.
The changes required in implementation of the ioctl are.
The function in the driver has changed from
The inode is no longer passed as an argument.
The fops uses the name unlocked_ioctl
The basic working of ioctl remains same.
Here is a code that implements the above mentioned changes if the kernel version is more than 2.6.39, else uses the older interface.
Here is a simple script we can use to find the mac address of the network card in our systems.
We will use the command ifconfig to find the mac address and in some distribution ifconfig is available only to the root hence we make use of "sudo" before ifconfig.
The following is a C program to find out the maximum length allowed for a host name in the system
We can make use of the function sysconf and pass the argument _SC_HOST_NAME_MAX
We need the header file unistd.h to use sysconf.
Save the program as get_max_hostname.c. Compile and execute the code.
The following is a C program to find out the number of processors configured on a system.
We can make use of the function sysconf and pass the argument _SC_NPROCESSORS_CONF.
We need the header file unistd.h to use sysconf.
Save the program as get_processors.c. Compile and execute the code.
Here are three ways in which we can get the path to the current working directory using a c program,
1. we can make use of the function "getcwd".
Header file required : unistd.h
The syntax of getcwd is
buf: Is the character pointer in which the path of current working directory is stored.
size: Is the maximum size of the path in bytes, if the size exceeds this then a NULL is returned
Here is a program that shows the usage of getcwd.
Save the program is get_cwd.c. Compile and execute it.
Header file required : unistd.h
The function returns the absolute path to the current working directory. The function itself mallocs for an array big enough to hold the current directory name, thus we don't need to do malloc in the program. This function returns the value of the environment variable PWD, thus if it is not set the function might fail to return the current value.
Here is a program which uses get_current_dir_name to get the current working directory.
Save the file as get_current_dir.c. Compile and execute it.
3. The third way of getting the current working directory is using the command "pwd" along with the function "system". The system function executes which ever command is passed to it and prints the result on the screen.
Thus we can execute the command system and pass the command "pwd" as the argument, the result of which will be the current working directory being printed on the screen.
The following program shows how the same can be implemented.
Save the file as get_system_pwd.c. Compile and execute the same.
Generating random numbers is common recruitment in number of scripts. bash by default gives a variable $RANDOM which when accessed gives a random number between 0 and 32767.
There might be situations where we might need random numbers between a range of smaller numbers or between zero and a smaller number than 32767. Here is a script which can be used to generate random numbers between any range of numbers.
It takes as input the lower limit and the upper limit of the random numbers required and then generates the required number of random numbers with in the range.
In the post we saw how we can use mutex to prevent simultaneous usage of the same resource by multiple threads.
But usage of mutexes have to be done very carefully to make sure that the threads don't end up in a dead lock.
A deadlock is a scenario when one thread is waiting for a resource which is held by the second thread, while the second thread is waiting for a resource held by the first thread. Thus causing both the threads to wait for each other infinitely.
To show how this situation might occur, in the following example we have used two mutexes,read_mutex and write_mutex. To gain access to the file both these mutexes have to be locked. In the code, the write thread locks write_mutex and then after a little delay tries to locks read_mutex.
The read thread on the other hand locks read_mutex first and then tries to lock write_mutex.
Thus by the time the write tries to access read_mutex, it has already been locked by read thread and by the time read thread tries to lock write_mutex, it has already been locked by the write thread. Thus both the threads end up waiting infinitely for each other to unlock the mutexes and process ends up in a deadlock.
Save the file as mutex_deadlock.c, and compile it by passing "-lpthread" flag.
There will be no output as both the threads endup in a deadlock state, to get out of the execution use "cntrl + c".
To avoid such simple deadlocks the easiest method is to make sure that all the threads access the locks in a specific order. In the above example if it is made compulsory that every thread should lock write_mutex first and then try to lock read_mutex, then the deadlock situation will not occur as only one thread will get access to write_mutex first and the same thread will be able to access read_mutex too.
The above code modified to avoid deadlock is shown below. Note that the order of acquiring lock by both the threads is the same, thus able to prevent deadlock.
Save the code as mutex_nodeadlock.c, compile it using "-lpthread" flag.
Thus we can successfully avoid a potential deadlock situation, by making use of the rules order of locks.
pthreads are used to split a process into multiple threads and execute them concurrently. The threads should
be independent of each other as far as possible, but at times the threads could be dependent on each other and they might be working on the same data.
Let us say we want to crate two threads,one to read from a file and the other to write into the same file. It is obvious that we can not read from a file unless we don't write into it, and at any given time the file should be allowed to be accessed by only one of the two threads. That is while it is being written it should not be allowed to be read and while it is being read, it should not be opened for write.
The following program implements the above mentioned two threads, but does not do any thing to synchronize the actions of the two threads.
Save the adove file as pthread_file.c. Compile it using "-lpthread" falg
We get a segmentation fault every time we execute the above program. This is because, the read thread tries to access the file which is being created by thread1 "write" and thus is still not available. When read thread accesses the file it still has not been created and thus we get a segmentation fault.
The part of the program in which multiple threads try to get access to the same resource, in this case the file, is termed as the critical section and ideally a critical section should be executed by only one thread at a any given time.
To prevent the access of the file by multiple threads at the same time we can make use of a mutex. Mutex stands for mutual exclution and as the name implies it keeps the threads mutually exclusive.
Access to the critical section is controlled by locking the mutex. That is whichever process locks the mutex first will be allowed to enter the critical section first and the other process can not enter the critical section unless the mutex is not unlocked by the first process.
Applying this to above example, both read and write threads will have to get a lock on a common mutex before getting access to the file. If we can make sure that the write thread always gets the access to the lock first then, the read thread will have to wait for the write thread to finish its operations on the file and unlock the mutex,before it can read it. Thus making sure that the segmentation fault never ocurrs.
To implement a mutex in pthreads we have to use a datatype of type pthread_mutex_t.
To lock the mutex we use the function pthread_mutex_lock(Address of mutex variable)
To unlock the mutex we use the functions pthread_mutex_unlock(address of mutex variable)
The implementation is shown in the code below.
save the code as pthread_mutex.c and compile by passing the "-lpthread" flag and execute it.
Every thread created using pthread_create gets assigned a uniue thread id, with which it is recognized.
Note: Refer to creation of threads using pthreads in the post " "
The parent gets to know the thread id after the pthread_create is executed sucessfully, but while executing the thread if we want to access the thread id we have to use the function pthread_self.
The function pthread_self does not take any arguments, and returns the thread id, which is of kind pthread_t.
In the following program we are creating a thread which executes the function "hello". In the function "hello" we have used pthread_self to find out the thread id and then printed the same. Note that pthread_t is an unsigned long data type and hence we have to use %u while printing using printf.
Save the file as self_pthread.c
Compile it using gcc by passing the "-lpthread" flag.
We can see that the thread_id printed by the main function, parent, and the thread are the same, indicating that
the value returned by pthread_self is the correct value.
The above error is a common error encountered by a number of people who begin writing programs using pthreads.
The POSIX libraries required for pthread functions are not linked by the compiler unless we don't ask or it to be linked. Thus we see the above error.
The simple workaround is to pass the option "-lp" to the compiler while compiling the code.
Here is a script that,when executed, will draw a christmas tree using the characters choosen by the user on the linux terminal.
The script will prompt the user to enter the character using which the tree has to be drawn. Then it will prompt the user to enter two characters that will be used to decorate the tree. The last input it will ask for is the character using which the base of the tree has to be drawn.
The following script will create a blank triangle of characters on the linux terminal, but unlike the script in "" the triangle will be empty, i.e. only the outline has the characters chosen by the user and inside is left blank.
In the post " " we saw how we can use the command factor to find whether a number is prime of not. We can extend the same script further to generate all the prime numbers in a given range of numbers.
To generate a range of numbers we can use the command "seq" . The usage of seq is shown in the post " ".
We can use seq in a for loop to iterate over one number at time.
Save the script as seq_for.sh, give it execute permissions and run the script.
Thus we can see that using seq along with for loop we can work on a range of numbers, one number at a time.
This script can be combined with the script in " " to generate all the prime numbers in a range of numbers.
We request the user to enter two numbers to indicate the lower and upper limits of the range of numbers between which the user wants to generate the prime numbers. The lower limit can not be 1 because the number 1 does not have any factors and the command "factor" does not return any thing for 1. Thus we need to make sure the user enters a number bigger than 1.
If the user enters 1, then we will prompt the user again to enter number greater than 1.
Then we pass these two numbers to seq in a for loop
In each iteration of the for loop we use the factor command to find out if a number is prime or not.
The full script looks as below.
Save the script as range_prime.sh,give it execute permissions and run it.
Thus we can see the script is able to generate a list of all the prime numbers between 2 and 20.
The command "factor" takes as input any integer number and returns the prime factors of the that number.
We can use this command to find wheter a given number is prime or not. If we pass a prime number as argument to the command factor, it returns the number itself as its prime factor. As shown above for the number 131.
We can pipe this output to grep,search for the number passed to factor in the output. If the output is comprised only of the input number then the given number is prime.
The following script does the same
Save the above script as prime.sh, and give it execute permissions