/* ** Copyright 2006, The Android Open Source Project ** Copyright (c) 2010, Code Aurora Forum. All rights reserved. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #define LOG_TAG "CND_EVENT" #define LOCAL_TAG "CND_EVENT_DEBUG" #include #include #include #include #include #include #include #include #include #include #include #include "cutils/properties.h" #include "cne.h" #include "cnd.h" static pthread_mutex_t listMutex; #define MUTEX_ACQUIRE() pthread_mutex_lock(&listMutex) #define MUTEX_RELEASE() pthread_mutex_unlock(&listMutex) #define MUTEX_INIT() pthread_mutex_init(&listMutex, NULL) #define MUTEX_DESTROY() pthread_mutex_destroy(&listMutex) cneProcessCmdFnType cne_processCommand; cneRegMsgCbFnType cne_regMessageCb; static fd_set readFds; static int nfds = 0; static struct cnd_event * watch_table[MAX_FD_EVENTS]; static struct cnd_event pending_list; static void init_list(struct cnd_event * list) { memset(list, 0, sizeof(struct cnd_event)); list->next = list; list->prev = list; list->fd = -1; } static void addToList(struct cnd_event * ev, struct cnd_event * list) { ev->next = list; ev->prev = list->prev; ev->prev->next = ev; list->prev = ev; } static void removeFromList(struct cnd_event * ev) { ev->next->prev = ev->prev; ev->prev->next = ev->next; ev->next = NULL; ev->prev = NULL; } static void removeWatch(struct cnd_event * ev, int index) { CNE_LOGV("removeWatch: fd=%d, index=%d", ev->fd, index); watch_table[index] = NULL; ev->index = -1; FD_CLR(ev->fd, &readFds); if (ev->fd+1 == nfds) { int n = 0; for (int i = 0; i < MAX_FD_EVENTS; i++) { struct cnd_event * rev = watch_table[i]; if ((rev != NULL) && (rev->fd > n)) { n = rev->fd; } } nfds = n + 1; } } static void processReadReadyEvent(fd_set * rfds, int n) { CNE_LOGV("processReadReadyEvent: n=%d, rfds0=%ld", n, rfds->fds_bits[0]); MUTEX_ACQUIRE(); for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) { struct cnd_event * rev = watch_table[i]; if (rev != NULL) CNE_LOGV("processReadReadyEvent: i=%d, fd=%d, rfds0=%ld", i, rev->fd, rfds->fds_bits[0]); else CNE_LOGV("processReadReadyEvent: i=%d, rev is NULL", i); if (rev != NULL && FD_ISSET(rev->fd, rfds)) { addToList(rev, &pending_list); CNE_LOGV("processReadReadyEvent: add to pendingList fd=%d", rev->fd); if (rev->persist == 0) { removeWatch(rev, i); } n--; } } MUTEX_RELEASE(); } static void firePendingEvent(void) { struct cnd_event * ev = pending_list.next; while (ev != &pending_list) { struct cnd_event * next = ev->next; removeFromList(ev); ev->func(ev->fd, ev->param); ev = next; } } // Initialize internal data structs int cnd_event_init() { MUTEX_INIT(); FD_ZERO(&readFds); init_list(&pending_list); memset(watch_table, 0, sizeof(watch_table)); void* cneLibHandle; cneIntFnType cne_svc_init = NULL; char prop_value[PROPERTY_VALUE_MAX] = {'\0'}; int len = property_get("persist.cne.UseCne", prop_value, "none"); prop_value[len] = '\0'; if(strcasecmp(prop_value, "vendor") == 0) { CNE_LOGV("loading vendor cne library"); cneLibHandle = dlopen("/system/lib/libcne.so",RTLD_NOW); } else { CNE_LOGV("loading refcne library"); cneLibHandle = dlopen("/system/lib/librefcne.so",RTLD_NOW); } if(cneLibHandle != NULL) { cne_svc_init = (cneIntFnType)dlsym(cneLibHandle, "cne_svc_init"); cne_processCommand = (cneProcessCmdFnType)dlsym(cneLibHandle, "cne_processCommand"); cne_regMessageCb = (cneRegMsgCbFnType)dlsym(cneLibHandle, "cne_regMessageCb"); } else { CNE_LOGV("cne library load failed."); } if(cne_svc_init == NULL || cne_processCommand == NULL || cne_regMessageCb == NULL) { CNE_LOGD("dlsym ret'd cne_svc_init=%x cne_processCommand=%x cne_regMessageCb=%x", (unsigned int)cne_svc_init, (unsigned int)cne_processCommand, (unsigned int)cne_regMessageCb); } else { return(cne_svc_init()); } return CNE_SERVICE_DISABLED; } // Initialize an event void cnd_event_set(struct cnd_event * ev, int fd, int persist, cnd_event_cb func, void * param) { memset(ev, 0, sizeof(struct cnd_event)); ev->fd = fd; ev->index = -1; ev->persist = persist; ev->func = func; ev->param = param; fcntl(fd, F_SETFL, O_NONBLOCK); } // Add event to watch list void cnd_event_add(struct cnd_event * ev) { MUTEX_ACQUIRE(); for (int i = 0; i < MAX_FD_EVENTS; i++) { if (watch_table[i] == NULL) { watch_table[i] = ev; ev->index = i; CNE_LOGV("cnd_event_add-before: add at i=%d for fd=%d, readFds0=%ld", i, ev->fd, readFds.fds_bits[0]); FD_SET(ev->fd, &readFds); if (ev->fd >= nfds) nfds = ev->fd+1; CNE_LOGV("cnd_event_add-after: add at i=%d for fd=%d, readFds0=%ld", i, ev->fd, readFds.fds_bits[0]); break; } } MUTEX_RELEASE(); } // Remove event from watch or timer list void cnd_event_del(struct cnd_event * ev) { CNE_LOGV("cnd_event_del: index=%d", ev->index); MUTEX_ACQUIRE(); if (ev->index < 0 || ev->index >= MAX_FD_EVENTS) { return; } removeWatch(ev, ev->index); MUTEX_RELEASE(); } void cnd_dump_watch_table(void) { struct cnd_event * ev; for (int i = 0; i < MAX_FD_EVENTS; i++) { if (watch_table[i] != NULL) { ev = watch_table[i]; CNE_LOGV("cnd_dump_watch_table: at i=%d , fd=%d", i, ev->fd); } } return; } void cnd_event_loop(void) { int n; fd_set rfds; int s_fdCommand; CNE_LOGV("cnd_event_loop: started, nfds=%d",nfds); for (;;) { // make local copy of read fd_set memcpy(&rfds, &readFds, sizeof(fd_set)); CNE_LOGV("cnd_event_loop: waiting for select nfds=%d, rfds0=%ld", nfds, rfds.fds_bits[0]); n = select(nfds, &rfds, NULL, NULL, NULL); if (n < 0) { if (errno == EINTR) continue; CNE_LOGD("cnd_event_loop: select error (%d)", errno); return; } if (n == 0) CNE_LOGV("cnd_event_loop: select timedout"); else if (n > 0) CNE_LOGV("cnd_event_loop: select ok,n=%d, rfds0=%ld",n, rfds.fds_bits[0]); // Check for read-ready events processReadReadyEvent(&rfds, n); // Fire pending event firePendingEvent(); } }