text: /* Copyright (c) 2011, The Linux Foundation. All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are
   * met:
   *     * Redistributions of source code must retain the above copyright
   *       notice, this list of conditions and the following disclaimer.
   *     * Redistributions in binary form must reproduce the above
   *       copyright notice, this list of conditions and the following
   *       disclaimer in the documentation and/or other materials provided
   *       with the distribution.
   *     * Neither the name of The Linux Foundation nor the names of its
   *       contributors may be used to endorse or promote products derived
   *       from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
   * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
   * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
   * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   */
  #include <stdio.h>
  
  #include "log_util.h"
  #include "platform_lib_includes.h"
  #include "loc_eng_dmn_conn_thread_helper.h"
  
  /*===========================================================================
  FUNCTION    thelper_signal_init
  
  DESCRIPTION
     This function will initialize the conditional variable resources.
  
     thelper - thelper instance
  
  DEPENDENCIES
     None
  
  RETURN VALUE
     0: success or negative value for failure
  
  SIDE EFFECTS
     N/A
  
  ===========================================================================*/
  int thelper_signal_init(struct loc_eng_dmn_conn_thelper * thelper)
  {
      int result;
      thelper->thread_exit  = 0;
      thelper->thread_ready = 0;
      result = pthread_cond_init( &thelper->thread_cond, NULL);
      if (result) {
          return result;
      }
  
      result = pthread_mutex_init(&thelper->thread_mutex, NULL);
      if (result) {
          pthread_cond_destroy(&thelper->thread_cond);
      }
      return result;
  }
  
  /*===========================================================================
  FUNCTION
  
  DESCRIPTION
     This function will destroy the conditional variable resources
  
      thelper - pointer to thelper instance
  
  DEPENDENCIES
     None
  
  RETURN VALUE
     0: success or negative value for failure
  
  SIDE EFFECTS
     N/A
  
  ===========================================================================*/
  int thelper_signal_destroy(struct loc_eng_dmn_conn_thelper * thelper)
  {
      int result, ret_result = 0;
      result = pthread_cond_destroy( &thelper->thread_cond);
      if (result) {
          ret_result = result;
      }
  
      result = pthread_mutex_destroy(&thelper->thread_mutex);
      if (result) {
          ret_result = result;
      }
  
      return ret_result;
  }
  
  /*===========================================================================
  FUNCTION    thelper_signal_wait
  
  DESCRIPTION
     This function will be blocked on the conditional variable until thelper_signal_ready
     is called
  
      thelper - pointer to thelper instance
  
  DEPENDENCIES
     None
  
  RETURN VALUE
     0: success or negative value for failure
  
  SIDE EFFECTS
     N/A
  
  ===========================================================================*/
  int thelper_signal_wait(struct loc_eng_dmn_conn_thelper * thelper)
  {
      int result = 0;
  
      pthread_mutex_lock(&thelper->thread_mutex);
      if (!thelper->thread_ready && !thelper->thread_exit) {
          result = pthread_cond_wait(&thelper->thread_cond, &thelper->thread_mutex);
      }
  
      if (thelper->thread_exit) {
          result = -1;
      }
      pthread_mutex_unlock(&thelper->thread_mutex);
  
      return result;
  }
  
  /*===========================================================================
  FUNCTION     thelper_signal_ready
  
  DESCRIPTION
     This function will wake up the conditional variable
  
      thelper - pointer to thelper instance
  
  DEPENDENCIES
     None
  
  RETURN VALUE
     0: success or negative value for failure
  
  SIDE EFFECTS
     N/A
  
  ===========================================================================*/
  int thelper_signal_ready(struct loc_eng_dmn_conn_thelper * thelper)
  {
      int result;
  
      LOC_LOGD("%s:%d] 0x%lx\n", __func__, __LINE__, (long) thelper);
  
      pthread_mutex_lock(&thelper->thread_mutex);
      thelper->thread_ready = 1;
      result = pthread_cond_signal(&thelper->thread_cond);
      pthread_mutex_unlock(&thelper->thread_mutex);
  
      return result;
  }
  
  /*===========================================================================
  FUNCTION     thelper_signal_block
  
  DESCRIPTION
     This function will set the thread ready to 0 to block the thelper_signal_wait
  
      thelper - pointer to thelper instance
  
  DEPENDENCIES
     None
  
  RETURN VALUE
     if thread_ready is set
  
  SIDE EFFECTS
     N/A
  
  ===========================================================================*/
  int thelper_signal_block(struct loc_eng_dmn_conn_thelper * thelper)
  {
      int result = thelper->thread_ready;
  
      LOC_LOGD("%s:%d] 0x%lx\n", __func__, __LINE__, (long) thelper);
  
      pthread_mutex_lock(&thelper->thread_mutex);
      thelper->thread_ready = 0;
      pthread_mutex_unlock(&thelper->thread_mutex);
  
      return result;
  }
  
  /*===========================================================================
  FUNCTION    thelper_main
  
  DESCRIPTION
     This function is the main thread. It will be launched as a child thread
  
      data - pointer to the instance
  
  DEPENDENCIES
     None
  
  RETURN VALUE
     NULL
  
  SIDE EFFECTS
     N/A
  
  ===========================================================================*/
  static void * thelper_main(void *data)
  {
      int result = 0;
      struct loc_eng_dmn_conn_thelper * thelper = (struct loc_eng_dmn_conn_thelper *) data;
  
      if (thelper->thread_proc_init) {
          result = thelper->thread_proc_init(thelper->thread_context);
          if (result < 0) {
              thelper->thread_exit = 1;
              thelper_signal_ready(thelper);
              LOC_LOGE("%s:%d] error: 0x%lx\n", __func__, __LINE__, (long) thelper);
              return NULL;
          }
      }
  
      thelper_signal_ready(thelper);
  
      if (thelper->thread_proc_pre) {
          result = thelper->thread_proc_pre(thelper->thread_context);
          if (result < 0) {
              thelper->thread_exit = 1;
              LOC_LOGE("%s:%d] error: 0x%lx\n", __func__, __LINE__, (long) thelper);
              return NULL;
          }
      }
  
      do {
          if (thelper->thread_proc) {
              result = thelper->thread_proc(thelper->thread_context);
              if (result < 0) {
                  thelper->thread_exit = 1;
                  LOC_LOGE("%s:%d] error: 0x%lx\n", __func__, __LINE__, (long) thelper);
              }
          }
      } while (thelper->thread_exit == 0);
  
      if (thelper->thread_proc_post) {
          result = thelper->thread_proc_post(thelper->thread_context);
      }
  
      if (result != 0) {
          LOC_LOGE("%s:%d] error: 0x%lx\n", __func__, __LINE__, (long) thelper);
      }
      return NULL;
  }
  
  static void thelper_main_2(void *data)
  {
      thelper_main(data);
      return;
  }
  
  
  /*===========================================================================
  FUNCTION    loc_eng_dmn_conn_launch_thelper
  
  DESCRIPTION
     This function will initialize the thread context and launch the thelper_main
  
      thelper - pointer to thelper instance
      thread_proc_init - The initialization function pointer
      thread_proc_pre  - The function to call before task loop and after initialization
      thread_proc      - The task loop
      thread_proc_post - The function to call after the task loop
      context          - the context for the above four functions
  
  DEPENDENCIES
     None
  
  RETURN VALUE
     0: success or negative value for failure
  
  SIDE EFFECTS
     N/A
  
  ===========================================================================*/
  int loc_eng_dmn_conn_launch_thelper(struct loc_eng_dmn_conn_thelper * thelper,
      int (*thread_proc_init) (void * context),
      int (*thread_proc_pre) (void * context),
      int (*thread_proc) (void * context),
      int (*thread_proc_post) (void * context),
      thelper_create_thread   create_thread_cb,
      void * context)
  {
      int result;
  
      thelper_signal_init(thelper);
  
      if (context) {
          thelper->thread_context    = context;
      }
  
      thelper->thread_proc_init  = thread_proc_init;
      thelper->thread_proc_pre   = thread_proc_pre;
      thelper->thread_proc       = thread_proc;
      thelper->thread_proc_post  = thread_proc_post;
  
      LOC_LOGD("%s:%d] 0x%lx call pthread_create\n", __func__, __LINE__, (long) thelper);
      if (create_thread_cb) {
          result = 0;
          thelper->thread_id = create_thread_cb("loc_eng_dmn_conn",
              thelper_main_2, (void *)thelper);
      } else {
          result = pthread_create(&thelper->thread_id, NULL,
              thelper_main, (void *)thelper);
      }
  
      if (result != 0) {
          LOC_LOGE("%s:%d] 0x%lx\n", __func__, __LINE__, (long) thelper);
          return -1;
      }
  
      LOC_LOGD("%s:%d] 0x%lx pthread_create done\n", __func__, __LINE__, (long) thelper);
  
      thelper_signal_wait(thelper);
  
      LOC_LOGD("%s:%d] 0x%lx pthread ready\n", __func__, __LINE__, (long) thelper);
      return thelper->thread_exit;
  }
  
  /*===========================================================================
  FUNCTION    loc_eng_dmn_conn_unblock_thelper
  
  DESCRIPTION
     This function unblocks thelper_main to release the thread
  
      thelper - pointer to thelper instance
  
  DEPENDENCIES
     None
  
  RETURN VALUE
     0: success
  
  SIDE EFFECTS
     N/A
  
  ===========================================================================*/
  int loc_eng_dmn_conn_unblock_thelper(struct loc_eng_dmn_conn_thelper * thelper)
  {
      LOC_LOGD("%s:%d] 0x%lx\n", __func__, __LINE__, (long) thelper);
      thelper->thread_exit = 1;
      return 0;
  }
  
  /*===========================================================================
  FUNCTION    loc_eng_dmn_conn_join_thelper
  
      thelper - pointer to thelper instance
  
  DESCRIPTION
     This function will wait for the thread of thelper_main to finish
  
  DEPENDENCIES
     None
  
  RETURN VALUE
     0: success or negative value for failure
  
  SIDE EFFECTS
     N/A
  
  ===========================================================================*/
  int loc_eng_dmn_conn_join_thelper(struct loc_eng_dmn_conn_thelper * thelper)
  {
      int result;
  
      LOC_LOGD("%s:%d] 0x%lx\n", __func__, __LINE__, (long) thelper);
      result = pthread_join(thelper->thread_id, NULL);
      if (result != 0) {
          LOC_LOGE("%s:%d] 0x%lx\n", __func__, __LINE__, (long) thelper);
      }
      LOC_LOGD("%s:%d] 0x%lx\n", __func__, __LINE__, (long) thelper);
  
      thelper_signal_destroy(thelper);
  
      return result;
  }
  
  