what could be a practical example of the usage of the shared global variables in threads….is the usage similar to the shared memory???
what could be a practical example of the usage of the shared global variables in threads….is the usage similar to the shared memory???
the obvious thought which comes in everybody’s mind is that when we give major and minor number at the time of mknod ,the device being opened is the one with the given minor number….i am also thinking the same…but discrepancy occurs when i print the minor number in the open function…if i give minor number 2 at the time of mknod then the minor number being printed in the open function is 4 onot 2….major number is always printed correctly ie 250 but not the minor number.
printf format specification:
%[flag][width][.precision][modifier]<type>
meaning of fields with e.g.,:
format output
1. flag: printf(“%7s”,”hello”); spacespacehello
2. width: prinf(“%4d”,10); spacespace10
3. precision: (“%.2f”,1.1412); 1.41
4. modifier:
h interpreted as short used with i,d,o,u,x
l interpreted as long used with i,d,o,u,x
L interpreted as double used with i,d,o,u,x
5. type: d,i,x,X as their usual meanings etc.
#include
void use_int(void *);
void use_float(void *);
void greeting(void (*)(void *), void *);
int main(void) {
char ans;
int i_age = 22;
float f_age = 22.0;
void *p;
printf(“Use int (i) or float (f)? “);
scanf(“%c”, &ans);
if (ans == ‘i’) {
p = &i_age;
greeting(use_int, p);
}
else {
p = &f_age;
greeting(use_float, p);
}
return 0;
}
void greeting(void (*fp)(void *), void *q) {
fp(q);
}
void use_int(void *r) {
int a;
a = * (int *) r;
printf(“As an integer, you are %d years old.\n”, a);
}
void use_float(void *s) {
float *b;
b = (float *) s;
printf(“As a float, you are %f years old.\n”, *b);
}
Although this requires us to cast the void pointer into the appropriate type in the relevant subroutine (use_int or use_float), the flexibility here appears in the greeting routine, which can now handle in principle a function with any type of argument. This will especially become apparent when we discuss structures in the next section.
Memory barriers are instructions to both the compiler and the CPU to
impose a partial ordering between the memory access operations
specified either side of the barrier.
Older and less complex CPUs will perform memory accesses in exactly
the order specified, so if one is given the following piece of code:
a = *A;
*B = b;
c = *C;
d = *D;
*E = e;
It can be guaranteed that it will complete the memory access for each
instruction before moving on to the next line, leading to a definite
sequence of operations on the bus:
read *A, write *B, read *C, read *D, write *E.
However, with newer and more complex CPUs, this isn't always true
because:
(*) they can rearrange the order of the memory accesses to promote
better use of the CPU buses and caches;
(*) reads are synchronous and may need to be done immediately to
permit progress, whereas writes can often be deferred without
a problem;
(*) and they are able to combine reads and writes to improve
performance when talking to the SDRAM (modern SDRAM chips can
do batched accesses of adjacent locations, cutting down on
transaction setup costs).
When a program runs on a single CPU, the hardware performs the necessary bookkeeping
to ensure that programs execute as if all memory operations were performed in the order
specified by the programmer (program order), hence memory barriers are not necessary.
However, when the memory is shared with multiple devices, such as other CPUs in a
multiprocessor system, or memory mapped peripherals, out-of-order access may affect
program behavior. For example, a second CPU may see memory changes made by the
first CPU in a sequence which differs from program order.
So what you might actually get from the above piece of code is:
read *A, read *C+*D, write *E, write *B
Under normal operation, this is probably not going to be a problem;
however,there are two circumstances where it definitely _can_ be a
problem:
(1) I/O
Many I/O devices can be memory mapped, and so appear to the CPU
as if they're just memory locations. However, to control the
device, the driver has to make the right accesses in exactly the
right order.
Consider, for example, an ethernet chipset such as the AMD
PCnet32. It presents to the CPU an "address register" and a bunch
of "data registers".The way it's accessed is to write the index
of the internal register you want to access to the address
register, and then read or write the appropriate data register
to access the chip's internal register:
*ADR = ctl_reg_3;
reg = *DATA;
The problem with a clever CPU or a clever compiler is that the
write to the address register isn't guaranteed to happen before
the access to the data register, if the CPU or the compiler
thinks it is more efficient to defer the address write:
read *DATA, write *ADR
then things will break.
The way to deal with this is to insert an I/O memory barrier
between the two accesses:
*ADR = ctl_reg_3;
mb();
reg = *DATA;
In this case, the barrier makes a guarantee that all memory accesses before the
barrier will happen before all the memory accesses after the barrier. It does not
guarantee that all memory accesses before the barrier will be
complete by the time the barrier is complete.
(2) Multiprocessor interaction
When there's a system with more than one processor, these may be
working on the same set of data, but attempting not to use locks
as locks are quite expensive. This means that accesses that
affect both CPUs may have to be carefully ordered to prevent
error.
Consider the R/W semaphore slow path. In that, a waiting process
is queued on the semaphore, as noted by it having a record on
its stack linked to the semaphore's list:
struct rw_semaphore {
...
struct list_head waiters;
};
struct rwsem_waiter {
struct list_head list;
struct task_struct *task;
};
To wake up the waiter, the up_read() or up_write() functions
have to read the pointer from this record to know as to where
the next waiter record is, clear the task pointer, call
wake_up_process() on the task, and release the task struct
reference held:
READ waiter->list.next;
READ waiter->task;
WRITE waiter->task;
CALL wakeup
RELEASE task
If any of these steps occur out of order, then the whole thing
may fail.
Note that the waiter does not get the semaphore lock again - it
just waits for its task pointer to be cleared. Since the record
is on its stack, this means that if the task pointer is cleared
before the next pointer in the list is read, then another CPU
might start processing the waiter and it might clobber its stack
before up*() functions have a chance to read the next pointer.
CPU 0 CPU 1
========================= ===========================
down_xxx()
Queue waiter
Sleep
up_yyy()
READ waiter->task;
WRITE waiter->task;
<preempt>
Resume processing
down_xxx() returns
call foo()
foo() clobbers *waiter
</preempt>
READ waiter->list.next;
--- OOPS ---
This could be dealt with using a spinlock, but then the down_xxx()
function has to get the spinlock again after it's been woken up,
which is a waste of resources. The way to deal with this is to
insert an SMP memory barrier:
READ waiter->list.next;
READ waiter->task;
smp_mb();
WRITE waiter->task;
CALL wakeup
RELEASE task
In this case, the barrier makes a guarantee that all memory
accesses before the barrier will happen before all the memory
accesses after the barrier. It does not guarantee that all
memory accesses before the barrier will be complete by the time
the barrier is complete.
SMP memory barriers are normally no-ops on
a UP system because the CPU orders overlapping accesses with
respect to itself.
Referrece:-http://lwn.net/Articles/174655/
read the following code:
main()
{
int *p,a[5]={1,2,3,4,5};
for(p=a;p<&a[5];p++)
{
*p=p-a;
printf(“%d “,*p);
}
return 0;
}
theoretical output= 0 4 8 12 16
compiler output=0 1 2 3 4
question: Why p++ (increment in address of p) increments the whole memory block , considering it as a unit and not the individual byte.
Levels of Optimization
Let’s first look at how GCC categorizes optimizations and how a developer can control which are used and, sometimes more important, which are not. A large variety of optimizations are provided by GCC. Most are categorized into one of three levels, but some are provided at multiple levels. Some optimizations reduce the size of the resulting machine code, while others try to create code that is faster, potentially increasing its size. For completeness, the default optimization level is zero, which provides no optimization at all. This can be explicitly specified with option -O or -O0.
Level 1 (-O1)
The purpose of the first level of optimization is to produce an optimized image in a short amount of time. These optimizations typically don’t require significant amounts of compile time to complete. Level 1 also has two sometimes conflicting goals. These goals are to reduce the size of the compiled code while increasing its performance. The set of optimizations provided in -O1 support these goals, in most cases. These are shown in Table 1 in the column labeled -O1. The first level of optimization is enabled as:
gcc -O1 -o test test.c
Any optimization can be enabled outside of any level simply by specifying its name with the -f prefix, as:
gcc -fdefer-pop -o test test.c
We also could enable level 1 optimization and then disable any particular optimization using the -fno- prefix, like this:
gcc -O1 -fno-defer-pop -o test test.c
This command would enable the first level of optimization and then specifically disable the defer-pop optimization.
Level 2 (-O2)
The second level of optimization performs all other supported optimizations within the given architecture that do not involve a space-speed trade-off, a balance between the two objectives. For example, loop unrolling and function inlining, which have the effect of increasing code size while also potentially making the code faster, are not performed. The second level is enabled as:
gcc -O2 -o test test.c
The level -O2 optimizations include all of the -O1 optimizations, plus a large number of others.
Level 2.5 (-Os)
The special optimization level (-Os or size) enables all -O2 optimizations that do not increase code size; it puts the emphasis on size over speed. This includes all second-level optimizations, except for the alignment optimizations. The alignment optimizations skip space to align functions, loops, jumps and labels to an address that is a multiple of a power of two, in an architecture-dependent manner. Skipping to these boundaries can increase performance as well as the size of the resulting code and data spaces; therefore, these particular optimizations are disabled. The size optimization level is enabled as:
gcc -Os -o test test.c
In gcc 3.2.2, reorder-blocks is enabled at -Os, but in gcc 3.3.2 reorder-blocks is disabled.
Level 3 (-O3)
The third and highest level enables even more optimizations by putting emphasis on speed over size. This includes optimizations enabled at -O2 and rename-register. The optimization inline-functions also is enabled here, which can increase performance but also can drastically increase the size of the object, depending upon the functions that are inlined. The third level is enabled as:
gcc -O3 -o test test.c
Although -O3 can produce fast code, the increase in the size of the image can have adverse effects on its speed. For example, if the size of the image exceeds the size of the available instruction cache, severe performance penalties can be observed. Therefore, it may be better simply to compile at -O2 to increase the chances that the image fits in the instruction cache.
Referrence:- http://www.linuxjournal.com/article/7269
I am trying to pad two characters in num and trying to print the num in bit pattern.But I am getting -1 instead of 1;
Output is
for 65 – it should be 01000001
but i am getting 0-100000-1
sample program is :-
/*padding ytwo char*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void char_pad();
void bit_representation( int num);
int main()
{
char_pad();
}
void char_pad()
{
int num =0;
char ch;
printf(“enter first char :”);
ch = getchar();
num = num << 8;
num = num | ch;
printf(“num is : %d\n”,num);
while( getchar() != ‘\n’);
printf(“enter second char :”);
ch = getchar();
num = num <<8;
num = num | ch;
printf(“num is : %d\n”,num);
bit_representation(num);
}
void bit_representation( int num)
{
int temp,loc;
int i,j;
for(i=0; i<4; i++)
{
temp = num;
temp = temp <<(8 * i);
temp = temp >>(24)
printf(“temp is : %d\n”,temp);
for(j=0; j<8; j++)
{
loc = temp;
loc = loc << (24 +j);
loc = loc >>31;
printf(“%d”,loc);
}
printf(“\n”);
}
}
I am performing file read and write operations
everything is working fine but my function is not
checking EOF. It is not coming out of loop even if
i had applied a condition (if character is equal to EOF
).
/*main file
File name : file_main.c*/
#include”myheader.h”
int main(int argc,char *arg[])
{
int fptr,ch;
fptr = open(arg[1],O_RDONLY);
if(fptr == -1)
{
perror(“file does not exist \n”);
exit(EXIT_FAILURE);
}
while(1)
{
printf(“press 1: to read 2: to copy to another file 3: to compress4: exit”);
scanf(“%d”, &ch);
switch(ch)
{
case 1: read_file(fptr);
break;
case 2: copy_file(fptr);
break;
case 3: compress_file(fptr);
break;
case 4: exit(0);
}
}
}
/*file functions.c — function definitions are
present in this file*/
/* file name : file_functions.c*/
#include”myheader.h”
void read_file(int fptr)
{
char ch = ”;
int i;
read(fptr,&ch,1);
while(1)
{
if(i != 0)
{
write(1,&ch,1);
}
i = read(fptr,&ch,1);
if(ch == EOF)
{
printf(“******* FILE COMPLETE ********\n”);
break;
}
}
}
void copy_file(int fptr)
{
int file_d,i;
char ch = ”;
file_d = open(“copy.txt”,O_CREAT | O_WRONLY);
if(file_d == -1)
{
perror(“ERROR IN COPY FUNCTION : \n”);
exit(EXIT_FAILURE);
}
while(1)
{
i = read(fptr,&ch,1);
if(i == 0)
{
continue;
}
if(ch == EOF)
{
break;
}
i = write(file_d,&ch,1);
while(i == 0)
{
i = write(file_d, &ch,1);
}
}
}
void compress_file(int fptr)
{
}
/*make file */
FILE:file_functions.o file_main.o
gcc -o FILE file_main.o file_functions.o
file_main.o:file_main.c myheader.h
gcc -g -c file_main.c
file_functions.o:file_functions.c myheader.h
gcc -g -c file_functions.c
clean:
rm *.o
rm FILE copy.txt
#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/usb.h>
#include<linux/fs.h> //for struct file_operations
#include<linux/slab.h> //for kmalloc
#include<linux/kref.h> //for struct kref
#include<linux/mutex.h> //for struct mutex
#include<linux/device.h> //for structure device
#include<linux/completion.h> //for struct completion
#include<linux/interrupt.h>
#include<linux/writeback.h>
MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“lkm”);
static int gdm7213_probe(struct usb_interface *interface, const struct usb_device_id *id);
void gdm7213_disconnect (struct usb_interface *intf);
static struct usb_device_id gdm7213_table [] = {
{ USB_DEVICE(0x03f0,0×5307) }, //my flash drive vendor id ,product id.u can check it with ur device.
{ }
};
MODULE_DEVICE_TABLE(usb, gdm7213_table);
static struct usb_driver gdm7213_driver = {
.name = “lkm”,
.probe = gdm7213_probe,
.disconnect = gdm7213_disconnect,
// .suspend = gdm7213_suspend,
// .resume = gdm7213_resume,
// .pre_reset = gdm7213_pre_reset,
// .post_reset = gdm7213_post_reset,
.id_table = gdm7213_table,
};
static int gdm7213_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
printk(KERN_INFO “GDM7213 gdm7213_probe()\n”);
return 0;
}
void gdm7213_disconnect (struct usb_interface *intf)
{
printk(KERN_INFO “GDM7213 gdm7213_disconnect()\n”);
}
static int __init gdm7213_init_module(void)
{
int result;
printk(KERN_INFO “GDM7213 init_module()\n”);
result = usb_register(&gdm7213_driver);
if (result)
err(“usb_register failed. Error number %d”, result);
else
printk(KERN_INFO “usb registerd\n”);
return result;
}
static void __exit gdm7213_cleanup_module(void)
{
printk(KERN_INFO “GDM7213 cleanup_module()\n”);
usb_deregister(&gdm7213_driver);
}
module_init(gdm7213_init_module);
module_exit(gdm7213_cleanup_module);
Implemented Driver Initialization Algo.
Able to run my own open() function in module.