/** * timerThread * * @brief Timer service thread * * This is the start function for the timer server thread. * * @param[in] data - The data passed in (UNUSED) * * @return This function eventually starts an infinite loop on a "select". */ void *timerThread (void *data) { static const char fname[] = "timerThread"; //CPR_INFO("timerThread:started..\n"); #ifndef HOST #ifndef PTHREAD_SET_NAME #define PTHREAD_SET_NAME(s) do { } while (0) #endif PTHREAD_SET_NAME("CPR Timertask"); #endif /* * Increase the timer thread priority from default priority. * This is required to make sure timers fire with reasonable precision. * * NOTE: always make sure the priority is higher than sip/gsm threads; * otherwise, we must use mutex around the following while loop. */ (void) cprAdjustRelativeThreadPriority(TIMER_THREAD_RELATIVE_PRIORITY); /* get ready to listen for timer commands and service them */ if (start_timer_service_loop() == CPR_FAILURE) { CPR_ERROR("%s: timer service loop failed\n", fname); } return NULL; }
/** * * sip_platform_task_loop * * Run the SIP task * * Parameters: arg - SIP message queue * * Return Value: None * */ void sip_platform_task_loop (void *arg) { static const char *fname = "sip_platform_task_loop"; int pending_operations; uint16_t i; fd_set sip_read_fds; fd_set sip_write_fds; sip_tcp_conn_t *entry; sip_msgq = (cprMsgQueue_t) arg; if (!sip_msgq) { CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sip_msgq is null, exiting", fname); return; } sip.msgQueue = sip_msgq; sip_platform_task_init(); /* * Initialize the SIP task */ SIPTaskInit(); if (platThreadInit("SIPStack Task") != 0) { CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to attach thread to JVM", fname); return; } /* * Adjust relative priority of SIP thread. */ (void) cprAdjustRelativeThreadPriority(SIP_THREAD_RELATIVE_PRIORITY); /* * Setup IPC socket addresses for main thread (server) */ { char stmpdir[sizeof(sip_serv_sock_addr.sun_path)]; sip_get_sock_dir(stmpdir, sizeof(stmpdir), SIP_MSG_SERV_SUFFIX); cpr_set_sockun_addr(&sip_serv_sock_addr, stmpdir, 0); } /* * Create IPC between the message queue thread and this main * thread. */ sip_ipc_serv_socket = sip_create_IPC_sock(sip_serv_sock_addr.sun_path); if (sip_ipc_serv_socket == INVALID_SOCKET) { CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sip_create_IPC_sock() failed:" " errno=%d\n", fname, cpr_errno); return; } /* * On Win32 platform, the random seed is stored per thread; therefore, * each thread needs to seed the random number. It is recommended by * MS to do the following to ensure randomness across application * restarts. */ cpr_srand((unsigned int)time(NULL)); /* * Set read IPC socket */ sip_platform_task_set_read_socket(sip_ipc_serv_socket); /* * Let the message queue waiting thread know that the main * thread is ready. */ main_thread_ready = TRUE; /* * Main Event Loop * - Forever-loop exits in sip_process_int_msg()::THREAD_UNLOAD */ while (TRUE) { /* * Wait on events or timeout */ sip_read_fds = read_fds; // start off by init to zero FD_ZERO(&sip_write_fds); // now look for sockets where data has been queued up for (i = 0; i < MAX_CONNECTIONS; i++) { entry = sip_tcp_conn_tab + i; if (-1 != entry->fd && entry->sendQueue && sll_count(entry->sendQueue)) { FD_SET(entry->fd, &sip_write_fds); } } pending_operations = cprSelect((nfds + 1), &sip_read_fds, &sip_write_fds, NULL, NULL); if (pending_operations == SOCKET_ERROR) { CCSIP_DEBUG_ERROR(SIP_F_PREFIX"cprSelect() failed: errno=%d." " Recover by initiating sip restart\n", fname, cpr_errno); /* * If we have come here, then either read socket related to * sip_ipc_serv_socket has got corrupted, or one of the write * socket related to cucm tcp/tls connection. * We will recover, by first clearing all fds, then re-establishing * the connection with sip-msgq by listening on * sip_ipc_serv_socket. */ sip_platform_task_init(); /* this clear FDs */ sip_platform_task_set_read_socket(sip_ipc_serv_socket); /* * Since all sockets fds have been cleared above, we can not anyway * send or receive msg from cucm. So, there is no point * trying to send registration cancel msg to cucm. Also, a * call may be active, and in that case we do not want to * un-register. So, by setting sip_reg_all_failed to true, we * make sure that no registration cancelation attempt is made. */ sip_reg_all_failed = TRUE; platform_reset_req(DEVICE_RESTART); continue; } else if (pending_operations) { /* * Listen socket is set only if UDP transport has been * configured. So see if the select return was for read * on the listen socket. */ if ((listen_socket != INVALID_SOCKET) && (sip.taskInited == TRUE) && FD_ISSET(listen_socket, &sip_read_fds)) { sip_platform_udp_read_socket(listen_socket); pending_operations--; } /* * Check IPC for internal message queue */ if (FD_ISSET(sip_ipc_serv_socket, &sip_read_fds)) { /* read the message to flush the buffer */ sip_process_int_msg(); pending_operations--; } /* * Check all sockets for stuff to do */ for (i = 0; ((i < MAX_SIP_CONNECTIONS) && (pending_operations > 0)); i++) { if ((sip_conn.read[i] != INVALID_SOCKET) && FD_ISSET(sip_conn.read[i], &sip_read_fds)) { /* * Assume tcp */ sip_tcp_read_socket(sip_conn.read[i]); pending_operations--; } if ((sip_conn.write[i] != INVALID_SOCKET) && FD_ISSET(sip_conn.write[i], &sip_write_fds)) { int connid; connid = sip_tcp_fd_to_connid(sip_conn.write[i]); if (connid >= 0) { sip_tcp_resend(connid); } pending_operations--; } } } } }
/** * The function is a thread loop that waits on SIP message queue * visible for the external components (sip_msgq). The thread is used * to avoid having the main task loop from having to set a small time * waiting on select() to poll inter-thread messages. The small waiting * time on select() to poll internal messages queue increases the * unnecessary of waking up when system is idle. On the platform that * power conservative is critical such as handheld phone, waking up * periodically is not good for battery life. * * This thread splits the message queue waiting function from the * main thread waiting on select(). This thread simply listens on the * internal message queue and signal to the main thread via IPC socket * or local socket trigger. Therefore the main thread can uniformly * process internal message event and the network event via select(). * The small internal poll time on select() can be * avoided. * * @param[in] arg - pointer to SIP main thread's message queue. * * @return None. * * @pre (arg != NULL) */ void sip_platform_task_msgqwait (void *arg) { const char *fname = "sip_platform_task_msgqwait"; cprMsgQueue_t *msgq = (cprMsgQueue_t *)arg; unsigned int wait_main_thread = 0; phn_syshdr_t *syshdr; void *msg; uint8_t num_messages = 0; uint8_t response = 0; boolean quit_thread = FALSE; char tempdir[sizeof(sip_serv_sock_addr.sun_path)]; if (msgq == NULL) { CCSIP_DEBUG_ERROR(SIP_F_PREFIX"task msgq is null, exiting", fname); return; } if (platThreadInit("SIP IPCQ task") != 0) { CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to attach thread to JVM", fname); return; } /* * Wait for SIP main thread ready for IPC connection. */ while (!main_thread_ready) { /* Pause for other threads to run while waiting */ cprSleep(SIP_PAUSE_WAIT_IPC_LISTEN_READY_TIME); wait_main_thread++; if (wait_main_thread > SIP_MAX_WAIT_FOR_IPC_LISTEN_READY) { /* Exceed the number of wait time */ CCSIP_DEBUG_ERROR(SIP_F_PREFIX"timeout waiting for listening IPC" " socket ready, exiting\n", fname); return; } } /* * Adjust relative priority of SIP thread. */ (void) cprAdjustRelativeThreadPriority(SIP_THREAD_RELATIVE_PRIORITY); /* * The main thread is ready. set global client socket address * so that the server can send back response. */ sip_get_sock_dir(tempdir, sizeof(tempdir), SIP_MSG_CLNT_SUFFIX); cpr_set_sockun_addr(&sip_clnt_sock_addr, tempdir, 0); sip_ipc_clnt_socket = sip_create_IPC_sock(sip_clnt_sock_addr.sun_path); if (sip_ipc_clnt_socket == INVALID_SOCKET) { CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sip_create_IPC_sock() failed," " exiting\n", fname); return; } while (quit_thread == FALSE) { msg = cprGetMessage(msgq, TRUE, (void **) &syshdr); while (msg != NULL) { /* * There is a message to be forwarded to the main SIP * thread for processing. */ sip_int_msgq_buf[num_messages].msg = msg; sip_int_msgq_buf[num_messages].syshdr = syshdr; num_messages++; switch (syshdr->Cmd) { case THREAD_UNLOAD: thread_ended(THREADMON_MSGQ); quit_thread = TRUE; break; default: break; } if (num_messages == MAX_SIP_MESSAGES) { /* * Limit the number of messages passed to the main SIP * thread to MAX_SIP_MESSAGES since SIP main thread only * process messages up to MAX_SIP_MESSAGES at a time. */ break; } /* * Check to see if there is more message on the queue * before sending IPC message trigger to the main SIP * thread. This is to minimize the overhead of the * the main SIP thread in processing select(). */ msg = cprGetMessage(msgq, 0, (void **) &syshdr); } if (num_messages) { CCSIP_DEBUG_TASK(DEB_F_PREFIX"%d msg available on msgq", DEB_F_PREFIX_ARGS(SIP_MSG_QUE, fname), num_messages); /* * There are some number of messages sent to the main thread, * trigger the main SIP thread via IPC to process the message. */ if (cprSendTo(sip_ipc_clnt_socket, (void *)&num_messages, sizeof(num_messages), 0, (cpr_sockaddr_t *)&sip_serv_sock_addr, cpr_sun_len(sip_serv_sock_addr)) < 0) { CCSIP_DEBUG_ERROR(SIP_F_PREFIX"send IPC failed errno=%d", fname, cpr_errno); } if (FALSE == quit_thread) { /* * Wait for main thread to signal us to get more message. */ if (cprRecvFrom(sip_ipc_clnt_socket, &response, sizeof(response), 0, NULL, NULL) < 0) { CCSIP_DEBUG_ERROR(SIP_F_PREFIX"read IPC failed:" " errno=%d\n", fname, cpr_errno); } num_messages = 0; } } } cprCloseSocket(sip_ipc_clnt_socket); unlink(sip_clnt_sock_addr.sun_path); // removes tmp file }
void GSMTask (void *arg) { static const char fname[] = "GSMTask"; void *msg; phn_syshdr_t *syshdr; boolean release_msg = TRUE; /* * Get the GSM message queue handle * A hack until the tasks in irx are * CPRized. */ gsm_msg_queue = (cprMsgQueue_t) arg; if (!gsm_msg_queue) { GSM_ERR_MSG(GSM_F_PREFIX"invalid input, exiting\n", fname); return; } if (platThreadInit("GSMTask") != 0) { return; } /* * Adjust relative priority of GSM thread. */ (void) cprAdjustRelativeThreadPriority(GSM_THREAD_RELATIVE_PRIORITY); /* * Initialize all the GSM modules */ lsm_init(); fsm_init(); fim_init(); gsm_init(); dcsm_init(); cc_init(); fsmutil_init_shown_calls_ci_map(); /* * On Win32 platform, the random seed is stored per thread; therefore, * each thread needs to seed the random number. It is recommended by * MS to do the following to ensure randomness across application * restarts. */ cpr_srand((unsigned int)time(NULL)); /* * Cache random numbers for SRTP keys */ gsmsdp_cache_crypto_keys(); while (1) { release_msg = TRUE; msg = cprGetMessage(gsm_msg_queue, TRUE, (void **) &syshdr); if (msg) { switch (syshdr->Cmd) { case TIMER_EXPIRATION: gsm_process_timer_expiration(msg); break; case GSM_SIP: case GSM_GSM: release_msg = gsm_process_msg(syshdr->Cmd, msg); break; case DP_MSG_INIT_DIALING: case DP_MSG_DIGIT_STR: case DP_MSG_STORE_DIGIT: case DP_MSG_DIGIT: case DP_MSG_DIAL_IMMEDIATE: case DP_MSG_REDIAL: case DP_MSG_ONHOOK: case DP_MSG_OFFHOOK: case DP_MSG_UPDATE: case DP_MSG_DIGIT_TIMER: case DP_MSG_CANCEL_OFFHOOK_TIMER: dp_process_msg(syshdr->Cmd, msg); break; case SUB_MSG_B2BCNF_SUBSCRIBE_RESP: case SUB_MSG_B2BCNF_NOTIFY: case SUB_MSG_B2BCNF_TERMINATE: sub_process_b2bcnf_msg(syshdr->Cmd, msg); break; case SUB_MSG_FEATURE_SUBSCRIBE_RESP: case SUB_MSG_FEATURE_NOTIFY: case SUB_MSG_FEATURE_TERMINATE: sub_process_feature_msg(syshdr->Cmd, msg); break; case SUB_MSG_KPML_SUBSCRIBE: case SUB_MSG_KPML_TERMINATE: case SUB_MSG_KPML_NOTIFY_ACK: case SUB_MSG_KPML_SUBSCRIBE_TIMER: case SUB_MSG_KPML_DIGIT_TIMER: kpml_process_msg(syshdr->Cmd, msg); break; case REG_MGR_STATE_CHANGE: gsm_reset(); break; case THREAD_UNLOAD: destroy_gsm_thread(); break; default: GSM_ERR_MSG(GSM_F_PREFIX"Unknown message\n", fname); break; } cprReleaseSysHeader(syshdr); if (release_msg == TRUE) { cprReleaseBuffer(msg); } /* Check if there are pending messages for dcsm * if it in the right state perform its operation */ dcsm_process_jobs(); } } }