libsystem_kernel: Cache UID and GID
As explained in `getuid.c`, the UID and GID getters are called very
frequently, and that was producing lots of traffic to the server in the
old implementation. Since the server never updates a process's UID and
GID values on its own (i.e. it only ever changes as a result of a call
from the process itself), we can cache the UID and GID values on the
client-side to significantly reduce RPC traffic.
I determined this was a call that needed to be optimized after checking
how often it was called. Using the following command, I generated a
list of how frequently each kind of call was made:
```
cat ~/.darling/private/var/log/dserver.log | grep 'Received call' | sed 's/.*(dserver_callnum_\([A-Za-z0-9_]\+\)).*/\1/g' | sort | uniq -c | sort -nr
```
I ran that command after doing a simple session of LLDB:
```
host> rm ~/.darling/private/var/log/dserver.log
host> darling shell zsh
darling> lldb -- ./hello
lldb> process launch
# control-c after it exits because LLDB doesn't currently detect that correctly
lldb> quit
darling> exit
```
The results before this change:
```
33245 uidgid
7173 pthread_canceled
2087 mach_msg_overwrite
1247 s2c
1008 kprintf
342 psynch_mutexwait
337 psynch_mutexdrop
327 mach_port_deallocate
226 thread_self_trap
112 mach_reply_port
102 task_self_trap
91 psynch_cvwait
85 host_self_trap
81 checkin
79 psynch_cvbroad
60 task_is_64_bit
59 vchroot_path
50 set_thread_handles
37 mldr_path
31 checkout
27 mach_port_insert_right
27 kqchan_proc_open
25 mach_port_allocate
21 mach_port_move_member
20 started_suspended
20 set_dyld_info
19 get_tracer
16 kqchan_mach_port_open
16 interrupt_enter
15 interrupt_exit
14 fork_wait_for_child
12 semaphore_signal
11 mach_port_request_notification
9 mach_port_get_attributes
9 console_open
8 thread_get_special_reply_port
8 semaphore_timedwait
8 mach_port_construct
7 sigprocess
4 thread_suspended
4 mach_port_destruct
3 mach_port_mod_refs
1 vchroot
1 tid_for_thread
1 task_for_pid
1 stop_after_exec
1 set_tracer
1 push_reply
1 ptrace_thupdate
1 ptrace_sigexc
1 pthread_markcancel
1 pid_for_task
```
And the results after this change:
```
7186 pthread_canceled
2122 mach_msg_overwrite
1247 s2c
1020 kprintf
332 mach_port_deallocate
295 psynch_mutexwait
295 psynch_mutexdrop
229 thread_self_trap
119 mach_reply_port
108 task_self_trap
89 host_self_trap
83 checkin
82 psynch_cvwait
79 psynch_cvbroad
62 vchroot_path
61 task_is_64_bit
52 set_thread_handles
44 uidgid
38 mldr_path
32 checkout
29 kqchan_proc_open
27 mach_port_insert_right
25 mach_port_allocate
21 started_suspended
21 set_dyld_info
21 mach_port_move_member
20 get_tracer
17 interrupt_enter
16 kqchan_mach_port_open
16 interrupt_exit
15 fork_wait_for_child
12 semaphore_signal
11 mach_port_request_notification
9 thread_get_special_reply_port
9 mach_port_get_attributes
9 console_open
8 semaphore_timedwait
8 mach_port_construct
7 sigprocess
4 thread_suspended
4 mach_port_destruct
3 mach_port_mod_refs
1 vchroot
1 tid_for_thread
1 task_for_pid
1 stop_after_exec
1 set_tracer
1 push_reply
1 ptrace_thupdate
1 ptrace_sigexc
1 pthread_markcancel
1 pid_for_task
```
As you can see, it went from over 33,000 UID/GID calls to just over 40.
Needless to say, this is a *significant* improvement.
It looks like the next call that could use some optimization is
`pthread_canceled` and I already have some ideas on how to do so.
However, that will have to wait until I get a few more issues fixed with
other things (like notifyd crashing).