libk  Check-in [175dc46a91]

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: 175dc46a91d51ec73c04b30f7d35e880d67e373502ff69c9980d7a644d1a8cbb
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,