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 1 # kcore 2 2 **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-`. 3 3 4 4 ## entry 5 5 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. 6 6 7 7 ## types 8 -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. 8 +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)`. 9 9 10 - * `u8` - an unsigned 8-bit integer 11 - * `s8` - a signed 8-bit integer 10 + * `u8` - an unsigned 8-bit integer, or the smallest available unsigned type 11 + * `s8` - a signed 8-bit integer, or the smallest available signed type 12 12 * `u16` - an unsigned 16-bit integer 13 13 * `s16` - a signed 16-bit integer 14 14 * `u32` - an unsigned 32-bit integer 15 15 * `s32` - a signed 32-bit integer 16 16 * `u64` - an unsigned 64-bit integer 17 17 * `s64` - a signed 64-bit integer 18 - * `u128` - an unsigned 128-bit integer 19 - * `s128` - a signed 128-bit integer 20 - * `word` - an unsigned integer of platform word-length (e.g. 32 bits on x86.32; 64 on x86.64) 21 - * `sword` - a signed integer of platform word-length (e.g. 32 bits on x86.32; 64 on x86.64) 18 + * `u128` - an unsigned 128-bit integer (uses GCC and clang extensions to offer 128-bit integer support on x86-64) 19 + * `s128` - a signed 128-bit integer (ibid) 20 + * `ubig` - the largest available unsigned integer type 21 + * `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. 22 + * `ubyte` - the smallest available unsigned integer type besides \_Bool 23 + * `sbyte` - the smallest available signed integer type besides \_Bool 22 24 * `stat` - the type of process return values expected by the platform (usually u8 on linux) 25 + * `sz` - a type large enough to cover a platform's entire address space (libc equivalent size_t) 26 + * `offset` - a type that can contain the difference between two pointers (libc equivalent ptrdiff_t) 27 + 28 +## constants 29 +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`). 30 + 31 + * `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. 23 32 24 33 ### struct kenv 25 34 `kenv` is a struct that encompasses the environment the program was launched in. 26 35 * `kiochan std` - a stereo IO channel for reading and writing to and from stdout. 27 36 * `kiochan err` - a mono IO channel for writing to stderr. 28 37 * `kvar* vars` - a pointer into the program's environment 29 38 ................................................................................ 33 42 * `kstr val` - the value of an environment variable 34 43 * `char* platform` - a pointer into the platform's underlying representation 35 44 36 45 ## functions 37 46 38 47 ### kstop() 39 48 40 -`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`). 49 +`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>`). 41 50 42 51 ## definitions 43 52 44 53 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>`. 45 54 46 55 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. 47 56
Modified kcore/type.h.m from [a9978dfd3a] to [def2d33e25].
3 3 --- this file gathers information on the environment it's 4 4 --- being compiled in, defining types that our code 5 5 --- needs. it will be emitted as <k/type.h>. 6 6 --- vim: ft=c 7 7 #ifndef KItype 8 8 #define KItype 9 9 10 -typedef unsigned char kc_uint_min; 11 -typedef signed char kc_sint_min; 12 -typedef unsigned long long kc_uint_max; 13 -typedef signed long long kc_sint_max; 14 - 15 -[ifdef type_bit8] 16 - typedef unsigned [type_bit8] u8; 17 - typedef signed [type_bit8] s8; 18 -[else] 19 - typedef kc_uint_min u8; 20 - typedef kc_sint_min s8; 21 -[endif] 22 - 23 -[ifdef type_bit16] 24 - typedef unsigned [type_bit16] u16; 25 - typedef signed [type_bit16] s16; 26 -[else] 27 - typedef kc_uint_max u16; 28 - typedef kc_sint_max s16; 29 -[endif] 30 - 31 -[ifdef type_bit32] 32 - typedef unsigned [type_bit32] u32; 33 - typedef signed [type_bit32] s32; 34 -[else] 35 - typedef kc_uint_max u32; 36 - typedef kc_sint_max s32; 37 -[endif] 10 +/* we define 64-bit types first due to an oddity in how 11 + * 128-bit types are handled: we want kc_?big to reference 12 + * the absolute largest type available to the compiler, 13 + * but in some cases, 128-bits may not be among the 14 + * standard C types despite being supported by the 15 + * compiler. to work around this, we first check whether 16 + * 64-bit types are available (__int128_t only works on 17 + * 64-bit systems) and then whether the compiler is one 18 + * that supports the 128-bit extension - but only if a 19 + * native 128-bit type is not available. 20 + * 21 + * once this is done, we can be certain that u128 will 22 + * reference the largest available integer type and can 23 + * safely define kc_?big by reference to it. */ 38 24 39 25 [ifdef type_bit64] 40 26 typedef unsigned [type_bit64] u64; 41 27 typedef signed [type_bit64] s64; 42 28 [ifndef type_bit128] 29 + /* even if no native type is 128 bits long, clang and 30 + * gcc have extensions to support 128 bit arithmetic 31 + * on 64-bit hardware */ 43 32 # if defined(__GNUC__) || defined(__clang__) 44 33 typedef unsigned __int128_t u128; 45 34 typedef signed __int128_t s128; 46 35 # else 47 - typedef kc_uint_max u128; 48 - typedef kc_sint_max s128; 36 + /* if we don't have access to that extension 37 + * or native 128-bit types, then we just use 38 + * the largest native type specified in the 39 + * C standard */ 40 + typedef unsigned long long u128; 41 + typedef signed long long s128; 49 42 # endif 50 43 [endif] 51 44 [else] 52 - typedef kc_uint_max u64; 53 - typedef kc_sint_max s64; 45 + typedef unsigned long long u64; 46 + typedef signed long long s64; 54 47 55 - typedef kc_uint_max u128; 56 - typedef kc_sint_max s128; 48 + typedef u64 u128; 49 + typedef s64 s128; 57 50 [endif] 58 51 59 52 [ifdef type_bit128] 60 53 typedef unsigned [type_bit128] u128; 61 54 typedef signed [type_bit128] s128; 62 55 [endif] 56 + 57 +typedef unsigned char ubyte; 58 +typedef signed char sbyte; 59 +typedef u128 ubig; 60 +typedef s128 sbig; 61 + 62 +[ifdef type_bit8] 63 + typedef unsigned [type_bit8] u8; 64 + typedef signed [type_bit8] s8; 65 +[else] 66 + typedef ubyte u8; 67 + typedef sbyte s8; 68 +[endif] 69 + 70 +[ifdef type_bit16] 71 + typedef unsigned [type_bit16] u16; 72 + typedef signed [type_bit16] s16; 73 +[else] 74 + typedef ubig u16; 75 + typedef sbig s16; 76 +[endif] 77 + 78 +[ifdef type_bit32] 79 + typedef unsigned [type_bit32] u32; 80 + typedef signed [type_bit32] s32; 81 +[else] 82 + typedef ubig u32; 83 + typedef sbig s32; 84 +[endif] 63 85 64 86 enum /* max-min values of each type */ { 65 - /* assuming two's complement. TODO: check math */ 66 - /* TODO: figure out how to calc min */ 67 - kc_byte_bits = [byte_bits], 87 + byte_bits = [byte_bits], 88 + 68 89 u8_min = 0, u8_max = ((u8)-1), 69 90 u16_min = 0, u16_max = ((u16)-1), 70 91 u32_min = 0, u32_max = ((u32)-1), 71 92 u64_min = 0, u32_max = ((u64)-1), 72 93 u128_min = 0, u128_max = ((u128)-1), 73 94 95 + /* assuming two's complement. TODO: check math */ 74 96 [define merge: $1$2] 75 97 [define [sspec type]: 76 98 [merge [type],_min] = 0 - ((1 << sizeof([type]) * kc_byte_bits) / 2), 77 99 [merge [type],_max] = (1 << sizeof([type]) * kc_byte_bits) / 2 - 1] 78 100 79 101 [sspec s8], [sspec s16], [sspec s32], 80 102 [sspec s64], [sspec s128], 81 103 82 - kc_min_uchar = 0, kc_max_uchar = [type_max_u_char], 83 - kc_min_ushort = 0, kc_max_ushort = [type_max_u_short], 84 - kc_min_uint = 0, kc_max_uint = [type_max_u_int], 85 - kc_min_ulong = 0, kc_max_ulong = [type_max_u_long], 86 - kc_min_ullong = 0, kc_max_ullong = [type_max_u_llong], 104 + kc_uchar_min = 0, kc_uchar_max = [type_max_u_char], 105 + kc_ushort_min = 0, kc_ushort_max = [type_max_u_short], 106 + kc_uint_min = 0, kc_uint_max = [type_max_u_int], 107 + kc_ulong_min = 0, kc_ulong_max = [type_max_u_long], 108 + kc_ullong_min = 0, kc_ullong_max = [type_max_u_llong], 109 + 110 + kc_schar_min = [type_min_s_char], kc_schar_max = [type_max_s_char], 111 + kc_sshort_min = [type_min_s_short], kc_sshort_max = [type_max_s_short], 112 + kc_sint_min = [type_min_s_int], kc_sint_max = [type_max_s_int], 113 + kc_slong_min = [type_min_s_long], kc_slong_max = [type_max_s_long], 114 + kc_sllong_min = [type_min_s_llong], kc_sllong_max = [type_max_s_llong], 115 + 116 + ubig_min = u128_min, ubig_max = u128_max, 117 + sbig_min = s128_min, sbig_max = s128_max, 87 118 88 - kc_min_schar = [type_min_s_char], kc_max_schar = [type_max_s_char], 89 - kc_min_sshort = [type_min_s_short], kc_max_sshort = [type_max_s_short], 90 - kc_min_sint = [type_min_s_int], kc_max_sint = [type_max_s_int], 91 - kc_min_slong = [type_min_s_long], kc_max_slong = [type_max_s_long], 92 - kc_min_sllong = [type_min_s_llong], kc_max_sllong = [type_max_s_llong], 119 + ubyte_min = kc_uchar_min, ubyte_max = kc_uchar_max, 120 + sbyte_min = kc_schar_min, sbyte_max = kc_schar_max, 93 121 }; 94 122 95 123 [ifdef type_sz] 96 124 typedef [type_sz] sz; 97 125 [else] 98 126 # ifdef __cplusplus 99 127 /* C++ gives us a clean, standardized way to do this */ ................................................................................ 102 130 # if defined(__GNUC__) || defined(__clang__) 103 131 typedef __typeof__ (sizeof(char)) sz; 104 132 # else 105 133 /* we're stumped - set sz to the safest possible value under 106 134 * the circumstances, and warn the user. */ 107 135 # warning no authoritative sz (size_t) type definition \ 108 136 available; defaulting to largest unsigned integer type 109 - typedef kc_uint_max sz; 137 + typedef ubig sz; 110 138 # endif 111 139 # endif 112 140 [endif] 113 141 114 142 [ifdef type_offset] 115 143 typedef [type_offset] offset; 116 144 [else] ................................................................................ 121 149 # if defined(__GNUC__) || defined(__clang__) 122 150 typedef __typeof__ (((void*)10) - ((void*)5)) offset; 123 151 # else 124 152 /* no dice - set offset to the safest possible value under 125 153 * the circumstances, and warn the user. */ 126 154 # warning no authoritative offset (ptrdiff_t) type definition \ 127 155 available; defaulting to largest unsigned integer type 128 - typedef kc_sint_max offset; 156 + typedef sbig offset; 129 157 # endif 130 158 # endif 131 159 [endif] 132 160 133 161 // exit status integer types - pls use kbad in <k/magic.h> instead 134 162 [if [target_posix] == yes] 135 163 /* by convention, posix return values are 8-bit,