120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang/* 220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * 338ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang * Copyright 2012 Samsung Electronics S.LSI Co. LTD 420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * 520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * Licensed under the Apache License, Version 2.0 (the "License"); 620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * you may not use this file except in compliance with the License. 720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * You may obtain a copy of the License at 820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * 920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * http://www.apache.org/licenses/LICENSE-2.0 1020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * 1120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * Unless required by applicable law or agreed to in writing, software 1220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * distributed under the License is distributed on an "AS IS" BASIS, 1320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * See the License for the specific language governing permissions and 1520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * limitations under the License. 1620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang*/ 1720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 1820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang/* 1920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * @file Exynos_OSAL_Event.c 2020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * @brief 2120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * @author SeungBeom Kim (sbcrux.kim@samsung.com) 2238ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang * @version 2.0.0 2320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang * @history 2438ef2572d26fc760c584a1855a3d002f34eb0231Jiho Chang * 2012.02.20 : Create 2520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang */ 2620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 2720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 2820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang#include <stdio.h> 2920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang#include <stdlib.h> 3020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang#include <string.h> 3120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang#include <pthread.h> 3220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang#include <errno.h> 3320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 3420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang#include "Exynos_OSAL_Memory.h" 3520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang#include "Exynos_OSAL_Mutex.h" 3620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang#include "Exynos_OSAL_Event.h" 3720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 3820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang#undef EXYNOS_LOG_TAG 3920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang#define EXYNOS_LOG_TAG "Exynos_OSAL_EVENT" 4020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang#define EXYNOS_LOG_OFF 4120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang#include "Exynos_OSAL_Log.h" 4220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 4320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 4420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho ChangOMX_ERRORTYPE Exynos_OSAL_SignalCreate(OMX_HANDLETYPE *eventHandle) 4520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang{ 4620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang Exynos_OSAL_THREADEVENT *event; 4720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang OMX_ERRORTYPE ret = OMX_ErrorNone; 4820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 4920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang event = (Exynos_OSAL_THREADEVENT *)Exynos_OSAL_Malloc(sizeof(Exynos_OSAL_THREADEVENT)); 5020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang if (!event) { 5120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = OMX_ErrorInsufficientResources; 5220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang goto EXIT; 5320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang } 5420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 5520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang Exynos_OSAL_Memset(event, 0, sizeof(Exynos_OSAL_THREADEVENT)); 5620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang event->signal = OMX_FALSE; 5720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 5820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = Exynos_OSAL_MutexCreate(&event->mutex); 5920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang if (ret != OMX_ErrorNone) { 6020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang Exynos_OSAL_Free(event); 6120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang goto EXIT; 6220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang } 6320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 6420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang if (pthread_cond_init(&event->condition, NULL)) { 6520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang Exynos_OSAL_MutexTerminate(event->mutex); 6620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang Exynos_OSAL_Free(event); 6720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = OMX_ErrorUndefined; 6820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang goto EXIT; 6920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang } 7020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 7120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang *eventHandle = (OMX_HANDLETYPE)event; 7220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = OMX_ErrorNone; 7320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 7420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho ChangEXIT: 7520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang return ret; 7620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang} 7720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 7820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho ChangOMX_ERRORTYPE Exynos_OSAL_SignalTerminate(OMX_HANDLETYPE eventHandle) 7920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang{ 8020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang Exynos_OSAL_THREADEVENT *event = (Exynos_OSAL_THREADEVENT *)eventHandle; 8120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang OMX_ERRORTYPE ret = OMX_ErrorNone; 8220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 8320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang if (!event) { 8420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = OMX_ErrorBadParameter; 8520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang goto EXIT; 8620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang } 8720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 8820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = Exynos_OSAL_MutexLock(event->mutex); 8920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang if (ret != OMX_ErrorNone) { 9020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = OMX_ErrorBadParameter; 9120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang goto EXIT; 9220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang } 9320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 9420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang if (pthread_cond_destroy(&event->condition)) { 9520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = OMX_ErrorUndefined; 9620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang goto EXIT; 9720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang } 9820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 9920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = Exynos_OSAL_MutexUnlock(event->mutex); 10020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang if (ret != OMX_ErrorNone) { 10120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = OMX_ErrorUndefined; 10220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang goto EXIT; 10320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang } 10420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 10520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = Exynos_OSAL_MutexTerminate(event->mutex); 10620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang if (ret != OMX_ErrorNone) { 10720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = OMX_ErrorUndefined; 10820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang goto EXIT; 10920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang } 11020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 11120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang Exynos_OSAL_Free(event); 11220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 11320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho ChangEXIT: 11420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang return ret; 11520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang} 11620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 11720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho ChangOMX_ERRORTYPE Exynos_OSAL_SignalReset(OMX_HANDLETYPE eventHandle) 11820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang{ 11920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang Exynos_OSAL_THREADEVENT *event = (Exynos_OSAL_THREADEVENT *)eventHandle; 12020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang OMX_ERRORTYPE ret = OMX_ErrorNone; 12120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 12220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang if (!event) { 12320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = OMX_ErrorBadParameter; 12420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang goto EXIT; 12520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang } 12620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 12720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = Exynos_OSAL_MutexLock(event->mutex); 12820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang if (ret != OMX_ErrorNone) { 12920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = OMX_ErrorBadParameter; 13020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang goto EXIT; 13120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang } 13220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 13320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang event->signal = OMX_FALSE; 13420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 13520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang Exynos_OSAL_MutexUnlock(event->mutex); 13620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 13720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho ChangEXIT: 13820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang return ret; 13920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang} 14020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 14120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho ChangOMX_ERRORTYPE Exynos_OSAL_SignalSet(OMX_HANDLETYPE eventHandle) 14220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang{ 14320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang Exynos_OSAL_THREADEVENT *event = (Exynos_OSAL_THREADEVENT *)eventHandle; 14420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang OMX_ERRORTYPE ret = OMX_ErrorNone; 14520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 14620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang if (!event) { 14720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = OMX_ErrorBadParameter; 14820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang goto EXIT; 14920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang } 15020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 15120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = Exynos_OSAL_MutexLock(event->mutex); 15220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang if (ret != OMX_ErrorNone) { 15320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = OMX_ErrorBadParameter; 15420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang goto EXIT; 15520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang } 15620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 15720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang event->signal = OMX_TRUE; 15820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang pthread_cond_signal(&event->condition); 15920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 16020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang Exynos_OSAL_MutexUnlock(event->mutex); 16120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 16220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho ChangEXIT: 16320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang return ret; 16420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang} 16520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 16620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho ChangOMX_ERRORTYPE Exynos_OSAL_SignalWait(OMX_HANDLETYPE eventHandle, OMX_U32 ms) 16720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang{ 16820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang Exynos_OSAL_THREADEVENT *event = (Exynos_OSAL_THREADEVENT *)eventHandle; 16920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang OMX_ERRORTYPE ret = OMX_ErrorNone; 17020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang struct timespec timeout; 17120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang struct timeval now; 17220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang int funcret = 0; 17320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang OMX_U32 tv_us; 17420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 17520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang FunctionIn(); 17620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 17720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang if (!event) { 17820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = OMX_ErrorBadParameter; 17920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang goto EXIT; 18020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang } 18120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 18220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang gettimeofday(&now, NULL); 18320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 18420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang tv_us = now.tv_usec + ms * 1000; 18520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang timeout.tv_sec = now.tv_sec + tv_us / 1000000; 18620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang timeout.tv_nsec = (tv_us % 1000000) * 1000; 18720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 18820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = Exynos_OSAL_MutexLock(event->mutex); 18920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang if (ret != OMX_ErrorNone) { 19020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = OMX_ErrorBadParameter; 19120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang goto EXIT; 19220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang } 19320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 19420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang if (ms == 0) { 19520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang if (!event->signal) 19620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = OMX_ErrorTimeout; 19720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang } else if (ms == DEF_MAX_WAIT_TIME) { 19820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang while (!event->signal) 19920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang pthread_cond_wait(&event->condition, (pthread_mutex_t *)(event->mutex)); 20020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = OMX_ErrorNone; 20120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang } else { 20220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang while (!event->signal) { 20320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang funcret = pthread_cond_timedwait(&event->condition, (pthread_mutex_t *)(event->mutex), &timeout); 20420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang if ((!event->signal) && (funcret == ETIMEDOUT)) { 20520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang ret = OMX_ErrorTimeout; 20620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang break; 20720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang } 20820d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang } 20920d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang } 21020d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 21120d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang Exynos_OSAL_MutexUnlock(event->mutex); 21220d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 21320d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho ChangEXIT: 21420d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang FunctionOut(); 21520d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang 21620d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang return ret; 21720d3e6e3118a6e19627296e9247e948d54ec0fb8Jiho Chang} 218