Study Notes on Android RIL source code: javasril_event

Source: Internet
Author: User
The android source code directory hardware/RIL/libril contains a total of five C/CPP files: ril_commands.h, ril_unsol_commands.h, ril_event.h, ril_event.cpp, and rIL. cpp. This article mainly analyzes the code of ril_event.

Ril_event mainly processes the ports and modem events involved in the telephone module, organizes multiple events in chronological order, and stores them in the event team, three queues are used: watch_table [], timer_list, and pending_list. The code is implemented in C language. First, let's look at the header file ril_event.h:

 

// The maximum number of file descriptor handles monitored each time, you can modify <br/> # define max_fd_events 8 </P> <p> // callback function of ril_event <br/> typedef void (* ril_event_cb) (int fd, short events, void * userdata ); </P> <p> struct ril_event {<br/> // used to concatenate ril_event into forward and backward pointers of two-way linked lists <br/> struct ril_event * next; <br/> struct ril_event * Prev; </P> <p> // file descriptor handle related to RIL events (such as files, pipelines, and sockets) <br/> int FD; </P> <p> // index of the event in the monitoring list <br/> int index; </P> <p> // after an event is processed (that is, the event is moved from watch_table to pending_list to be moderately awaiting processing ), <br/> // The persist parameter determines whether the event persists in the monitoring list watch_table [] <br/> bool persist; </P> <p> // event timeout <br/> struct timeval timeout; </P> <p> // callback function and its input parameters <br/> ril_event_cb func; <br/> void * Param; <br/> }; </P> <p> // The following are RIL event-related operation functions <br/> // initialize the internal data structure <br/> void ril_event_init (); </P> <p> // initialize a RIL event <br/> void ril_event_set (struct ril_event * eV, int FD, bool persist, ril_event_cb func, void * PARAM ); </P> <p> // Add the event to the monitoring list watch_table [] <br/> void ril_event_add (struct ril_event * eV ); </P> <p> // Add a timer event to the timer_list linked list <br/> void ril_timer_add (struct ril_event * eV, struct timeval * TV ); </P> <p> // remove the specified event from the monitoring list watch_table [] <br/> void ril_event_del (struct ril_event * eV ); </P> <p> // event loop <br/> void ril_event_loop ();

Next, analyze the ril_event. cpp file:

 

