Overview
Comment: | update kcore docs, fix bad type names and dumb logic |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
175dc46a91d51ec73c04b30f7d35e880 |
User & Date: | lexi on 2019-07-26 10:52:44 |
Other Links: | manifest | tags |
Context
2019-07-26
| ||
21:56 | add kmath module stub check-in: 85a8c60bd2 user: lexi tags: trunk | |
10:52 | update kcore docs, fix bad type names and dumb logic check-in: 175dc46a91 user: lexi tags: trunk | |
09:51 | major update. fix ridiculous old type size determination mechanism. mmap is still broken and i'm not sure why; the syscall does not appear to be going through correctly - see posix_mmap, kmheapa, and kcore/testbin.exe.fn check-in: 6479e060a3 user: lexi tags: trunk | |
Changes
Modified kcore/kcore.md from [28cd81b166] to [a610cab74a].
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
..
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
# kcore **kcore** is the foundation for the rest of libk. it defines types and structs that are needed by every program, and provides the stub that launches a program's "entry" function. unlike the non-core modules, kcore definitions simply use the prefix `k-`. ## entry when using libk, your program's entry point will not be the `int main(int,char**)` function that libc opens into. libk will call the function `stat entry(kenv)` instead. like libc, the value returned by `entry` will be returned to the host platform. ## types kcore contains fixed-width integer types (in <k/type.h>). note that the availability of each depends on your platform; compilation will fail if e.g. you try to use a u64 or a u128 on a 32-bit platform, so where exact lengths are not required, you may wish to use the built-in C types instead. * `u8` - an unsigned 8-bit integer * `s8` - a signed 8-bit integer * `u16` - an unsigned 16-bit integer * `s16` - a signed 16-bit integer * `u32` - an unsigned 32-bit integer * `s32` - a signed 32-bit integer * `u64` - an unsigned 64-bit integer * `s64` - a signed 64-bit integer * `u128` - an unsigned 128-bit integer * `s128` - a signed 128-bit integer * `word` - an unsigned integer of platform word-length (e.g. 32 bits on x86.32; 64 on x86.64) * `sword` - a signed integer of platform word-length (e.g. 32 bits on x86.32; 64 on x86.64) * `stat` - the type of process return values expected by the platform (usually u8 on linux) ### struct kenv `kenv` is a struct that encompasses the environment the program was launched in. * `kiochan std` - a stereo IO channel for reading and writing to and from stdout. * `kiochan err` - a mono IO channel for writing to stderr. * `kvar* vars` - a pointer into the program's environment ................................................................................ * `kstr val` - the value of an environment variable * `char* platform` - a pointer into the platform's underlying representation ## functions ### kstop() `noreturn void kstop(stat)` terminates the program immediately, returning the specified integer to the OS as an exit status. the type of integer it takes depends on your operating system. consider using the `enum kbad` defines in `<k/magic.h>`, which are designed to standardize exit statuses across different software and are synchronized with a FreeBSD effort to do the same (`<sysexit.h`). ## definitions kcore is the only module that defines any terms outside the k- namespace. the only terms it so defines are native C terms like `noreturn`, which are implemented as keywords in a reserved namespace (`_` followed by an uppercase letter; in this case, `_Noreturn`). macros are then defined in new headers for the "natural" version of the term in order to avoid breaking older code. examples of this technique are `<stdbool.h>` and `<stdnoreturn.h>`. since libk is designed for new, modern code, breaking old code isn't a concern, and we turn on all these new keywords as soon as you load `<k/core.h>`. libk attempts to find the best possible definition and implementation for these various types and keywords, abstracting across different C versions and dialects. you can go ahead and use the normal version of the keywords (e.g. `noreturn`, `bool`) no matter what kind of compiler you're using and you're guaranteed that as long as you don't go fiddling with undefined- or implementation behavior, your code will behave the same every time. at worst, it may lack a few optimizations or warnings. |
|
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
|
|
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
..
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
# kcore **kcore** is the foundation for the rest of libk. it defines types and structs that are needed by every program, and provides the stub that launches a program's "entry" function. unlike the non-core modules, kcore definitions simply use the prefix `k-`. ## entry when using libk, your program's entry point will not be the `int main(int,char**)` function that libc opens into. libk will call the function `stat entry(kenv)` instead. like libc, the value returned by `entry` will be returned to the host platform. ## types kcore contains fixed-width integer types (in `<k/type.h>`). these types are present on every platform. if a platform has a type with a given bit length, it will be used, otherwise, the type will round to the largest available type (except `u8` and `s8`). if you need to be absolutely certain that a type is the appropriate bit length, use sizeof to check its length in a conditional or static assert, for instance `if (sizeof(u16) == 16 / kc_byte_bits)`. * `u8` - an unsigned 8-bit integer, or the smallest available unsigned type * `s8` - a signed 8-bit integer, or the smallest available signed type * `u16` - an unsigned 16-bit integer * `s16` - a signed 16-bit integer * `u32` - an unsigned 32-bit integer * `s32` - a signed 32-bit integer * `u64` - an unsigned 64-bit integer * `s64` - a signed 64-bit integer * `u128` - an unsigned 128-bit integer (uses GCC and clang extensions to offer 128-bit integer support on x86-64) * `s128` - a signed 128-bit integer (ibid) * `ubig` - the largest available unsigned integer type * `sbig` - the largest available signed integer type. note: ubig and sbig really are the *largest* possible integer types not just the largest native types - if your compiler has extensions for 128-bit types on your arch (as GCC and clang do on x86-64), ubig and sbig will be 128 bits long even if your system word length is less than 128. so only use ubig/sbig if you really, really mean it. * `ubyte` - the smallest available unsigned integer type besides \_Bool * `sbyte` - the smallest available signed integer type besides \_Bool * `stat` - the type of process return values expected by the platform (usually u8 on linux) * `sz` - a type large enough to cover a platform's entire address space (libc equivalent size_t) * `offset` - a type that can contain the difference between two pointers (libc equivalent ptrdiff_t) ## constants in `<k/type.h>`, every type has an associated min and max constant, containing the smallest and largest value that type can hold on your system. these can be access by suffixing a type with `_min` and `_max`, respectively. min and max values of native types can be accessed with the `kc_[us]` prefix - for instance, the minimum value of `signed long` is `kc_slong_min`. (`long long` can be referenced as `llong`). * `byte_bits` - the bit length of ubyte, sbyte, and char; that is, the number of bits in the type `sizeof` measures things in terms of. `sizeof(type) * byte_bits` will always return the number of bits in a type. ### struct kenv `kenv` is a struct that encompasses the environment the program was launched in. * `kiochan std` - a stereo IO channel for reading and writing to and from stdout. * `kiochan err` - a mono IO channel for writing to stderr. * `kvar* vars` - a pointer into the program's environment ................................................................................ * `kstr val` - the value of an environment variable * `char* platform` - a pointer into the platform's underlying representation ## functions ### kstop() `noreturn void kstop(stat)` terminates the program immediately, returning the specified integer to the OS as an exit status. the type of integer it takes depends on your operating system. consider using the `enum kbad` defines in `<k/magic.h>`, which are designed to standardize exit statuses across different software and are synchronized with a FreeBSD effort to do the same (`<sysexit.h>`). ## definitions kcore is the only module that defines any terms outside the k- namespace. the only terms it so defines are native C terms like `noreturn`, which are implemented as keywords in a reserved namespace (`_` followed by an uppercase letter; in this case, `_Noreturn`). macros are then defined in new headers for the "natural" version of the term in order to avoid breaking older code. examples of this technique are `<stdbool.h>` and `<stdnoreturn.h>`. since libk is designed for new, modern code, breaking old code isn't a concern, and we turn on all these new keywords as soon as you load `<k/core.h>`. libk attempts to find the best possible definition and implementation for these various types and keywords, abstracting across different C versions and dialects. you can go ahead and use the normal version of the keywords (e.g. `noreturn`, `bool`) no matter what kind of compiler you're using and you're guaranteed that as long as you don't go fiddling with undefined- or implementation behavior, your code will behave the same every time. at worst, it may lack a few optimizations or warnings. |
Modified kcore/type.h.m from [a9978dfd3a] to [def2d33e25].
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 ... 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 ... 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
--- this file gathers information on the environment it's --- being compiled in, defining types that our code --- needs. it will be emitted as <k/type.h>. --- vim: ft=c #ifndef KItype #define KItype typedef unsigned char kc_uint_min; typedef signed char kc_sint_min; typedef unsigned long long kc_uint_max; typedef signed long long kc_sint_max; [ifdef type_bit8] typedef unsigned [type_bit8] u8; typedef signed [type_bit8] s8; [else] typedef kc_uint_min u8; typedef kc_sint_min s8; [endif] [ifdef type_bit16] typedef unsigned [type_bit16] u16; typedef signed [type_bit16] s16; [else] typedef kc_uint_max u16; typedef kc_sint_max s16; [endif] [ifdef type_bit32] typedef unsigned [type_bit32] u32; typedef signed [type_bit32] s32; [else] typedef kc_uint_max u32; typedef kc_sint_max s32; [endif] [ifdef type_bit64] typedef unsigned [type_bit64] u64; typedef signed [type_bit64] s64; [ifndef type_bit128] # if defined(__GNUC__) || defined(__clang__) typedef unsigned __int128_t u128; typedef signed __int128_t s128; # else typedef kc_uint_max u128; typedef kc_sint_max s128; # endif [endif] [else] typedef kc_uint_max u64; typedef kc_sint_max s64; typedef kc_uint_max u128; typedef kc_sint_max s128; [endif] [ifdef type_bit128] typedef unsigned [type_bit128] u128; typedef signed [type_bit128] s128; [endif] enum /* max-min values of each type */ { /* assuming two's complement. TODO: check math */ /* TODO: figure out how to calc min */ kc_byte_bits = [byte_bits], u8_min = 0, u8_max = ((u8)-1), u16_min = 0, u16_max = ((u16)-1), u32_min = 0, u32_max = ((u32)-1), u64_min = 0, u32_max = ((u64)-1), u128_min = 0, u128_max = ((u128)-1), [define merge: $1$2] [define [sspec type]: [merge [type],_min] = 0 - ((1 << sizeof([type]) * kc_byte_bits) / 2), [merge [type],_max] = (1 << sizeof([type]) * kc_byte_bits) / 2 - 1] [sspec s8], [sspec s16], [sspec s32], [sspec s64], [sspec s128], kc_min_uchar = 0, kc_max_uchar = [type_max_u_char], kc_min_ushort = 0, kc_max_ushort = [type_max_u_short], kc_min_uint = 0, kc_max_uint = [type_max_u_int], kc_min_ulong = 0, kc_max_ulong = [type_max_u_long], kc_min_ullong = 0, kc_max_ullong = [type_max_u_llong], kc_min_schar = [type_min_s_char], kc_max_schar = [type_max_s_char], kc_min_sshort = [type_min_s_short], kc_max_sshort = [type_max_s_short], kc_min_sint = [type_min_s_int], kc_max_sint = [type_max_s_int], kc_min_slong = [type_min_s_long], kc_max_slong = [type_max_s_long], kc_min_sllong = [type_min_s_llong], kc_max_sllong = [type_max_s_llong], }; [ifdef type_sz] typedef [type_sz] sz; [else] # ifdef __cplusplus /* C++ gives us a clean, standardized way to do this */ ................................................................................ # if defined(__GNUC__) || defined(__clang__) typedef __typeof__ (sizeof(char)) sz; # else /* we're stumped - set sz to the safest possible value under * the circumstances, and warn the user. */ # warning no authoritative sz (size_t) type definition \ available; defaulting to largest unsigned integer type typedef kc_uint_max sz; # endif # endif [endif] [ifdef type_offset] typedef [type_offset] offset; [else] ................................................................................ # if defined(__GNUC__) || defined(__clang__) typedef __typeof__ (((void*)10) - ((void*)5)) offset; # else /* no dice - set offset to the safest possible value under * the circumstances, and warn the user. */ # warning no authoritative offset (ptrdiff_t) type definition \ available; defaulting to largest unsigned integer type typedef kc_sint_max offset; # endif # endif [endif] // exit status integer types - pls use kbad in <k/magic.h> instead [if [target_posix] == yes] /* by convention, posix return values are 8-bit, |
| | | | < > | | | | | < < | > > | < < < < < < < < < < < < < < > > > | | > > > > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < | > > | | | | | | | | | | > > > > > > | | |
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 ... 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 ... 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
--- this file gathers information on the environment it's --- being compiled in, defining types that our code --- needs. it will be emitted as <k/type.h>. --- vim: ft=c #ifndef KItype #define KItype /* we define 64-bit types first due to an oddity in how * 128-bit types are handled: we want kc_?big to reference * the absolute largest type available to the compiler, * but in some cases, 128-bits may not be among the * standard C types despite being supported by the * compiler. to work around this, we first check whether * 64-bit types are available (__int128_t only works on * 64-bit systems) and then whether the compiler is one * that supports the 128-bit extension - but only if a * native 128-bit type is not available. * * once this is done, we can be certain that u128 will * reference the largest available integer type and can * safely define kc_?big by reference to it. */ [ifdef type_bit64] typedef unsigned [type_bit64] u64; typedef signed [type_bit64] s64; [ifndef type_bit128] /* even if no native type is 128 bits long, clang and * gcc have extensions to support 128 bit arithmetic * on 64-bit hardware */ # if defined(__GNUC__) || defined(__clang__) typedef unsigned __int128_t u128; typedef signed __int128_t s128; # else /* if we don't have access to that extension * or native 128-bit types, then we just use * the largest native type specified in the * C standard */ typedef unsigned long long u128; typedef signed long long s128; # endif [endif] [else] typedef unsigned long long u64; typedef signed long long s64; typedef u64 u128; typedef s64 s128; [endif] [ifdef type_bit128] typedef unsigned [type_bit128] u128; typedef signed [type_bit128] s128; [endif] typedef unsigned char ubyte; typedef signed char sbyte; typedef u128 ubig; typedef s128 sbig; [ifdef type_bit8] typedef unsigned [type_bit8] u8; typedef signed [type_bit8] s8; [else] typedef ubyte u8; typedef sbyte s8; [endif] [ifdef type_bit16] typedef unsigned [type_bit16] u16; typedef signed [type_bit16] s16; [else] typedef ubig u16; typedef sbig s16; [endif] [ifdef type_bit32] typedef unsigned [type_bit32] u32; typedef signed [type_bit32] s32; [else] typedef ubig u32; typedef sbig s32; [endif] enum /* max-min values of each type */ { byte_bits = [byte_bits], u8_min = 0, u8_max = ((u8)-1), u16_min = 0, u16_max = ((u16)-1), u32_min = 0, u32_max = ((u32)-1), u64_min = 0, u32_max = ((u64)-1), u128_min = 0, u128_max = ((u128)-1), /* assuming two's complement. TODO: check math */ [define merge: $1$2] [define [sspec type]: [merge [type],_min] = 0 - ((1 << sizeof([type]) * kc_byte_bits) / 2), [merge [type],_max] = (1 << sizeof([type]) * kc_byte_bits) / 2 - 1] [sspec s8], [sspec s16], [sspec s32], [sspec s64], [sspec s128], kc_uchar_min = 0, kc_uchar_max = [type_max_u_char], kc_ushort_min = 0, kc_ushort_max = [type_max_u_short], kc_uint_min = 0, kc_uint_max = [type_max_u_int], kc_ulong_min = 0, kc_ulong_max = [type_max_u_long], kc_ullong_min = 0, kc_ullong_max = [type_max_u_llong], kc_schar_min = [type_min_s_char], kc_schar_max = [type_max_s_char], kc_sshort_min = [type_min_s_short], kc_sshort_max = [type_max_s_short], kc_sint_min = [type_min_s_int], kc_sint_max = [type_max_s_int], kc_slong_min = [type_min_s_long], kc_slong_max = [type_max_s_long], kc_sllong_min = [type_min_s_llong], kc_sllong_max = [type_max_s_llong], ubig_min = u128_min, ubig_max = u128_max, sbig_min = s128_min, sbig_max = s128_max, ubyte_min = kc_uchar_min, ubyte_max = kc_uchar_max, sbyte_min = kc_schar_min, sbyte_max = kc_schar_max, }; [ifdef type_sz] typedef [type_sz] sz; [else] # ifdef __cplusplus /* C++ gives us a clean, standardized way to do this */ ................................................................................ # if defined(__GNUC__) || defined(__clang__) typedef __typeof__ (sizeof(char)) sz; # else /* we're stumped - set sz to the safest possible value under * the circumstances, and warn the user. */ # warning no authoritative sz (size_t) type definition \ available; defaulting to largest unsigned integer type typedef ubig sz; # endif # endif [endif] [ifdef type_offset] typedef [type_offset] offset; [else] ................................................................................ # if defined(__GNUC__) || defined(__clang__) typedef __typeof__ (((void*)10) - ((void*)5)) offset; # else /* no dice - set offset to the safest possible value under * the circumstances, and warn the user. */ # warning no authoritative offset (ptrdiff_t) type definition \ available; defaulting to largest unsigned integer type typedef sbig offset; # endif # endif [endif] // exit status integer types - pls use kbad in <k/magic.h> instead [if [target_posix] == yes] /* by convention, posix return values are 8-bit, |