First, I found no Internet in the guest OS, need to manually turn on the related service on the Windows host.
I had problems with open-vm-tools on Debian 12. The auto resolution, and the sharing folder features does not work. Try to manual install the VMWare tool with inserting ISO, resulted in segment fault when compiling.
Tried same approach with Debian 13 released few days ago, does not work.
Try to install Ubuntu 24 LTS as the guest OS instead. VMWare detected the OS, will use the easy install. open-vm-tools and other features are automatically set up.
2. Setup the Cross Compile Toolchain
Update the system first.
1
apt update && apt upgrade
Install the required packages.
1
apt install vim p7zip-full git make cmake stlink-tools minicom
Download and extract the cross-compile toolchain to the ~/opt/ folder.
tar xvf arm-gnu-toolchain-14.2.rel1-x86_64-arm-none-eabi.tar.xz
As for the meaning of the suffix arm-none-eabi: ARM is the target architecture, none means no vender, EABI stands for Embedded Application Binary Interface.
Update the environment and verify the installation is successful by printing the version.
1
source ~/.bashrc
3. Setup the Serial Port in the Guest OS
Plug in the STM32 board and link that to the guest OS ![[/images/Setup STM32 Dev Environment on Windows Laptop with Virtual Machine-res/setup_usb_reflex.png]] The drive file should show up in the /dev device mapping folder as /dev/ACM0
ev_io_init is a macro that expands to the following code, mainly for initializing the watcher, such as setting the callback, fd, events, etc.:
1 2 3 4 5 6 7 8 9 10 11
do { do { ((ev_watcher *)(void *)((&stdin_watcher)))->active = ((ev_watcher *)(void *)((&stdin_watcher)))->pending = 0; ((ev_watcher *)(void *)(((&stdin_watcher))))->priority = (0); (((&stdin_watcher)))->cb = ((stdin_cb)), memmove(&((ev_watcher *)(((&stdin_watcher))))->cb, &(((&stdin_watcher)))->cb, sizeof((((&stdin_watcher)))->cb)); } while (0); do { ((&stdin_watcher))->fd = ((0)); ((&stdin_watcher))->events = ((EV_READ)) | EV__IOFDSET; } while (0); } while (0);
ev_io_start mainly modifies the anfds and fdchanges arrays. For watchers that are already active, it returns directly. If it is not active, it sets the active and priority and uses the head insertion method to insert it into the linked list of the corresponding fd in anfds, and sets the current watcher as the head:
void (*backend_modify)(struct ev_loop *loop, int fd, int oev, int nev); void (*backend_poll)(struct ev_loop *loop, ev_tstamp timeout);
Taking epoll as an example, backend_modify is epoll_modify, and backend_poll is epoll_poll. epoll_modify is the epoll_ctl commonly used by everyone. When an event changes, use EPOLL_CTL_MOD, otherwise use EPOLL_CTL_ADD.
The internal implementation of the timer uses a Binary Heap and a Quaternary Heaps (for better cache efficiency).
1 2 3 4
#define DHEAP 4 #define HEAP0 (DHEAP - 1) /* index of first element in heap */ #define HPARENT(k) ((((k) - HEAP0 - 1) / DHEAP) + HEAP0) #define UPHEAP_DONE(p,k) ((p) == (k))
Note that HEAP0 is used as the first element, that is, the offset. The internal implementation of the heap is upheap and downheap, which are relatively simple and will not be described here. Its structure is:
1 2 3 4 5 6
typedef ev_watcher_time *WT;
typedefstruct { ev_tstamp at; WT w; } ANHE;
The heap is sorted according to at, which is the expiration time of the timer. The heap sort is sorted according to the value of at from small to large.
EV_DEFAULT will call the ev_default_loop function to initialize an ev_loop structure, which mainly initializes the loop structure through loop_init, such as choosing epoll or poll, select. The most critical point: epoll_init occurs when the above loop is created.
ev_run is more complicated and mainly does the following:
fd_reify: Traverse the fdchanges array mentioned earlier, take out the linked list from anfds according to the fd, traverse all event linked lists, get all events, and determine whether the latest event is consistent with the previous old event (events). If they are inconsistent, call epoll_modify (or add the event for the first time).
1 2 3 4 5
typedefstruct { WL head; // event linked list unsignedchar events; // other } ANFD;
backend_poll: See the implementation of backend_poll above, it will fetch the ready events and put the events into the pendings array, that is, put them at the end of the corresponding priority queue.
timer_reify: If the event has not expired, no processing is done. Otherwise, the executes the following:
Call ev_timer_stop to clear the timer that has no repeat set.
Set the repeat timer with ev_timer_init() call
invoke_cb: it is ev_invoke_pending by default, the callback will be take out of from the priority queue then be triggered respectively.
Design a data structure to store the strings’ count with the ability to return the strings with minimum and maximum counts.
Implement the AllOne class:
AllOne() Initializes the object of the data structure.
inc(String key) Increments the count of the string key by 1. If key does not exist in the data structure, insert it with count 1.
dec(String key) Decrements the count of the string key by 1. If the count of key is 0 after the decrement, remove it from the data structure. It is guaranteed that key exists in the data structure before the decrement.
getMaxKey() Returns one of the keys with the maximal count. If no element exists, return an empty string "".
getMinKey() Returns one of the keys with the minimum count. If no element exists, return an empty string "".
Note that each function must run in O(1) average time complexity.
Analysis
This problem requires accessing random value and boundries in constant time.
Hence, a cache replacement algorithm pattern should be used:
Hashing map ensures inc and dec runs in constant time. Its pairs’ value points to another container.
To ensure getting max and min value in constant time, ordered linear data structure such as: std::vector, std::list, should be used. std::list is finnaly chosen because its low cost to insert, delete, & relocate elements.