| 1 | @[has_globals] |
| 2 | module builtin |
| 3 | |
| 4 | // NOTE: g_main_argc and g_main_argv are filled in right after C's main start. |
| 5 | // They are used internally by V's builtin; for user code, it is much |
| 6 | // more convenient to just use `os.args` or call `arguments()` instead. |
| 7 | |
| 8 | @[markused] |
| 9 | __global g_main_argc = int(0) |
| 10 | |
| 11 | @[markused] |
| 12 | __global g_main_argv = unsafe { nil } |
| 13 | |
| 14 | @[markused] |
| 15 | __global g_live_reload_info voidptr |
| 16 | |
| 17 | pub type FnExitCb = fn () |
| 18 | |
| 19 | fn C.atexit(f FnExitCb) i32 |
| 20 | fn C.strerror(i32) &char |
| 21 | |
| 22 | // These functions (_vinit, and _vcleanup), are generated by V. |
| 23 | // `module no_main` programs that use custom manual entrypoints should ensure to call them when appropriate. |
| 24 | // Exported V entrypoints are initialized automatically by the generated wrappers. |
| 25 | fn C._vinit(argc i32, argv &&char) |
| 26 | |
| 27 | fn C._vcleanup() |
| 28 | |
| 29 | // exit terminates execution immediately and returns exit `code` to the shell. |
| 30 | @[noreturn] |
| 31 | pub fn exit(code int) { |
| 32 | C.exit(code) |
| 33 | for {} |
| 34 | } |
| 35 | |
| 36 | // at_exit registers a fn callback, that will be called at normal process termination. |
| 37 | // It returns an error, if the registration was not successful. |
| 38 | // The registered callback functions, will be called either via exit/1, |
| 39 | // or via return from the main program, in the reverse order of their registration. |
| 40 | // The same fn may be registered multiple times. |
| 41 | // Each callback fn will called once for each registration. |
| 42 | pub fn at_exit(cb FnExitCb) ! { |
| 43 | $if freestanding { |
| 44 | return error('at_exit not implemented with -freestanding') |
| 45 | } $else { |
| 46 | res := C.atexit(cb) |
| 47 | if res != 0 { |
| 48 | return error_with_code('at_exit failed', res) |
| 49 | } |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | fn v_segmentation_fault_handler(signal_number i32) { |
| 54 | $if freestanding { |
| 55 | eprintln('signal 11: segmentation fault') |
| 56 | } $else { |
| 57 | C.fprintf(C.stderr, c'signal %d: segmentation fault\n', signal_number) |
| 58 | } |
| 59 | $if use_libbacktrace ? { |
| 60 | $if openbsd { |
| 61 | print_backtrace() |
| 62 | } $else { |
| 63 | eprint_libbacktrace(1) |
| 64 | } |
| 65 | } $else { |
| 66 | print_backtrace() |
| 67 | } |
| 68 | exit(128 + signal_number) |
| 69 | } |
| 70 | |
| 71 | @[inline] |
| 72 | fn v_fixed_index(i int, len int) int { |
| 73 | $if !no_bounds_checking { |
| 74 | if i < 0 || i >= len { |
| 75 | panic('fixed array index out of range (index: ' + i64(i).str() + ', len: ' + |
| 76 | i64(len).str() + ')') |
| 77 | } |
| 78 | } |
| 79 | return i |
| 80 | } |
| 81 | |
| 82 | @[inline; markused] |
| 83 | fn v_fixed_index_i64(i i64, len int) int { |
| 84 | $if !no_bounds_checking { |
| 85 | if i < 0 || i >= i64(len) { |
| 86 | panic('fixed array index out of range (index: ' + i.str() + ', len: ' + i64(len).str() + |
| 87 | ')') |
| 88 | } |
| 89 | } |
| 90 | return int(i) |
| 91 | } |
| 92 | |
| 93 | @[inline; markused] |
| 94 | fn v_fixed_index_u64(i u64, len int) int { |
| 95 | $if !no_bounds_checking { |
| 96 | if i >= u64(len) { |
| 97 | panic('fixed array index out of range (index: ' + i.str() + ', len: ' + i64(len).str() + |
| 98 | ')') |
| 99 | } |
| 100 | } |
| 101 | return int(i) |
| 102 | } |
| 103 | |
| 104 | @[inline; markused] |
| 105 | fn v_fixed_index_ni(i int, len int) int { |
| 106 | return v_fixed_index(v_ni_index(i, len), len) |
| 107 | } |
| 108 | |
| 109 | @[inline; markused] |
| 110 | fn v_slice_index_i64(i i64) int { |
| 111 | if i < i64(min_int) || i > i64(max_int) { |
| 112 | panic('slice index out of range for int: ' + i.str()) |
| 113 | } |
| 114 | return int(i) |
| 115 | } |
| 116 | |
| 117 | @[inline; markused] |
| 118 | fn v_slice_index_u64(i u64) int { |
| 119 | if i > u64(max_int) { |
| 120 | panic('slice index out of range for int: ' + i.str()) |
| 121 | } |
| 122 | return int(i) |
| 123 | } |
| 124 | |
| 125 | // arguments returns the command line arguments, used for starting the current program as a V array of strings. |
| 126 | // The first string in the array (index 0), is the name of the program, used for invoking the program. |
| 127 | // The second string in the array (index 1), if it exists, is the first argument to the program, etc. |
| 128 | // For example, if you started your program as `myprogram -option`, then arguments() will return ['myprogram', '-option']. |
| 129 | // Note: if you `v run file.v abc def`, then arguments() will return ['file', 'abc', 'def'], or ['file.exe', 'abc', 'def'] (on Windows). |
| 130 | pub fn arguments() []string { |
| 131 | argv := &&u8(g_main_argv) |
| 132 | mut res := []string{cap: g_main_argc} |
| 133 | for i in 0 .. g_main_argc { |
| 134 | $if windows { |
| 135 | res << unsafe { string_from_wide(&u16(argv[i])) } |
| 136 | } $else { |
| 137 | res << unsafe { tos_clone(argv[i]) } |
| 138 | } |
| 139 | } |
| 140 | return res |
| 141 | } |
| 142 | |
| 143 | // vcurrent_hash returns @VCURRENTHASH, which depends on the git version of |
| 144 | // the V repository, from which the V executable had been compiled. |
| 145 | pub fn vcurrent_hash() string { |
| 146 | return @VCURRENTHASH |
| 147 | } |
| 148 | |
| 149 | // v_getpid returns a process identifier. It is a number that is guaranteed to |
| 150 | // remain the same while the current process is running. It may or may not be |
| 151 | // equal to the value of v_gettid(). Note: it is *NOT equal on Windows*. |
| 152 | pub fn v_getpid() u64 { |
| 153 | $if no_getpid ? { |
| 154 | // support non posix/windows systems that lack process management |
| 155 | return 0 |
| 156 | } $else $if windows { |
| 157 | return u64(C.GetCurrentProcessId()) |
| 158 | } $else { |
| 159 | return u64(C.getpid()) |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | // v_gettid retuns a thread identifier. It is a number that is guaranteed to not |
| 164 | // change, while the current thread is running. Different threads, running at |
| 165 | // the same time in the same process, have different thread ids. There is no |
| 166 | // such guarantee for threads running in different processes. |
| 167 | // Important: this will be the same number returned by v_getpid(), but only on |
| 168 | // non windows systems, when the current thread is the main one. It is best to |
| 169 | // *avoid relying on this equivalence*, and use v_gettid and v_getpid only for |
| 170 | // tracing and debugging multithreaded issues, but *NOT for logic decisions*. |
| 171 | pub fn v_gettid() u64 { |
| 172 | $if no_gettid ? { |
| 173 | // support non posix/windows systems that lack process management |
| 174 | return 0 |
| 175 | } $else $if windows { |
| 176 | return u64(C.GetCurrentThreadId()) |
| 177 | } $else $if linux && !musl ? { |
| 178 | return u64(C.gettid()) |
| 179 | } $else $if threads { |
| 180 | return u64(C.pthread_self()) |
| 181 | } $else { |
| 182 | return v_getpid() |
| 183 | } |
| 184 | } |
| 185 | |