-
Notifications
You must be signed in to change notification settings - Fork 153
/
Copy pathmain.c
2043 lines (1348 loc) · 51.3 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
Main cheat on the kernel kernel modules and on kernel concepts
that can be exemplified in modules, which is much easier than recompiling and reinstalling the kernel.
#__rcu
TODO a type of locking directive
*/
#include <linux/version.h> /* include/generated/uapi/linux. LINUX_VERSION_CODE, KERNEL_VERSION */
#include <asm/page.h> /* PAGE_SIZE */
#include <asm/param.h> /* HZ */
#include <asm/atomic.h> /* atomic_t */
#include <linux/cdev.h> /* cdev_init, cdev_add, cdev_del */
#include <linux/dcache.h> /* dentry, super_block */
#include <linux/errno.h> /* ENOMEM, */
#include <linux/fs_struct.h> /* fs_struct */
#include <linux/fs.h> /* super_block */
#include <linux/gfp.h> /* Mnemonic: Get Free Pages. alloc_pages */
#include <linux/interrupt.h> /* request_irq, IRQF_SHARED */
#include <linux/jiffies.h> /* jiffies */
#include <linux/kernel.h> /* KERN_DEBUG */
#include <linux/kthread.h> /* kthread_create */
#include <linux/mm.h> /* Memory Management. page_address. Includes mm_types.h. */
#include <linux/mm_types.h> /* page, mm_struct */
#include <linux/module.h> /* module specific utilities: MODULE_* macros, module_param, module_init, module exit */
#include <linux/path.h> /* path */
#include <linux/sched.h> /* current */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
#include <linux/sched/rt.h> /* MAX_PRIO, MAX_USER_RT_PRIO, DEFAULT_PRIO */
#endif
#include <linux/slab.h> /* kmalloc, kmem_cach_create, kmem_cach_alloc */
#include <linux/spinlock.h>
#include <linux/string.h> /* memcpy, memcmp */
/*
#errors
The kernel defines a series of macros starting with the prefix `E` under:
include/uapi/asm-generic/errno.h
include/uapi/asm-generic/errno-base.h
For each error a short comment describing it is available on those files.
Error numbers are meant to be returned from functions to indicate the cause of errors
after being multiplied by `-1`. Ex:
return -EBADF
TODO0 errno.h vs errno-base.h
*/
/*
# Module description
## License
the kernel offers methods to indicate the license of modules or parts of modules
such as symbols
for entire modules, the `MODULE_LICENSE` macro can be used. Possible args:
- "GPL v2" (for GPL version two only)
- "GPL and additional rights"
- "Dual BSD/GPL"
- "Dual MPL/GPL"
- "Proprietary"
where `Dual` means that developers can either use BSD or GPL
If you don't set this, it is taken to be `Proprietary` by default,
'tainting' the module and the kernel,
so always define this if your module is not proprietary.
*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("John Smith <[email protected]>");
MODULE_DESCRIPTION("a cheat module");
MODULE_VERSION("0.1");
/*MODULE_DEVICE_TABLE(table_info);*/
/*MODULE_ALIAS("cheat2");*/
static int i_global;
int exported_symbol;
int exported_symbol_gpl;
EXPORT_SYMBOL(exported_symbol);
EXPORT_SYMBOL_GPL(exported_symbol_gpl);
/* Must be global: */
DEFINE_PER_CPU(int, cpu_int);
static atomic_t i_global_atomic;
static int initdata __initdata = 0;
static int initconst __initconst = 0;
static dev_t dev;
/* number of devices */
#define N_DEVS 2
static struct cdev cdevs[N_DEVS];
/*
This function is defined as the entry point by the `module_init` call below.
Using `init_module` as name also worked. TODO why
Static is not mandatory, but good practice since this function should not be seen
from other files.
Typical things a real module would do here include:
- initialize variables
- register an interrupt handler
- register a the bottom half of the interrupt handler
Return value:
- 0 on success
- non zero on failure.
You should always return the negation of constants defined in `linux/errno.h`,
for example as `return -ENOMEM`
# cleanup
module insertion forget to nicely cleanup in case
*/
static int __init init(void)
{
/* separate from older entries in log*/
printk(KERN_DEBUG __FILE__ ": \n============================================================\n");
/*
# printk
The kernel has no simple way to communicate with a terminal
so you the simplest thing to do is dump program output to a file.
`printk` does this in a very reliable manner
At the time of writting on Ubuntu 13.04 the file is: `/var/log/syslog`
This can be viewed with `dmesg`.
`KERN_DEBUG` is a message priority string macro
It is understood by printk when put at the beginning of the input string.
8 levels are defined in order of decreasing priority:
- KERN_EMERG: system is unusable
- KERN_ALERT: action must be taken immediately
- KERN_CRIT: critical conditions
- KERN_ERR: error conditions
- KERN_WARNING: warning conditions
- KERN_NOTICE: normal, but significant, condition
- KERN_INFO: informational message
- KERN_DEBUG: debug-level message
printk takes printf format strings with containing things like `%d`
*/
{
printk(KERN_DEBUG "%s\n", __func__ );
}
/* Don't be afraid, it's just a c program. Globals are still globals. */
i_global = 0;
printk(KERN_DEBUG "i_global = %d\n", i_global);
/*
# version
Device drivers depend on kernel version.
You can get some version flexibility with the preprocessor.
# LINUX_VERSION_CODE
Example: on kernel `2.6.10` == 0x02060a
# KERNEL_VERSION
Transform human version numbers into HEXA notation:
0x02060a == KERNEL_VERSION(2, 6, 10)
Always use it in case some day the version organization changes.
*/
{
/* printk( "UTS_RELEASE = %s", UTS_RELEASE ); */ /* TODO get working */
printk(KERN_DEBUG "LINUX_VERSION_CODE = %d\n", LINUX_VERSION_CODE);
/* are we at least at 2.6.10? */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
printk(KERN_DEBUG "LINUX_VERSION_CODE >= 2.6.10\n");
#endif
}
/*
# __KERNEL__
Defined on the Makefile when compiling the kernel or kernel modules.
Used with `ifdef` blocks on files which may be included from userspace,
to avoid that parts of those files be used on userpace. Example:
TODO how would a single source file be usable by both kernel and userspace?
*/
{
#ifdef __KERNEL__
printk(KERN_DEBUG "__KERNEL__");
#endif
}
/*
# assembly instructions that only kernel code can do
some instructions require kernel priviledge to be used
those that can be demonstrated here shall be
the use of plain assembly should be avoided whenever possible,
since more portable alternatives have usually already been coded,
but understanding those instructions may give you insights
on how the system achieves certain effects.
# x86
- interrupt flag IF instruction
determines if interrupts are enabled or disabled
- IO instructions
- IN Read from a port
- OUT Write to a port
- INS/INSB Input string from port/Input byte string from port
- INS/INSW Input string from port/Input word string from port
- INS/INSD Input string from port/Input doubleword string from port
- OUTS/OUTSB Output string to port/Output byte string to port
- OUTS/OUTSW Output string to port/Output word string to port
- OUTS/OUTSD Output string to port/Output doubleword string to port
*/
#ifdef __i386__
{
/*
cheat on instructions that can only be done from kernel space
in the kernel, those are be separated from non architecture specific files
*/
/* TODO how to get cr0? */
/*
int out = 0;
asm (
"mov %%cr0, %0"
: "=m" (out)
);
printk( "%d", out );
*/
}
#endif
/*
# fixed size integers
Like c99 `int32_t` family
u for unsigned, s for signed.
Defined in `include/linux/types.h`.
# fixed size endieness
For cases were big or little endieness must be explicit
Defined in `include/linux/types.h`.
TODO what is the difference between using le and be?
*/
{
/*__u8 u8 = 127;*/
/*__s8 s8 = 255;*/
__le16 le16 = 1;
__be16 be16 = 1;
if ( le16 != be16 ) return 0;
}
/*
# smp
stands for Symettrical MultiProcessing.
means using multiple cpus at once (multicore systems)
# per cpu variables
http://www.makelinux.net/ldd3/chp-8-sect-5
# DEFINE_PER_CPU
define a copy of given variable for each cpu
# get_cpu_var(name);
get variable for current cpu
this is a macro, so you can modify the variable with that too
# put_cpu_var(name);
must be called after the variable has been modified
# smp_processor_id()
get id of current processor
run this many times and it may change
# get_cpu(name, cpu)
like `get_cpu_var`, but from any processor
*/
{
get_cpu_var(cpu_int) = 0;
put_cpu_var(cpu_int);
printk(KERN_DEBUG "cpu_int = %d\n", get_cpu_var(cpu_int));
printk(KERN_DEBUG "smp_processor_id() = %d\n", smp_processor_id());
}
/*
# likely
# unlikely
the unlikely function marks a condition as rare, and makes it easier
for compilers and processors to optimize the code
likelly does the exac oposite
those should only be used when the condition is extremelly rare (common)
a typical use case is to test for errors conditions (which should, in theory, be rare...)
*/
{
if (likely(0)) {
printk(KERN_DEBUG "ERROR\n");
}
if (likely(1)) {
printk(KERN_DEBUG "unlikely(1)\n");
}
if (unlikely(0)) {
printk(KERN_DEBUG "ERROR\n");
}
if (unlikely(1)) {
printk(KERN_DEBUG "unlikely(1)\n");
}
}
/*
# __init macros
Put data on speial sections:
# define __init __attribute__ ((__section__ (".init.text")))
# define __initdata __attribute__ ((__section__ (".init.data")))
# define __exitdata __attribute__ ((__section__(".exit.data")))
# define __exit_call __attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))
# ifdef MODULE
# define __exit __attribute__ ((__section__(".exit.text")))
# else
# define __exit __attribute_used__ __attribute__ ((__section__(".exit.text")))
# endif
Functions and data in those sections are meant to be used only at initialization processes (kernel or modules),
and are then removed from RAM by `free_initmem()`.
Sources:
- http://stackoverflow.com/questions/8832114/what-does-init-mean-in-this-linux-kernel-code
- http://kernelnewbies.org/FAQ/InitExitMacros
# __init
Tells the compiler that this function is only used once at initialization,
so the kernel may free up the code memory after the initialization.
# __initdata
Marks data instead of functions.
# __initconst
# __devinit
TODO0
# __exit
Only used for modules.
Functions marked as such are removed from the RAM if the module is not loaded.
*/
{
initdata = 1;
if (initdata != 1) return -1;
if (initconst != 0) return -1;
}
/*
# data structures
the kernel has some basic and effective data structure implementations
that should be reused whenever possible
*/
{
/*
# linked lists
list_head with associated methods and macros is a doubly linked circular linked list
based on `container_of`
to understand things better:
struct list_head {
list_head *next;
list_head *prev;
}
but you should use methods and macros instead of next and prev directly
# list_head
Represents a node of a linked list.
*/
{
struct char_list {
char c; /* the actual data */
struct list_head list; /* used for the list */
};
/*
# LIST_HEAD
creates a differentiated `list_head` which shall represent the enteire list
for example, you would pass this to functions that expect a list
*/
LIST_HEAD( alist );
/*
# LIST_HEAD_INIT
links list.next and list.prev to itself:
the first element of the list
TODO when to use it? I have seen:
struct char_list ca = {
.c = 'a',
.list = LIST_HEAD_INIT(&ca.list)
};
but this does not work properly for example with transversal:
we need the differentiated element
*/
struct char_list ca = {
.c = 'a',
};
/*
# list_add
adds the element next to the given one
# list_add_tail
adds the element previous to the given one
if we use THE list head, this is the same as adding to the end of the list
*/
list_add_tail(&ca.list, &alist);
struct char_list cb = {
.c = 'b'
};
list_add_tail(&cb.list, &alist);
struct char_list cc = {
.c = 'c'
};
list_add_tail(&cc.list, &alist);
/*
# list_for_each_entry
Simplifies a loop over a list:
list_for_each_entry( list_pointer, list_head_ptr, field_name) {
- `list_pointer`: `container*` type that will point to each value of the list
- `list_head`: `container*` first element of the list
- `field_name`: name of the field of the struct that contains the `list_head*`
TODO why is this skipping the a character?
*/
printk(KERN_DEBUG "linked list:\n" );
struct char_list *char_list_ptr;
list_for_each_entry(char_list_ptr, &alist, list) {
printk(KERN_DEBUG " %c\n", char_list_ptr->c );
}
/*
to modify the list items while looping use:
list_for_each_entry_safe
*/
/*
# container_of
this macros allows us to get the address of the struct given one of the
addresses of the fields of the struct
you don't need to use it directly with lists,
but clearly it is needed internally to go from the `list_head` to the actual structure
in general, the advantage of container_of is clear:
it allows to emulate inheritance independant of the type of structure
that is inheriting
*/
if ( container_of(&ca.list, struct char_list, list) != &ca )
return -1;
}
}
/*
# algorithms
Generally useful algorithms that you would take from libc.
*/
{
int is[] = {0,1,2};
int is2[3];
memcpy( is2, is, 3 * sizeof( int ) );
if ( memcmp( is, is2, 3 * sizeof(int)) != 0 ) return -1;
}
/*
# time
There are 2 types of time:
- absolute. Ex: 1/1/2010. Hardware: RTC. Precision: Hz.
- relative: Ex: 1 sec after now.
Hardware: system timer. Precision: kHz. Interface: jiffies.
Greater precision interfaces (up to nanoseconds are also available)
Time is important on the kernel,
for example when giving hardware time to complete certain tasks.
# system timer
Programmable hardware that emmits interrputs at a given frequency,
on the 10 - 1k Hz range as of 2013.
*/
{
/*
# HZ
Frequency of the system clock.
# jiffies
How many system clock periods have passed since boot.
Starts at 0.
Mnemonic: in a jiffy is an informal / old expression for in a while.
A jiffle then is a small amount of time.
# wraparound
jiffies is an unsigned long, so if we reach its limit it wraps around to 0.
Example: half a second in the future:
unsigned long timeout = jiffies + HZ/2;
//work
//see whether we took too long
if (timeout > jiffies) {
//we did not time out, good
} else {
//we timed out, error
}
What if `jiffies` goes around and comes back to 0?
This is why you should use:
# define time_after(unknown, known) ((long)(known) - (long)(unknown) < 0)
# define time_before(unknown, known) ((long)(unknown) - (long)(known) < 0)
# define time_after_eq(unknown, known) ((long)(unknown) - (long)(known) >= 0)
# define time_before_eq(unknown, known) ((long)(known) - (long)(unknown) >= 0)
to compare times as:
if (time_before(jiffies, timeout)) {
TODO why does this work?
*/
{
printk( KERN_DEBUG "HZ = %d\n", HZ );
printk( KERN_DEBUG "jiffies = %lu\n", jiffies );
}
}
/*
# PAGE_SIZE
Size of a page.
*/
{
printk(KERN_DEBUG "PAGE_SIZE (Kib) = %lu\n", PAGE_SIZE / ( 1 << 10 ));
}
/*
# memory zones
Each page belongs to a zone.
Defined in `mmzone.h`.
There are 3 zone types: ZONE_NORMAL, ZONE_DMA and ZONE_HIGHMEM.
# ZONE_NORMAL
Not any of the other pathological cases.
# ZONE_DMA
Used for hardware access communication.
ISA.
Mainly historical usage.
# ZONE_HIGHMEM
Memory that needs more than 32 bits to be addressed, that is,
if you have more than 4 Gb memory.
Harder to work with, but useful if you need lots of memory.
It is possible to use even on IA-32 because of the PAE extension,
which essentially adds 4 bits to the memory address bus, allowing
64 Gb of memory. PAE was introduced in 1995.
This zone is always empty on x64 since there is more than enough address space there.
TODO why book says memory above 986 Mb is high memory? Why not 4 Gb?
*/
/*
# memory allocation
The following methods are common for memory allocation by the kernel for is own use:
- alloc_pages
- kmalloc
- slab alocator methods such as: kmem_cach_create + kmem_cache_alloc
- vmalloc
# gfp flags
Certain flags are used on all of those functions.
They are:
TODO
*/
/*
# alloc_pages
Gets a given number of contiguous (linear address) pages.
The number of pages is the log_2 of the multiplier.
Use this when you want the memory for a small number of large objects.
Based on the Buddy System.
# page_address
Returns start of linear address of given page, NULL if that page is on high memory
or is not mapped.
TODO page_address vs page->virtual?
# free_pages
Like aloc_pages, but takes the starting linear address.
# page struct
Fields:
- long virtual: address of current page
- atomic_t _count: usage count by whom TODO
*/
{
struct page *page;
page = alloc_pages(GFP_KERNEL, 1);
printk(KERN_DEBUG "alloc_pages\n" );
if ( page == NULL ){
printk(KERN_DEBUG " NULL\n" );
} else {
char *cs = page_address(page);
if ( (long)cs % PAGE_SIZE != 0 ) return -1;
for ( int i = 0; i < 2 * PAGE_SIZE; i++ ){
cs[i] = i;
}
printk( KERN_DEBUG " _count = %d\n", atomic_read(&page->_count) );
free_pages( (long)cs, 1);
}
}
/*
# slab allocator
Best way to allocate several objects of the same type (size and required initial data).
This is more efficicient than other methods because
- it tries to keep hardware caches correctly aligned
Structure:
- each cache contains many slabs.
All objects contained in those slabs will be of the same type.
- each slab contains objects.
Each slab occupies an integer number of contiguous pages.
Therefore, this method is only good if you are going to allocate enough
small objects to at least fill a page.
Objects can be either free or occupied.
# kmem_cache_create
Create a cache.
Signature:
kmem_cache *kmem_cache_create(
const char *name,
size_t size,
size_t offset,
unsigned long flags,
void (*ctor)(void *)
);
In a module, this operation would be typically done at module startup time.
The constructor is called on the data at creation of every object.
NULL means no contructor.
# kmem_cache_alloc
Allocate data on a created chache.
You do not need to know in which slab it will be created.
# kmem_cache_free
Free data on a cache.
# kmem_cache_destroy
Delete a cache.
*/
{
struct kmem_cache *cache;
int *is[2];
/* simple constructor function that initializes each array to { 1, 2 } */
void ctor(void *vobj){
int *obj = (int *)vobj;
obj[0] = 1;
obj[1] = 2;
}
/* create the cache */
cache = kmem_cache_create(
"test_cache_0",
2 * sizeof( int ),
0,
0,
ctor
);
if (!cache) return -1;
/* allocate memory for the cache */
/* we make two pairs of integers */
is[0] = kmem_cache_alloc(cache, GFP_KERNEL);
is[1] = kmem_cache_alloc(cache, GFP_KERNEL);
is[1][1]++;
if ( is[0][0] != 1 ) return -1;
if ( is[0][1] != 2 ) return -1;
if ( is[1][0] != 1 ) return -1;
if ( is[1][1] != 3 ) return -1;
kmem_cache_free(cache, is[0]);
kmem_cache_free(cache, is[1]);
kmem_cache_destroy(cache);
}
/*
# kmalloc
Like libc malloc, but for the kernel.
Use this when you want to create a single,
or a small number of objects of a type that is not too large.
Based on the slab allocator.
*/
{
int *is = kmalloc(2 * sizeof(int), GFP_KERNEL);
if ( !is ) return -ENOMEM;
is[0] = 0;
is[1] = 1;
is[0]++;
is[1]++;
if ( is[0] != 1 ) return -1;
if ( is[1] != 2 ) return -1;
kfree(is);
}
/*
# process
The kernel manages user processes and kernel processes, scheduling them with some algorithm
so that users see all process make some progress more or less at the same time.
The process model is found under `sched.h` and is named `struct task_struct`.
# threads
Threads are processes that share the same address space so they act on common variables.
# current
Macro that gives the `task_struct` representing the current process.
Defined in `include/asm-generic/current.h` as `current_thread_info()->task`,
which is finally defined for each arch under `asm/thread_info.h`.
`current` is so important that `x86` Linux 3.10 reserves the unused `ESP` stack pointer
only to point to the `task_struct` of the current task via:
(current_stack_pointer & ~(THREAD_SIZE - 1));
Note how `THREAD_SIZE - 1` is of the form: `00000FFF`, `~` makes it `FFFFF000`,
so that only the top bits of `current_stack_pointer` (ESP) are considered.
# current_thread_info
# task_struct
Represents processes (called taks on the kern), found in `include/linux/sched.h`
# tgid
thread group id
same for all threads that TODO have the same data?
# parent vs real_parent
TODO
there are two main scheduler used today: completely_fair and real_time
real time attempts to be real time, but linux maker no guarantees that
a process will actually run before a given time, only this is very likely
# children
processes keep a linked list of its children
# sibling
processes keep a linked list of its siblings
# task_struct scheduling fields
The following fields relate to process scheduling.
# state
Possible values are:
- TASK_RUNNING
- TASK_INTERRUPTIBLE
- TASK_UNINTERRUPTIBLE
- TASK_STOPPED
- TASK_TRACED
- TASK_ZOMBIE
- EXIT_DEAD
# static_priority
Priority when the process was started
can be changed with `nice` and `sched_setscheduler` system calls.
# normal_priority
Priority based on the static priority and on the scheduling policy only.
# prio
Actual priority.
The kernel may change this at runtime for certain reasons.
# rt_priority
real time priority. Range: 0 to 99, like nice, smallest is most urgent.
- policy
one of:
- SCHED_FIFO
- SCHED_RR
- SCHED_NORMAL
- SCHED_BATCH
- SCHED_IDLE
representing the scheduling policy
# run_list
used by the real time scheduler only
TODO
# time_slice
used by the real time only
TODO
*/
{
printk(KERN_DEBUG "TASK_RUNNING = %d\n", TASK_RUNNING);
printk(KERN_DEBUG "TASK_INTERRUPTIBLE = %d\n", TASK_INTERRUPTIBLE);
/* self is obviously running when state gets printed, parent may be not: */