v2 / vlib / builtin / builtin.c.v
184 lines · 163 sloc · 5.4 KB · ffd6da8ac9c8314c9dd2d5ea6ed878e6402883eb
Raw
1@[has_globals]
2module 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
17pub type FnExitCb = fn ()
18
19fn C.atexit(f FnExitCb) i32
20fn 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.
25fn C._vinit(argc i32, argv &&char)
26
27fn C._vcleanup()
28
29// exit terminates execution immediately and returns exit `code` to the shell.
30@[noreturn]
31pub 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.
42pub 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
53fn 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]
72fn 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]
83fn 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]
94fn 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]
105fn 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]
110fn 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]
118fn 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).
130pub 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.
145pub 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*.
152pub 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*.
171pub 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