/* * Function: ccUnload * * Description: * - deinit portable runtime. * - Cleanup call control modules, GSM and SIp Stack * * Parameters: none * * Returns: none * */ void ccUnload (void) { static const char fname[] = "ccUnload"; DEF_DEBUG(DEB_F_PREFIX"ccUnload called..\n", DEB_F_PREFIX_ARGS(SIP_CC_INIT, fname)); if (platform_initialized == FALSE) { TNP_DEBUG(DEB_F_PREFIX"system is not loaded, ignore unload\n", DEB_F_PREFIX_ARGS(SIP_CC_INIT, fname)); return; } /* * We are going to send an unload msg to each of the thread, which on * receiving the msg, will kill itself. */ send_task_unload_msg(CC_SRC_SIP); send_task_unload_msg(CC_SRC_GSM); if (FALSE == gHardCodeSDPMode) { send_task_unload_msg(CC_SRC_MISC_APP); } send_task_unload_msg(CC_SRC_CCAPP); cprSleep(200); gStopTickTask = TRUE; }
int TickerTask (void *a) { TNP_DEBUG(DEB_F_PREFIX"Ticker Task initialized..\n", DEB_F_PREFIX_ARGS(SIP_CC_INIT, "TickerTask")); while (FALSE == gStopTickTask) { cprSleep(20); MAIN0Timer(); } return 0; }
cpr_status_e cprSocketCleanup (void) { if (initialized == FALSE) { return CPR_SUCCESS; } /* wait for all of the sockets to close before cleaning up */ cprSleep(500); if (WSACleanup() == SOCKET_ERROR) { /* startup failed */ return CPR_FAILURE; } initialized = FALSE; return CPR_SUCCESS; }
/** * cpr_timer_pre_init * * @brief Initalize timer service and client IPC * * @return CPR_SUCCESS or CPR_FAILURE */ cprRC_t cpr_timer_pre_init (void) { static const char fname[] = "cpr_timer_pre_init"; int32_t returnCode; /* start the timer service first */ returnCode = (int32_t)pthread_create(&timerThreadId, NULL, timerThread, NULL); if (returnCode == -1) { CPR_ERROR("%s: Failed to create Timer Thread : %s\n", fname, strerror(errno)); return CPR_FAILURE; } /* * wait some time so that timer service thread is up * TBD:we should really implement wait on timerthread using condvar. */ cprSleep(1000); return CPR_SUCCESS; }
/** * 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 }
/** * Place a message on a particular queue. Note that caller may * block (see comments below) * * @param msgQueue - msg queue on which to place the message * @param msg - pointer to the msg to place on the queue * @param ppUserData - pointer to a pointer to user defined data * * @return CPR_SUCCESS or CPR_FAILURE, errno provided * * @note 1. Messages queues are set to be non-blocking, those cases * where the system call fails with a would-block error code * (EAGAIN) the function will attempt other mechanisms described * below. * @note 2. If enabled with an extended message queue, either via a * call to cprCreateMessageQueue with depth value or a call to * cprSetExtendMessageQueueDepth() (when unit testing), the message * will be added to the extended message queue and the call will * return successfully. When room becomes available on the * system's message queue, those messages will be added. * @note 3. If the message queue becomes full and no space is availabe * on the extended message queue, then the function will attempt * to resend the message up to CPR_ATTEMPTS_TO_SEND and the * calling thread will *BLOCK* CPR_SND_TIMEOUT_WAIT_INTERVAL * milliseconds after each failed attempt. If unsuccessful * after all attempts then EGAIN error code is returned. * @note 4. This applies to all CPR threads, including the timer thread. * So it is possible that the timer thread would be forced to * sleep which would have the effect of delaying all active * timers. The work to fix this rare situation is not considered * worth the effort to fix....so just leaving as is. */ cprRC_t cprSendMessage (cprMsgQueue_t msgQueue, void *msg, void **ppUserData) { static const char fname[] = "cprSendMessage"; static const char error_str[] = "%s: Msg not sent to %s queue: %s\n"; cpr_msgq_post_result_e rc; cpr_msg_queue_t *msgq; int16_t attemptsToSend = CPR_ATTEMPTS_TO_SEND; uint16_t numAttempts = 0; /* Bad application? */ if (msgQueue == NULL) { CPR_ERROR(error_str, fname, "undefined", "invalid input"); errno = EINVAL; return CPR_FAILURE; } msgq = (cpr_msg_queue_t *) msgQueue; /* * Attempt to send message */ do { /* * Post the message to the Queue */ rc = cprPostMessage(msgq, msg, ppUserData); if (rc == CPR_MSGQ_POST_SUCCESS) { cprPegSendMessageStats(msgq, numAttempts); return CPR_SUCCESS; } else if (rc == CPR_MSGQ_POST_FAILED) { CPR_ERROR("%s: Msg not sent to %s queue: %d\n", fname, msgq->name, errno); msgq->sendErrors++; /* * If posting to calling thread's own queue, * then peg the self queue error. */ if (pthread_self() == msgq->thread) { msgq->selfQErrors++; } return CPR_FAILURE; } /* * Did not succeed in sending the message, so continue * to attempt up to the CPR_ATTEMPTS_TO_SEND. */ attemptsToSend--; if (attemptsToSend > 0) { /* * Force a context-switch of the thread attempting to * send the message, in order to help the case where * the msg queue is full and the owning thread may get * a a chance be scheduled so it can drain it (Note: * no guarantees, more of a "last-ditch effort" to * recover...especially when temporarily over-whelmed). */ cprSleep(CPR_SND_TIMEOUT_WAIT_INTERVAL); msgq->reTries++; numAttempts++; } } while (attemptsToSend > 0); CPR_ERROR(error_str, fname, msgq->name, "FULL"); msgq->sendErrors++; return CPR_FAILURE; }
/* * Function: send_task_unload_msg * * Description: * - send shutdown and thread destroy msg to sip, gsm, ccapp, misc * threads * Parameters: destination thread * * Returns: none * */ void send_task_unload_msg(cc_srcs_t dest_id) { const char *fname = "send_task_unload_msg"; uint16_t len = 4; cprBuffer_t msg = gsm_get_buffer(len); int sdpmode = 0; config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode)); if (msg == NULL) { err_msg("%s: failed to allocate msg cprBuffer_t\n", fname); return; } DEF_DEBUG(DEB_F_PREFIX"send Unload message to %s task ..\n", DEB_F_PREFIX_ARGS(SIP_CC_INIT, fname), dest_id == CC_SRC_SIP ? "SIP" : dest_id == CC_SRC_GSM ? "GSM" : dest_id == CC_SRC_MISC_APP ? "Misc App" : dest_id == CC_SRC_CCAPP ? "CCApp" : "Unknown"); switch(dest_id) { case CC_SRC_SIP: { /* send this msg so phone can send unRegister msg */ SIPTaskPostShutdown(SIP_EXTERNAL, CC_CAUSE_SHUTDOWN, ""); /* allow unRegister msg to sent out and shutdown to complete */ if (!sdpmode) { cprSleep(2000); } /* send a unload message to the SIP Task to kill sip thread*/ msg = SIPTaskGetBuffer(len); if (msg == NULL) { err_msg("%s:%d: failed to allocate sip msg buffer\n", fname); return; } if (SIPTaskSendMsg(THREAD_UNLOAD, (cprBuffer_t)msg, len, NULL) == CPR_FAILURE) { cpr_free(msg); err_msg("%s: Unable to send THREAD_UNLOAD msg to sip thread", fname); } } break; case CC_SRC_GSM: { msg = gsm_get_buffer(len); if (msg == NULL) { err_msg("%s: failed to allocate gsm msg cprBuffer_t\n", fname); return; } if (CPR_FAILURE == gsm_send_msg(THREAD_UNLOAD, msg, len)) { err_msg("%s: Unable to send THREAD_UNLOAD msg to gsm thread", fname); } } break; case CC_SRC_MISC_APP: { msg = cpr_malloc(len); if (msg == NULL) { err_msg("%s: failed to allocate misc msg cprBuffer_t\n", fname); return; } if (CPR_FAILURE == MiscAppTaskSendMsg(THREAD_UNLOAD, msg, len)) { err_msg("%s: Unable to send THREAD_UNLOAD msg to Misc App thread", fname); } } break; case CC_SRC_CCAPP: { msg = cpr_malloc(len); if (msg == NULL) { err_msg("%s: failed to allocate ccapp msg cprBuffer_t\n", fname); return; } if (ccappTaskPostMsg(CCAPP_THREAD_UNLOAD, msg, len, CCAPP_CCPROVIER) == CPR_FAILURE ) { err_msg("%s: Unable to send THREAD_UNLOAD msg to CCapp thread", fname); } err_msg("%s: send UNLOAD msg to CCapp thread good", fname); } break; default: err_msg("%s: Unknown destination task passed=%d.", fname, dest_id); break; } }