# Define log_tag "rilc" </P> <p> # include <stdlib. h> <br/> # include <unistd. h> <br/> # include <errno. h> <br/> # include <fcntl. h> <br/> # include <utils/log. h> <br/> # include <ril_event.h> <br/> # include <string. h> <br/> # include <sys/time. h> <br/> # include <time. h> </P> <p> # include <pthread. h> </P> <p> // use mutex for thread synchronization. For more information, see <br/> static pthread_mutex_t listmutex in Linux program design; <br/> # define mutex_acquire () pthread _ Mutex_lock (& listmutex) <br/> # define mutex_release () pthread_mutex_unlock (& listmutex) <br/> # define mutex_init () pthread_mutex_init (& listmutex, null) <br/> # define mutex_destroy () pthread_mutex_destroy (& listmutex) </P> <p> // Add two values of the timeval type <br/> # ifndef timeradd <br/> # define timeradd (TVP, UVP, vvp) \ <br/> do {\ <br/> (vvp)-> TV _sec = (TVP)-> TV _sec + (UVP)-> TV _sec; \ <br/> (vvp)-> TV _usec = (TVP)-> TV _usec + (UVP)-> TV _usec; \ <br/> If (vvp)-> TV _usec >=1000000) {\< br/> (vvp)-> TV _sec ++; \ <br/> (vvp)-> TV _usec-= 1000000; \ <br/>}\< br/>} while (0) <br/> # endif </P> <p> // compare two values of the timeval type <br/> # ifndef timercmp <br/> # define timercmp (, b, OP) \ <br/> (a)-> TV _sec = (B)-> TV _sec \ <br/>? (A)-> TV _usec OP (B)-> TV _usec \ <br/>: (a)-> TV _sec OP (B)-> TV _sec) <br/> # endif </P> <p> // two values of the timeval type subtract <br/> # ifndef timersub <br/> # define timersub (A, B, res) \ <br/> do {\< br/> (RES)-> TV _sec = (a)-> TV _sec-(B)-> TV _sec; \ <br/> (RES)-> TV _usec = (a)-> TV _usec-(B)-> TV _usec; \ <br/> If (RES) -> TV _usec <0) {\< br/> (RES)-> TV _usec + = 1000000 ;\< br/> (RES)-> TV _sec-= 1; \ <br/>}\ <br/>} while (0); <br/> # endi </P> <p> // save all device file handles in rild, easy to use the select function to monitor events <br/> static fd_set readfds; <br/> // record the maximum FD value in readfds + 1 <br/> static int NFDs = 0; </P> <p> // to centrally manage RIL events, Android provides the following three Queues: <br/> // monitoring event list, all events to be detected must be saved to the list. <br/> static struct ril_event * watch_table [max_fd_events]; </P> <p> // timer event queue, after the event times out, it is moved into the pending_list queue <br/> static struct ril_event timer_list; </P> <p> // the queue of the event to be processed, that is, the event has been triggered, callback Function of the event to be called later <br/> S Tatic struct ril_event pending_list; </P> <p> # define debug 0 </P> <p> # If debug <br/> # define dlog (X ...) logd (x) <br/> static void dump_event (struct ril_event * eV) <br/>{< br/> dlog ("~~~~ Event % x ~~~~ ", (Unsigned INT) eV); <br/> dlog (" next = % x ", (unsigned INT) ev-> next ); <br/> dlog ("Prev = % x", (unsigned INT) ev-> PREV); <br/> dlog ("FD = % d ", ev-> FD); <br/> dlog ("pers = % d", ev-> persist ); <br/> dlog ("timeout = % DS + % DUS", (INT) ev-> timeout. TV _sec, (INT) ev-> timeout. TV _usec); <br/> dlog ("func = % x", (unsigned INT) ev-> func); <br/> dlog ("Param = % x ", (unsigned INT) ev-> param); <br/> dlog ("~~~~~~ ~~~~~~~~~~~~ "); <Br/>}< br/> # else <br/> # define dlog (X ...) do {} while (0) <br/> # define dump_event (x) do {} while (0) <br/> # endif </P> <p> // obtain the timeval value at the moment <br/> static void getnow (struct timeval * TV) <br/>{< br/> # ifdef have_posix_clocks <br/> struct timespec ts; <br/> clock_gettime (clock_monotonic, & TS ); <br/> TV-> TV _sec = ts. TV _sec; <br/> TV-> TV _usec = ts. TV _nsec/1000; <br/> # else <br/> gettimeofday (TV, null); <br/> # Endif <br/>}</P> <p> // initialize the specified ril_event linked list <br/> static void init_list (struct ril_event * List) <br/>{< br/> memset (list, 0, sizeof (struct ril_event); <br/> list-> next = List; <br/> list-> Prev = List; <br/> list-> FD =-1; <br/>}</P> <p> // Add an ril_event event to the ril_event queue header <br/> static void addtolist (struct ril_event * eV, struct ril_event * List) <br/>{< br/> ev-> next = List; <br/> ev-> Prev = List-> Prev; <B R/> ev-> Prev-> next = EV; <br/> list-> Prev = EV; <br/> dump_event (EV ); <br/>}</P> <p> // remove the specified ril_event from the ril_event queue <br/> static void removefromlist (struct ril_event * eV) <br/> {<br/> dlog ("~~~~ Removing event ~~~~ "); <Br/> dump_event (EV); </P> <p> ev-> next-> Prev = ev-> Prev; <br/> ev-> Prev-> next = ev-> next; <br/> ev-> next = NULL; <br/> ev-> Prev = NULL; <br/>}</P> <p> // remove the event of the specified index from watch_table [] <br/> static void removewatch (struct ril_event * eV, int index) <br/> {<br/> // The Event corresponding to the index is set to null, at the same time, the index of the event eV is set to an invalid value-1 <br/> watch_table [Index] = NULL; <br/> ev-> Index =-1; </P> <p> // clear the file descriptor handle corresponding to the event from readfds <br/> fd_clr (ev-> FD, & Readfds); </P> <p> If (ev-> FD + 1 = NFDs) {<br/> int n = 0; </P> <p> for (INT I = 0; I <max_fd_events; I ++) {<br/> struct ril_event * REV = watch_table [I]; </P> <p> If (Rev! = NULL) & (REV-> FD> N) {<br/> N = rev-> FD; <br/>}< br/> NFDs = n + 1; <br/> dlog ("~~~~ NFDs = % d ~~~~ ", NFDs); <br/>}</P> <p> // traverses events in the timer_list queue, when the event expires, <br/> // remove the event and add it to the pending_list queue <br/> static void processtimeouts () <br/> {<br/> dlog ("~~~~ + Processtimeouts ~~~~ "); <Br/> mutex_acquire (); <br/> struct timeval now; <br/> struct ril_event * TEV = timer_list.next; <br/> struct ril_event * next; </P> <p> getnow (& now); <br/> // walk list, see if now> = ev-> timeout for any events </P> <p> dlog ("~~~~ Looking for timers <= % DS + % DUS ~~~~ ", (INT) now. TV _sec, (INT) now. TV _usec); <br/> while (TEV! = & Timer_list) & (timercmp (& now, & TEV-> timeout,> ))) {<br/> // timer expired <br/> dlog ("~~~~ Firing timer ~~~~ "); <Br/> next = TEV-> next; <br/> removefromlist (TEV); <br/> addtolist (TEV, & pending_list ); <br/> TEV = next; <br/>}< br/> mutex_release (); <br/> dlog ("~~~~ -Processtimeouts ~~~~ "); <Br/>}</P> <p> // traverses events in the monitoring list watch_table, and add the event with readable data to the pending_list linked list, at the same time, if the persist of the event is not true <br/> //, the event will be removed from watch_table [] <br/> static void processreadies (fd_set * rfds, int N) <br/> {<br/> dlog ("~~~~ + Processreadreadies (% d )~~~~ ", N); <br/> mutex_acquire (); </P> <p> for (INT I = 0; (I <max_fd_events) & (n> 0 ); I ++) {<br/> struct ril_event * REV = watch_table [I]; <br/> If (Rev! = NULL & fd_isset (REV-> FD, rfds) {<br/> addtolist (Rev, & pending_list ); <br/> If (REV-> persist = false) {<br/> removewatch (Rev, I); <br/>}< br/> n --; <br/>}</P> <p> mutex_release (); <br/> dlog ("~~~~ -Processreadreadies (% d )~~~~ ", N); <br/>}</P> <p> // call the callback function of the events in the pending_list queue in sequence <br/> static void firepending () <br/> {<br/> dlog ("~~~~ + Firepending ~~~~ "); <Br/> struct ril_event * EV = pending_list.next; <br/> while (Ev! = & Pending_list) {<br/> struct ril_event * Next = ev-> next; <br/> removefromlist (EV ); <br/> ev-> func (ev-> FD, 0, ev-> param); <br/> EV = next; <br/>}< br/> dlog ("~~~~ -Firepending ~~~~ "); <Br/>}</P> <p> // calculate the new timeout value of the next event in the timer_list linked list <br/> static int calcnexttimeout (struct timeval * TV) <br/>{< br/> struct ril_event * TEV = timer_list.next; <br/> struct timeval now; </P> <p> getnow (& now ); </P> <p> // sorted list, so calc based on first node <br/> If (TEV = & timer_list) {<br/> // no pending timers <br/> return-1; <br/>}</P> <p> dlog ("~~~~ Now = % DS + % DUS ~~~~ ", (INT) now. TV _sec, (INT) now. TV _usec); <br/> dlog ("~~~~ Next = % DS + % DUS ~~~~ ", <Br/> (INT) TEV-> timeout. TV _sec, (INT) TEV-> timeout. TV _usec); <br/> If (timercmp (& TEV-> timeout, & now,>) {<br/> timersub (& TEV-> timeout, & now, TV); <br/>}else {<br/> // timer already expired. <br/> TV-> TV _sec = TV-> TV _usec = 0; <br/>}< br/> return 0; <br/>}</P> <p> // initialize the internal data structure (mutex, FD set, and three event queues) <br/> void ril_event_init () <br/>{< br/> mutex_init (); </P> <p> fd_zero (& readfds); <br/> init_list (& time R_list); <br/> init_list (& pending_list); <br/> memset (watch_table, 0, sizeof (watch_table )); <br/>}</P> <p> // initialize a RIL event <br/> void ril_event_set (struct ril_event * eV, int FD, bool persist, ril_event_cb func, void * PARAM) <br/>{< br/> dlog ("~~~~ Ril_event_set % x ~~~~ ", (Unsigned INT) eV); <br/> memset (EV, 0, sizeof (struct ril_event); <br/> ev-> FD = FD; <br/> ev-> Index =-1; <br/> ev-> persist = persist; <br/> ev-> func = func; <br/> ev-> param = Param; </P> <p> // file lock function of Linux, non-blocking file lock on file descriptor FD <br/> fcntl (FD, f_setfl, o_nonblock ); <br/>}</P> <p> // Add the event to the monitoring list watch_table [] <br/> void ril_event_add (struct ril_event * eV) <br/> {<br/> dlog ("~~~~ + Ril_event_add ~~~~ "); <Br/> mutex_acquire (); <br/> for (INT I = 0; I <max_fd_events; I ++) {<br/> If (watch_table [I] = NULL) {<br/> watch_table [I] = EV; <br/> ev-> Index = I; <br/> dlog ("~~~~ Added at % d ~~~~ ", I); <br/> dump_event (EV); <br/> fd_set (ev-> FD, & readfds ); <br/> If (ev-> FD> = NFDs) NFDs = ev-> FD + 1; <br/> dlog ("~~~~ NFDs = % d ~~~~ ", NFDs); <br/> break; <br/>}< br/> mutex_release (); <br/> dlog ("~~~~ -Ril_event_add ~~~~ "); <Br/>}</P> <p> // Add a timer event to the timer_list linked list <br/> void ril_timer_add (struct ril_event * eV, struct timeval * TV) <br/>{< br/> dlog ("~~~~ + Ril_timer_add ~~~~ "); <Br/> mutex_acquire (); </P> <p> struct ril_event * List; <br/> If (TV! = NULL) {<br/> // Add to timer list <br/> List = timer_list.next; <br/> ev-> FD =-1; // make sure FD is invalid </P> <p> struct timeval now; <br/> getnow (& now); <br/> timeradd (& now, TV, & ev-> timeout); </P> <p> // sort the values in the linked list from small to large. <br/> while (timercmp (& list-> timeout, & ev-> timeout, <) <br/> & (list! = & Timer_list) {<br/> List = List-> next; <br/>}< br/> // After the loop ends, list points to the first event with a timeout value greater than eV in the linked list. <br/> // Add the newly added event eV to the beginning of the event pointed to in the list. <br/> addtolist (EV, list); <br/>}</P> <p> mutex_release (); <br/> dlog ("~~~~ -Ril_timer_add ~~~~ "); <Br/>}</P> <p> // remove the event from watch_table [] <br/> void ril_event_del (struct ril_event * eV) <br/> {<br/> dlog ("~~~~ + Ril_event_del ~~~~ "); <Br/> mutex_acquire (); </P> <p> If (ev-> index <0 | ev-> index> = max_fd_events) {<br/> mutex_release (); <br/> return; <br/>}</P> <p> removewatch (EV, ev-> index ); </P> <p> mutex_release (); <br/> dlog ("~~~~ -Ril_event_del ~~~~ "); <Br/>}</P> <p> # If debug <br/> // print the events available in the monitoring list <br/> static void printreadies (fd_set * rfds) <br/> {<br/> for (INT I = 0; (I <max_fd_events); I ++) {<br/> struct ril_event * REV = watch_table [I]; <br/> If (Rev! = NULL & fd_isset (REV-> FD, rfds) {<br/> dlog ("Don: FD = % d is ready", rev-> FD ); <br/>}< br/> # else <br/> # define printreadies (rfds) Do {} while (0) <br/> # endif </P> <p> void ril_event_loop () <br/>{< br/> int N; <br/> fd_set rfds; <br/> struct timeval TV; <br/> struct timeval * PTV; </P> <p> (;;) {<br/> // make local copy of read fd_set <br/> memcpy (& rfds, & readfds, sizeof (fd_set); <br />/// Calculate the wait time of the select function based on timer_list <br/> // The Event timeout time has been sorted before timer_list <br/> If (-1 = calcnexttimeout (& TV )) {<br/> // no pending timers; block indefinitely <br/> dlog ("~~~~ No timers; blocking indefinitely ~~~~ "); <Br/> PTV = NULL; <br/>}else {<br/> dlog ("~~~~ Blocking for % DS + % DUS ~~~~ ", (INT) TV. TV _sec, (INT) TV. TV _usec); <br/> PTV = & TV; <br/>}< br/> printreadies (& rfds ); <br/> // use the select function to achieve multiplexing <br/> N = select (NFDs, & rfds, null, null, PTV ); <br/> printreadies (& rfds); <br/> dlog ("~~~~ % D events fired ~~~~ ", N); <br/> If (n <0) {<br/> If (errno = eintr) continue; </P> <p> LogE ("ril_event: Select error (% d)", errno); <br/> // bail? <Br/> return; <br/>}</P> <p> // check for timeouts <br/> processtimeouts (); <br/> // check for read-ready <br/> processreadies (& rfds, n); <br/> // fire away <br/> firepending (); <br/>}< br/>}

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.