Linux kernel allows modules stacking, which basically means one module can use the symbols defined in other modules. But this is possible only
when the symbols are exported.
In this post let us see how can a module export a symbol and how another module can make use of it.
A symbol can be exported by a module using the macro EXPORT_SYMBOL().
Let us make use of the very basic hello world module. In this module we have added function called "hello_export" and used the EXPORT_SYMBOL macro to export this function.
hello_export.c
Makefile required to compile this module is
Makefile
Compile it using the "make" command and then insert it into the kernel using insmod
All the symbols that the kernel is aware of is listed in /proc/kallsyms. Let us search for our symbol in this file.
From the output we can see that the symbol we exported is listed in the symbols recognized by the kernel. The first column gives the address of the column and the last column the module to which the symbol belongs to.
If you look into the Module.symvers file in directory where the module was compiled you will see a line similar to the following
Now let us write another module which will make use of the exported symbol. To make use of the symbol we just have to inform the module that the symbols being used is defined externally by using the "extern" keyword. Thus to use the hello_export function we will have to use
Once this is done we can use the function any where in the module, as shown in the module below.
hello_use_export.c
Use the same Makefile as shown above only change the module name to hello_use_export.o
Compile and load as done before.
If the function has got called successfully we should see the message "Hello from another module" in the kernel logs.
Thus we could call the function defined in another module successfully once it was exported by the module.
The dependecy of hello_use_export on hello_export can be found using the lsmod command
We know the modprobe command can load the module that is passed to it as well as the dependent modules, hence we can also see the working of modprobe using these modules.
Copy the two .ko files, hello_export.ko and hello_use_export.ko to /lib/modules/`uname -r`/
To use modprobe we have to update the dependencies in the modules.dep file in /lib/modules/`uname -r`/modules.dep . This can be done using the
command depmod.
The output "hello_use_export.ko: hello_export.ko" signifies that hello_use_export is dependent on hello_export.
Now remove the two modules we inserted before
Note: You will not be able to remove the modules in the reverse order cause hello_use_export will be using hello_export. Hence unless hello_use_export is not removed, hello_export can not be removed.
Now use the modprobe command to load hello_use_export, and we will see that hello_export gets loaded automatically.
We can see that even though we did not load the module "hello_export" it got loaded automatically because "hello_use_export" was dependent on it.
Search
Usage of printk_ratelimit()
printk is used in kernel programming to print,logs, messages, errors etc as we can not access the usual printf of the user space. The general syntax of prtink is
printk(
The various Log levels and their meanings are listed in the file linux/kernel.h
While programming we can use a huge number of printk statements to debug or to track the flow of the code. But what if we want to control the logging to a certain limit to make sure that the logs don't get filled with messages.
For eg: on an error a module might repeatedly print error message every second filling up the logs with the same error.
To handle such situations and control the amount pf logging we can use the printk_ratelimit function.
The kernel by default defines a limit of how many messages will it print before it stops printing for a while. The limit on the number of messages is set in
/proc/sys/kernel/printk_ratelimit_burst.
After the above mentioned number of prints, kernel would stop printing for a predefined number of seconds which is set in the file
/proc/sys/kerne/printk_ratelimit.
To use this rate limit feature of printk we have to use the function printk_ratelimit(). The function returns true as long as the limit of number of messages printed does not excedd the limit set. Once the limit exceeds the functions starts retuning "0" .
Hence using this function with in a "if" condition we can limit the printing of our module .
if(printk_ratelimit())
printk(
This is depicted in the example module below. The values of the two proc entries are as follows
$ cat /proc/sys/kernel/printk_ratelimit_burst
10
$ cat /proc/sys/kernel/printk_ratelimit
5
In the module below we will try to print 20 messages continously. As see above , the limit set in the proc entry is for 10 messages. So we should be able to see only the first 10 prints of the 20 prints we are attempting.
****************************rate_limit.c********************************************
#include
#include
int rate_limit_init(void) {
int i;
unsigned long j0,j1;
j0 = jiffies;
j1 = jiffies + 30*HZ;
for(i=0;i<20;i++) {
if(printk_ratelimit()) {
printk(KERN_INFO"Printing %d", i);
}
}
return 0;
}
void rate_limit_exit(void){
printk(KERN_INFO "Done");
}
module_init(rate_limit_init);
module_exit(rate_limit_exit);
******************************************************************************************
Use the following makefile to compile the module.
******************************Makefile***************************************************
ifneq ($(KERNELRELEASE),)
obj-m := rate_limit.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
endif
*******************************************************************************************
Once compiled load it using insmod.
$insmod rate_limit.ko
$dmesg | tail -10[ 6886.360547] __ratelimit: 10 callbacks suppressed
[ 6886.360555] Printing 0
[ 6886.360559] Printing 1
[ 6886.360564] Printing 2
[ 6886.360567] Printing 3
[ 6886.360570] Printing 4
[ 6886.360574] Printing 5
[ 6886.360577] Printing 6
[ 6886.360580] Printing 7
[ 6886.360584] Printing 8
[ 6886.360587] Printing 9
The first line in the output says that 10 call backs were suppressed. So out of the 20 prints we tried only 10 successed and the other 10 were suppressed by the kernel because we used the function printk_ratelimit().
Now let us modify the code a little, and add a delay after the first failure to print i.e when we exceed the limit number of prints.
The wait time mentioned in proc entry is 5, so if we wait for 5 or more seconds we should see our prints again appear in the logs .
*********************************rate_limit_wait.c****************************************************************
#include
#include
#include
int rate_limit_init(void) {
int i;
unsigned long j0,j1;
j0 = jiffies;
j1 = jiffies + 30*HZ; // A wait for approximately 30 seconds
for(i=0;i<20;i++) {
if(printk_ratelimit()) {
printk(KERN_INFO"Printing %d", i);
}
else {
while(time_before(jiffies,j1));
}
}
return 0;
}
void rate_limit_exit(void){
}
module_init(rate_limit_init);
module_exit(rate_limit_exit);
*********************************************************************************************************************
load the module using insmod
$insmod rate_limit.ko
$dmesg |tail -20
[15438.590395] Printing 0
[15438.590399] Printing 1
[15438.590403] Printing 2
[15438.590406] Printing 3
[15438.590410] Printing 4
[15438.590413] Printing 5
[15438.590416] Printing 6
[15438.590420] Printing 7
[15438.590423] Printing 8
[15438.590426] Printing 9
[15468.588021] __ratelimit: 1 callbacks suppressed
[15468.588029] Printing 11
[15468.588033] Printing 12
[15468.588037] Printing 13
[15468.588040] Printing 14
[15468.588043] Printing 15
[15468.588047] Printing 16
[15468.588050] Printing 17
[15468.588054] Printing 18
[15468.588057] Printing 19
As seen in the output of dmesg, after a delay of some seconds the printing regains again only one print has been missed which was right after the first 10
prints. Because of the delay introduced after reaching the limit, the prints after 10th print have also appeared in the logs.
Errors while compiling custom kernel and workarounds
These are the few errors that I encountered while compiling a custom kernel(2.6.32 on Debian 6.0), and the workarounds that helped.
1.make-kpkg fails to generate initrd image.
You will have to copy initramfs from the examples in the kernel, i.e.
cp -a /usr/share/doc/kernel-package/examples/etc/kernel/postinst.d/initramfs /etc/kernel/postinst.d
2. mount: mounting /dev/disk/by-uuid/
To get around thing edit the grub entry and change the line
root=uuid=
to
root=/dev/sdXY where X,Y are the paritions of your disk it could be /dev/sda1 or /dev/sdb1 etc... You can use gparted to find this out.
3. Ext3-Fs :sda1 couldn't mount because of unsupporte features.(204)
The cause of the error might be that your disk has ext4 filesystem and while compiling the kernel you have not enabled ext4 in the new kernel
Edit the .config file and set CONFIG_EXT4 to "y".
Now recomile the kernel and try booting again.
error while Installing kdb: traps.c:418: error: expected identifier or ‘(’ before ‘if’
While installing the kernel debugger(KDB) patches in Linux 2.6.32 you might encounter a few errors. Here are the work around.
To start with the installation you can follow the steps listed in
http://www.ibm.com/developerworks/linux/library/l-kdbug/
Once the patches are applied successfully, you will need to recompile the kernel. But make sure you enable the kernel debugger by setting the option
CONFIG_KDB=y
On running make The following are the errors you might encounter
1. arch/x86/kernel/traps.c:418: error: expected identifier or ‘(’ before ‘if’
The problem is with a brace in the traps.c file. at the line 415, which is an extra brace. So remove that brace.
2. CC drivers/usb/host/ehci-hcd.o
In file included from drivers/usb/host/ehci-hcd.c:312:
drivers/usb/host/ehci-q.c: In function ‘qh_completions_kdb’:
drivers/usb/host/ehci-q.c:701: error: ‘struct ehci_qh’ has no member named ‘hw_current’
This error is because the struct ehci_qh does not contain hw_current any more, it is present in a structure ehci_qh_hw . ehci_qh has a member
ehci_qh_hw *hw. Thus we need to use this "hw" pointer to get access to hw_current. So in the line 701 of the file drivers/usb/host/ehci-q.c
change
qh->hw_current
to
qh->hw->hw_current
3. CC drivers/usb/host/ehci-hcd.o
In file included from drivers/usb/host/ehci-hcd.c:312:
drivers/usb/host/ehci-q.c: In function ‘qh_completions_kdb’:
drivers/usb/host/ehci-q.c:702: error: ‘struct ehci_qh’ has no member named ‘hw_token’
The member hw_token has also been moved to the structure ehci_qh_hw hence in the lines of the file drivers/usb/host/ehci-q.c 702, 708 and 710 change
qh->hw_token
to
qh->hw->hw_token
4. drivers/usb/host/ehci-q.c: In function ‘qh_completions_kdb’:
drivers/usb/host/ehci-q.c:765: error: ‘struct ehci_qh’ has no member named ‘hw_qtd_next’
drivers/usb/host/ehci-q.c:765: error: ‘struct ehci_qh’ has no member named ‘hw_info2’
Both these members are present in the structure ehci_qh_hw hence change in the lines of the file drivers/usb/host/ehci-q.c 765 and 775 change
qh->hw_qtd_next
to
qh->hw->hw_qtd_next
and
qh->hw_info2
to
qh->hw->hw_info2
5. drivers/usb/host/ehci-q.c:776: error: implicit declaration of function ‘intr_deschedule’
The functions intr_deschedule has been declared in ehci-sched.c but we need to inform ehci-q.c about it so add this line at the top of
the file drivers/usb/host/ehci-q.c
extern void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
and from the file drivers/usb/host/ehci-sched.c remove the static before the declaration of intr_deschedule. (line 628).
Once the above 5 changes are done, your kernel should compile with out any errors.
Wrapping lines in a text file to specific width.
fold: Formatting a text file to wrap the lines to specific number of columns.
In case you have a text file that have very long sentences that span long column lengths and you want to wrap the length to specific number of columns then you can make use of the command fold.
For eg let us assume we have a file named one
one:
This is line is very long and we need to truncate it to lesser number of columns.
The above line approximately spans for around 74 columns. Let us try to wrap it to 50 columns.
$ fold -w 50 one
This is line is very long and we need to truncate
it to lesser number of columns.
The number that we pass after the -w option is the number of columns after which the columns will truncate to.
It is possible that the number of columns specified might split a word in between.
For eg in the above example if we use 45 instead of 50 the word "truncate" will get split in between.
$ fold -w 45 one
This is line is very long and we need to tru
ncate it to lesser number of columns.
To avoid such spliting we can add an option -s , which truncates at the first space before the column width mentioned.
For eg:
$fold -s -w 45 one
This is line is very long and we need to
truncate it to lesser number of columns.
In the above example we see that with "-s" option the line gets wrapped at the space before the word "truncated".
Happy folding :-)
In case you have a text file that have very long sentences that span long column lengths and you want to wrap the length to specific number of columns then you can make use of the command fold.
For eg let us assume we have a file named one
one:
This is line is very long and we need to truncate it to lesser number of columns.
The above line approximately spans for around 74 columns. Let us try to wrap it to 50 columns.
$ fold -w 50 one
This is line is very long and we need to truncate
it to lesser number of columns.
The number that we pass after the -w option is the number of columns after which the columns will truncate to.
It is possible that the number of columns specified might split a word in between.
For eg in the above example if we use 45 instead of 50 the word "truncate" will get split in between.
$ fold -w 45 one
This is line is very long and we need to tru
ncate it to lesser number of columns.
To avoid such spliting we can add an option -s , which truncates at the first space before the column width mentioned.
For eg:
$fold -s -w 45 one
This is line is very long and we need to
truncate it to lesser number of columns.
In the above example we see that with "-s" option the line gets wrapped at the space before the word "truncated".
Happy folding :-)
Making a script speak.
espeak: Speech synthesiser.
If you ever wanted your script to speak out words or messages, here is a command that will come handy, "espeak".
"espeak " will speak out any english word or sentence you give as input. It supports a few other languages too.
Eg:
Open a terminal and type
$ espeak "hello"
If your speaker is turned on, you should hear a digial voice speak hello to you. This could be used to make scripts
very user friendly and interestingly inetractive.
The speed, pitch and amplitude of the voice can be changed by options -s,-p and -a respectively.
For eg:
Save the following as speak.sh
**********speak.sh***********
espeak -s 20 "hello"
espeak -a 30 -p 5 "welcome"
espeak -s 100 "Have a great day"
******************************
Now run the script from the terminal
$ sh speak.sh
you should hear the three sentences being spoken at different speeds and amplitudes. Change the numbers being passed to the options
and see the different voices that you can generate.
If you do not have the package installed you can get it from
http://espeak.sourceforge.net/
Go ahead, let your scripts do the talking :-)
Comparing two files word by word
wdiff: Utility to comapre two files word by word.
When comapring two files, the usual diff command compares line by line, but if we wanted the comparision to happen word by word then diff command would not be helpful.
The wdiff command will pick up the exact words that do not match between the lines.
wdiff is not present by default and needs to be installed. Run the following command to install wdiff package.
sudo apt-get install wdiff
or you can select wdiff from the synaptic package manager.
Let us take two files
one:
This is the first file
and
two:
This is the second file
If we run the command diff on these two files
$ diff one two
1c1
< This is the first file
---
> This is the second file
Note:The output of diff is explained in the post "Comparing files using diff"
The above output does not tell us which are the mismatching words . Let us try wdiff and see the output
$ wdiff one two
This is the [-first-] {+second+} file
In the output braces are put around the differing words. In the above example words [-first-], {+second+} are put in braces. The words with square braces of the kind "[" are the words of the first file and the words with curly braces of the kind "{" belong to the second file.
The "-" around the first set of words signify that if these set of words are removed from the first file and the second set of words with "+" around them are added to it, we will get the second file.
If there are multiple lines in the file the differing words in each line is printed out loine by line.
if we pass the option -3 to wdiff it will output only the differing words instead of the whole lines
$wdiff -3 one two
============================================================
[-first line-] {+second+}
============================================================
Comparing 3 files
diff and diff3 : Both are commands for comparing files and showing the differences.
The diff command is used to compare two files and list out the lines that are different between the files.
For Eg:
If we have tow files "one" and "two" having contents as follows
"one" :
This
is the
first
file
"two" :
This
is the
second
file
$ diff one two
3c3
< first
---
> second
The 3c3 signifies the line numbers in which the files differ. The set of numbers before c is for the first file, and the numbers after c specifies the line numbers in the second file.
The lines printed out are the lines that do not match. In the output, the line that begins with "<" belongs to the first file and the line that starts with ">" belongs to the second file and these are separated by "---".
In case the number of files that you want to compare are 3 then diff would not be able to do it.
To compare 3 files we can use diff3 command.
Let us say we have another file named "three"
three:
This
is the
third
file.
$diff3 one two three
1:3c
first
2:3c
second
3:3c
third
The output looks a little better structured than diff which has the following format.
"file number": Differing line numbers
Differing lines
Wonder what command to use to compare 4 files :-)
The diff command is used to compare two files and list out the lines that are different between the files.
For Eg:
If we have tow files "one" and "two" having contents as follows
"one" :
This
is the
first
file
"two" :
This
is the
second
file
$ diff one two
3c3
< first
---
> second
The 3c3 signifies the line numbers in which the files differ. The set of numbers before c is for the first file, and the numbers after c specifies the line numbers in the second file.
The lines printed out are the lines that do not match. In the output, the line that begins with "<" belongs to the first file and the line that starts with ">" belongs to the second file and these are separated by "---".
In case the number of files that you want to compare are 3 then diff would not be able to do it.
To compare 3 files we can use diff3 command.
Let us say we have another file named "three"
three:
This
is the
third
file.
$diff3 one two three
1:3c
first
2:3c
second
3:3c
third
The output looks a little better structured than diff which has the following format.
"file number": Differing line numbers
Differing lines
Wonder what command to use to compare 4 files :-)
Changing virtual terminal from command line
chvt: change vitrual terminal.
Linux is a multiuser operating system so multiple users can work on it parallely by logging in using different terminals. This is generally achieved by using the cntrl+(left)alt+Fn key where Fn is the function keys from 1-6. Thus So there can be 6 users working on these six terminals at the same time but only one of them will have the GUI.
In case you want to change between these terminals from the command line then you can use the command chvt.
chvt n
where n is the terminal number. For eg :
$ sudo chvt 1
is equivalent to cntrl+(left)alt+F1
Linux is a multiuser operating system so multiple users can work on it parallely by logging in using different terminals. This is generally achieved by using the cntrl+(left)alt+Fn key where Fn is the function keys from 1-6. Thus So there can be 6 users working on these six terminals at the same time but only one of them will have the GUI.
In case you want to change between these terminals from the command line then you can use the command chvt.
chvt n
where n is the terminal number. For eg :
$ sudo chvt 1
is equivalent to cntrl+(left)alt+F1
Command to save commands being run
Script :
The command script is very useful for students and faculty. It helps to save the commands and the output run on the terminal to a file, which can be submitted as an assignment by the students.
Working:
It can be started as follows.
$ script
Script started, file is typescript
$
The default file in which the commands are saved are "typescript", to create a output file by any other name use the -f option.
Any command that you run after this and its output will be saved in a file by the name typescript in the same folder where you ran the command script.
For eg if we run the following commands after running the script command.
$ ls
temp test file1 typescript
$ cat temp
Hello
$
To stop the script hit "cntrl + D" ( for Bash shell) or exit (for C shell).
Now look into the typescript file to see what it has saved
$ cat typescript
Script started on Wednesday 06 July 2011 04:58:13 PM IST
$ ls
temp test file1 typescript
$ cat temp
hello
$ exit
Script done on Wednesday 06 July 2011 05:05:32 PM IST
We see that the typescript command also gives the time of starting as well as ending of the script.
To save the output in a file in another file name start the script with the option "-f"
$ script -f output
Script started, file is output
$
As stated , the output will be saved in a file named "output".
You can also append the output to a previously existing file using the "-a" option.
Internally the command script forks another shell in which the commands are executed, and saved in the typescript file. When "cntrl+D" or exit is executed the sub shell gets killed and the command stops running.
In case just one command has to be executed and we do not want to launch another shell then we can use the option "-c"
$ script -c ls
This will put the command output into the typescript file and ends by itself.
So next time you want to save your terminal session you know what command to use. :)
The command script is very useful for students and faculty. It helps to save the commands and the output run on the terminal to a file, which can be submitted as an assignment by the students.
Working:
It can be started as follows.
$ script
Script started, file is typescript
$
The default file in which the commands are saved are "typescript", to create a output file by any other name use the -f option.
Any command that you run after this and its output will be saved in a file by the name typescript in the same folder where you ran the command script.
For eg if we run the following commands after running the script command.
$ ls
temp test file1 typescript
$ cat temp
Hello
$
To stop the script hit "cntrl + D" ( for Bash shell) or exit (for C shell).
Now look into the typescript file to see what it has saved
$ cat typescript
Script started on Wednesday 06 July 2011 04:58:13 PM IST
$ ls
temp test file1 typescript
$ cat temp
hello
$ exit
Script done on Wednesday 06 July 2011 05:05:32 PM IST
We see that the typescript command also gives the time of starting as well as ending of the script.
To save the output in a file in another file name start the script with the option "-f"
$ script -f output
Script started, file is output
$
As stated , the output will be saved in a file named "output".
You can also append the output to a previously existing file using the "-a" option.
Internally the command script forks another shell in which the commands are executed, and saved in the typescript file. When "cntrl+D" or exit is executed the sub shell gets killed and the command stops running.
In case just one command has to be executed and we do not want to launch another shell then we can use the option "-c"
$ script -c ls
This will put the command output into the typescript file and ends by itself.
So next time you want to save your terminal session you know what command to use. :)
Game of anagrams using perl
The game of anagrams using perl
The perl script below is for the game of anagram, i.e you will presented with a word with its letters jumbled and you have to guess the correct word.
The script by default uses the file /usr/share/dict/words, which has a list words of english.
Script explanation:
Variables :
$score = 0; To keep track of the score
$level = 5; To set the level
$file = "/usr/share/dict/words"; The default file to look into for words.
$max = 74000; Maximum number of words in the file being used.
Subroutines :
randomize :
This is the main subroutine that is the core of the game.
The file to be used is opened in read mode using
We will pick any random word from this file and shuffle it to generate the anagram. So for this we need a random integer number, which is generated using the rand function.
Where $max is the maximum number among random the numbers generated.
We will loop over the file incrementing a count on every word till count becomes equal to the random number.
The word at the specified count will have to be shuffled now. But before this we have look into the following points
1. The word is not a noun, hence we check if the first letter is capitalized /^[A-Z]/
2. The word is not of the kind her's , their's etc. We look for " ' " in the file using
index($_,"\'")
If this returns -1 then the word does not have a " ' ".
3. Make sure the number of letter in the word is as per the level set, i.e.
For easy number of letters is lesser than 5
For medium number of letter is lesser than 7
For hard number of letter is lesser than 10.
These three conditions are checked using
In case this if condition fails we generate a new random number and restart from the beginning of the file and
This is the else part
If the word is fine then the word will be read as a string, to shuffle the letters we will have to convert it to an array. This is done using split as follows.
To get the length of the string we use the function length () .
An array of flags is used to keep track of the letters that have been shuffled. The flag array is initialized to 0 using
Next we start a loop which runs as many times as the word length and in each iteration we select a random letter from the string again using the rand() function. This random letter is assigned to a new array called shuffled, whose index is incremented serially. Each time we select a letter from the array sting, we set the flag of the corresponding index to inform that the character at that index has been shuffled.
The above steps have been implemented in the following loop.
Once we have finished the above loop, there are chances that some characters might have been missed out as the characters were generated randomly. To account for this we loop over the array string again, but serially this time and check the flag corresponding to each index. If any of the flag is not set, we append that letter to the end of shuffled array.
This is done using the following loop.
Now that we have our shuffled word ready we will present it to the user, and ask the user to enter the answer.
The answer entered by the user is comapred with the original word, if its the correct answer then we increment the score and ask the user if he/she wants to continue playing. If the user enter the wrong answer the we ask the user to try again. If the user does not want to try again we will show the correct answer and continue to the next word.
set_level: This routine is for setting the level, it has three options of level
Easy, Medium and Hard. Depending on the selection, the variable level is set which is used in the randomize routine to set the number of letters.
set_file: The default file used to look for words is /usr/share/dict/words. In case we want to use some other file we can use this routine. We can enter the full path to the file which will be set to the variable "file".
We also have to set the variable "max" to the number of words in the file, which is done by looping over the file and incrementing a count on every word.
The file that we use should have only one word per line as we count one line a one word in the program.
Main menu :
print " Press: 1 to begin the game : Will call the randomize routine
2 to know about the game : Will give information about how to play and set levels etc
3 to select level : Will allow you to change the level by calling set_level routine.
4 to change the input file : Will allow you to change the input file using set_file.
5 to quit : Will exit the game.
Here is the full script, it has been tested on perl version 5.10 on linux.It might work in windows too but has not been tried.
Anagram.pl
Sample output
Hope you have fun... feel free to give any kind of feedback. :-)
The perl script below is for the game of anagram, i.e you will presented with a word with its letters jumbled and you have to guess the correct word.
The script by default uses the file /usr/share/dict/words, which has a list words of english.
Script explanation:
Variables :
$score = 0; To keep track of the score
$level = 5; To set the level
$file = "/usr/share/dict/words"; The default file to look into for words.
$max = 74000; Maximum number of words in the file being used.
Subroutines :
randomize :
This is the main subroutine that is the core of the game.
The file to be used is opened in read mode using
We will pick any random word from this file and shuffle it to generate the anagram. So for this we need a random integer number, which is generated using the rand function.
Where $max is the maximum number among random the numbers generated.
We will loop over the file incrementing a count on every word till count becomes equal to the random number.
The word at the specified count will have to be shuffled now. But before this we have look into the following points
1. The word is not a noun, hence we check if the first letter is capitalized /^[A-Z]/
2. The word is not of the kind her's , their's etc. We look for " ' " in the file using
index($_,"\'")
If this returns -1 then the word does not have a " ' ".
3. Make sure the number of letter in the word is as per the level set, i.e.
For easy number of letters is lesser than 5
For medium number of letter is lesser than 7
For hard number of letter is lesser than 10.
These three conditions are checked using
In case this if condition fails we generate a new random number and restart from the beginning of the file and
This is the else part
If the word is fine then the word will be read as a string, to shuffle the letters we will have to convert it to an array. This is done using split as follows.
To get the length of the string we use the function length () .
An array of flags is used to keep track of the letters that have been shuffled. The flag array is initialized to 0 using
Next we start a loop which runs as many times as the word length and in each iteration we select a random letter from the string again using the rand() function. This random letter is assigned to a new array called shuffled, whose index is incremented serially. Each time we select a letter from the array sting, we set the flag of the corresponding index to inform that the character at that index has been shuffled.
The above steps have been implemented in the following loop.
Once we have finished the above loop, there are chances that some characters might have been missed out as the characters were generated randomly. To account for this we loop over the array string again, but serially this time and check the flag corresponding to each index. If any of the flag is not set, we append that letter to the end of shuffled array.
This is done using the following loop.
Now that we have our shuffled word ready we will present it to the user, and ask the user to enter the answer.
The answer entered by the user is comapred with the original word, if its the correct answer then we increment the score and ask the user if he/she wants to continue playing. If the user enter the wrong answer the we ask the user to try again. If the user does not want to try again we will show the correct answer and continue to the next word.
set_level: This routine is for setting the level, it has three options of level
Easy, Medium and Hard. Depending on the selection, the variable level is set which is used in the randomize routine to set the number of letters.
set_file: The default file used to look for words is /usr/share/dict/words. In case we want to use some other file we can use this routine. We can enter the full path to the file which will be set to the variable "file".
We also have to set the variable "max" to the number of words in the file, which is done by looping over the file and incrementing a count on every word.
The file that we use should have only one word per line as we count one line a one word in the program.
Main menu :
print " Press: 1 to begin the game : Will call the randomize routine
2 to know about the game : Will give information about how to play and set levels etc
3 to select level : Will allow you to change the level by calling set_level routine.
4 to change the input file : Will allow you to change the input file using set_file.
5 to quit : Will exit the game.
Here is the full script, it has been tested on perl version 5.10 on linux.It might work in windows too but has not been tried.
Anagram.pl
Sample output
Hope you have fun... feel free to give any kind of feedback. :-)
Changing process state in a module
The example shows how we can change the state of a process.
Every process in linux has a task_struct for itself which stores all the relevant information about the process.
The possible states a process can have in linux are
Running or Runnable defined as TASK_RUNNING
Interruptible sleep defined as TASK_INTERRUPTIBLE
Uniterruptible sleep defined as TASK_UNINTERRUPTIBLE
Terminated task defined as TASK_STOPPED
(There are few more states that are not used often).
To look at the state of the task we can use the command
ps -eo state,comm
For eg : The ouput of the above command could be
S evince
S evinced
D gnome-terminal
S gnome-pty-helpe
S bash
R ps
The first column sigifies the state of the process where
S implies Interruptible Sleep
D implies Uninterruptible Sleep
R implies Running or Runnable.
T imples STOPPED
The second coulmn has the name of the process.
The module below creates a thread on inserting into the module kernel. The thread runs for a minute before terminating itself. The details how the thread gets created can be seen in "Kernel Threads" .
There are two proc entries that get created on inserting the module
suspend_state: On reading this proc entry the running thread's state is changed from running to Interruptible sleep
This is done by setting " thread1->state" to TASK_INTERRUPTIBLE. where thread1 is the task_struct of the thread that was created.
run_state: On reading this proc entry the thread that is in sleep state is woken up. This is done by calling wake_up_process() on thread1. Which reschedules the sleeping process.
You can read more about proc entry creation in "Creating proc entries" .
***************************process_change.c****************************************
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/semaphore.h>
#include <linux/kthread.h> // for threads
#include <linux/sched.h> // for task_struct
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/proc_fs.h>
/*char buffer[10];
int count;
struct semaphore sem;*/
static struct task_struct *thread1;
int thread_fn() {
unsigned long j0,j1;
int delay = 100*HZ;
j0 = jiffies;
j1 = j0 + delay;
while (time_before(jiffies, j1))
schedule();
printk(KERN_INFO "In thread1");
set_current_state(TASK_INTERRUPTIBLE);
while (!kthread_should_stop())
{
schedule();
set_current_state(TASK_INTERRUPTIBLE);
}
set_current_state(TASK_RUNNING);
return 0;
}
int suspendstate(char *buf,char **start,off_t offset,int count,int *eof,void *data)
{
printk(KERN_INFO "In suspend sate");
thread1->state = TASK_INTERRUPTIBLE;
return 0;
}
int runstate(char *buf,char **start,off_t offset,int count,int *eof,void *data)
{
printk(KERN_INFO "In runsate");
wake_up_process(thread1);
return 0;
}
int thread_init (void) {
char name[15]="process1";
printk(KERN_INFO "in init");
thread1 = kthread_create(thread_fn,NULL,name);
if((thread1))
{
printk(KERN_INFO "in if");
wake_up_process(thread1);
}
create_proc_read_entry("suspend_state",0,NULL,suspendstate,NULL);
create_proc_read_entry("run_state",0,NULL,runstate,NULL);
return 0;
}
void thread_cleanup(void) {
int ret;
ret = kthread_stop(thread1);
if(!ret)
printk(KERN_INFO "Thread stopped");
}
MODULE_LICENSE("GPL");
module_init(thread_init);
module_exit(thread_cleanup);
***************************************************************************************
***************************Makefile********************************************
ifneq ($(KERNELRELEASE),)
obj-m := process_change.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
*********************************************************************************
Save the above two files with the respective names and run the following commands to see the output.
$ make
$ sudo insmod process_change.ko
$ ps -eo state,comm | grep process1 R process1
The output shows process1 is currently running
$ cat /proc/suspend_state
$ ps -eo state,comm | grep process1 S process1
After read of the proc entry suspend_state the process state changed to S, i.e. sleep state. But note the thread runs approximately for a minute so you will have to execute the "cat" command within one minute to be able to see this change.
$ cat /proc/run_state.
$ ps -eo state,comm | grep process1
R process1
After read of proc entry run_state the process state has again changed to run state.
To remove the module
$ sudo rmmod process_change
Every process in linux has a task_struct for itself which stores all the relevant information about the process.
The possible states a process can have in linux are
Running or Runnable defined as TASK_RUNNING
Interruptible sleep defined as TASK_INTERRUPTIBLE
Uniterruptible sleep defined as TASK_UNINTERRUPTIBLE
Terminated task defined as TASK_STOPPED
(There are few more states that are not used often).
To look at the state of the task we can use the command
ps -eo state,comm
For eg : The ouput of the above command could be
S evince
S evinced
D gnome-terminal
S gnome-pty-helpe
S bash
R ps
The first column sigifies the state of the process where
S implies Interruptible Sleep
D implies Uninterruptible Sleep
R implies Running or Runnable.
T imples STOPPED
The second coulmn has the name of the process.
The module below creates a thread on inserting into the module kernel. The thread runs for a minute before terminating itself. The details how the thread gets created can be seen in "Kernel Threads" .
There are two proc entries that get created on inserting the module
suspend_state: On reading this proc entry the running thread's state is changed from running to Interruptible sleep
This is done by setting " thread1->state" to TASK_INTERRUPTIBLE. where thread1 is the task_struct of the thread that was created.
run_state: On reading this proc entry the thread that is in sleep state is woken up. This is done by calling wake_up_process() on thread1. Which reschedules the sleeping process.
You can read more about proc entry creation in "Creating proc entries" .
***************************process_change.c****************************************
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/semaphore.h>
#include <linux/kthread.h> // for threads
#include <linux/sched.h> // for task_struct
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/proc_fs.h>
/*char buffer[10];
int count;
struct semaphore sem;*/
static struct task_struct *thread1;
int thread_fn() {
unsigned long j0,j1;
int delay = 100*HZ;
j0 = jiffies;
j1 = j0 + delay;
while (time_before(jiffies, j1))
schedule();
printk(KERN_INFO "In thread1");
set_current_state(TASK_INTERRUPTIBLE);
while (!kthread_should_stop())
{
schedule();
set_current_state(TASK_INTERRUPTIBLE);
}
set_current_state(TASK_RUNNING);
return 0;
}
int suspendstate(char *buf,char **start,off_t offset,int count,int *eof,void *data)
{
printk(KERN_INFO "In suspend sate");
thread1->state = TASK_INTERRUPTIBLE;
return 0;
}
int runstate(char *buf,char **start,off_t offset,int count,int *eof,void *data)
{
printk(KERN_INFO "In runsate");
wake_up_process(thread1);
return 0;
}
int thread_init (void) {
char name[15]="process1";
printk(KERN_INFO "in init");
thread1 = kthread_create(thread_fn,NULL,name);
if((thread1))
{
printk(KERN_INFO "in if");
wake_up_process(thread1);
}
create_proc_read_entry("suspend_state",0,NULL,suspendstate,NULL);
create_proc_read_entry("run_state",0,NULL,runstate,NULL);
return 0;
}
void thread_cleanup(void) {
int ret;
ret = kthread_stop(thread1);
if(!ret)
printk(KERN_INFO "Thread stopped");
}
MODULE_LICENSE("GPL");
module_init(thread_init);
module_exit(thread_cleanup);
***************************************************************************************
***************************Makefile********************************************
ifneq ($(KERNELRELEASE),)
obj-m := process_change.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
*********************************************************************************
Save the above two files with the respective names and run the following commands to see the output.
$ make
$ sudo insmod process_change.ko
$ ps -eo state,comm | grep process1 R process1
The output shows process1 is currently running
$ cat /proc/suspend_state
$ ps -eo state,comm | grep process1 S process1
After read of the proc entry suspend_state the process state changed to S, i.e. sleep state. But note the thread runs approximately for a minute so you will have to execute the "cat" command within one minute to be able to see this change.
$ cat /proc/run_state.
$ ps -eo state,comm | grep process1
R process1
After read of proc entry run_state the process state has again changed to run state.
To remove the module
$ sudo rmmod process_change
Subscribe to:
Posts (Atom)