void *
sge_worker_main(void *arg)
{
   bool do_endlessly = true;
   cl_thread_settings_t *thread_config = (cl_thread_settings_t*)arg;
   sge_gdi_ctx_class_t *ctx = NULL;
   monitoring_t monitor;
   monitoring_t *monitorp = &monitor;
   time_t next_prof_output = 0;

   DENTER(TOP_LAYER, "sge_worker_main");

   DPRINTF(("started"));
   cl_thread_func_startup(thread_config);
   sge_monitor_init(&monitor, thread_config->thread_name, GDI_EXT, MT_WARNING, MT_ERROR);
   sge_qmaster_thread_init(&ctx, QMASTER, WORKER_THREAD, true);

   /* register at profiling module */
   set_thread_name(pthread_self(), "Worker Thread");
   conf_update_thread_profiling("Worker Thread");
 
   while (do_endlessly) {
      sge_gdi_packet_class_t *packet = NULL;

      /*
       * Wait for packets. As long as packets are available cancelation 
       * of this thread is ignored. The shutdown procedure in the main 
       * thread takes care that packet producers will be terminated 
       * before all worker threads so that this won't be a problem.
       */
      MONITOR_IDLE_TIME(
         sge_tq_wait_for_task(Master_Task_Queue, 1, SGE_TQ_GDI_PACKET, (void *)&packet),
         &monitor, mconf_get_monitor_time(), mconf_is_monitor_message());

      MONITOR_SET_QLEN((monitorp), sge_tq_get_task_count(Master_Task_Queue));

      if (packet != NULL) {
         sge_gdi_task_class_t *task = packet->first_task;
         bool is_only_read_request = true;

         thread_start_stop_profiling();

#ifdef SEND_ANSWER_IN_LISTENER
#else
         /*
          * prepare buffer for sending an answer 
          */
         if (packet->is_intern_request == false && packet->is_gdi_request == true) {
            init_packbuffer(&(packet->pb), 0, 0);
         }
#endif

         MONITOR_MESSAGES((monitorp));

         if (packet->is_gdi_request == true) {
            /*
             * test if a write lock is necessary
             */
            task = packet->first_task;
            while (task != NULL) {
               u_long32 command = SGE_GDI_GET_OPERATION(task->command); 

               if (command != SGE_GDI_GET) {
                  is_only_read_request = false;
                  break;
               }
               task = task->next;            
            }
         } else {
            is_only_read_request = false;
         }

         /*
          * acquire the correct lock
          */
         if (is_only_read_request) {
            MONITOR_WAIT_TIME(SGE_LOCK(LOCK_GLOBAL, LOCK_READ), monitorp);
         } else {
            MONITOR_WAIT_TIME(SGE_LOCK(LOCK_GLOBAL, LOCK_WRITE), monitorp);
         }

         if (packet->is_gdi_request == true) {
            /*
             * do the GDI request
             */
            task = packet->first_task;
            while (task != NULL) {
               sge_c_gdi(ctx, packet, task, &(task->answer_list), &monitor);

               task = task->next;
            }
         } else {
            task = packet->first_task;
            sge_c_report(ctx, packet->host, packet->commproc, packet->commproc_id, 
                         task->data_list, &monitor);
         }

         /*
          * do unlock
          */
         if (is_only_read_request) {
            SGE_UNLOCK(LOCK_GLOBAL, LOCK_READ)
         } else {
            SGE_UNLOCK(LOCK_GLOBAL, LOCK_WRITE)
         }

         if (packet->is_gdi_request == true) {
#ifdef SEND_ANSWER_IN_LISTENER
            sge_gdi_packet_broadcast_that_handled(packet);
#else
            /*
             * Send the answer to the client
             */
            if (packet->is_intern_request == false) {
               MONITOR_MESSAGES_OUT(monitorp);
               sge_gdi2_send_any_request(ctx, 0, NULL,
                                         packet->host, packet->commproc, packet->commproc_id, 
                                         &(packet->pb), TAG_GDI_REQUEST, 
                                         packet->response_id, NULL);
               clear_packbuffer(&(packet->pb));
#  ifdef BLOCK_LISTENER
               sge_gdi_packet_broadcast_that_handled(packet);
#  else
               sge_gdi_packet_free(&packet);
#  endif
               /*
                * Code only for TS: 
                *
                * Following if-block will only be executed in testsuite if the qmaster
                * parameter __TEST_SLEEP_AFTER_REQUEST is defined. This will block the
                * worker thread if it handled a request. Only this makes sure that
                * other worker threads can handle incoming requests. Otherwise
                * it might be possible that one worker threads handles all requests
                * on fast qmaster hosts if testsuite is not fast enough to generate
                * gdi requests.
                */
               if (mconf_get_enable_test_sleep_after_request() == true) {
                  sleep(5);
               }
            } else {
               sge_gdi_packet_broadcast_that_handled(packet);
               /* this is an internal request, packet will get destroyed later,
                * where the caller waits for the answer
                * make sure it is no longer accessed here
                */
               packet = NULL;
            }
#endif
         } else {
            sge_gdi_packet_free(&packet);
         }
     
         thread_output_profiling("worker thread profiling summary:\n",
                                 &next_prof_output);

         sge_monitor_output(&monitor);
      } else { 
/****** gdi/request_internal/sge_gdi_packet_unpack() *************************
*  NAME
*     sge_gdi_packet_unpack() -- unpacks a GDI packet 
*
*  SYNOPSIS
*     bool 
*     sge_gdi_packet_unpack(sge_gdi_packet_class_t **packet, 
*                           lList **answer_list, sge_pack_buffer *pb) 
*
*  FUNCTION
*     This functions unpacks all data representing a single or multi 
*     GDI request. The information is parsed from the given packing 
*     buffer "pb" and ist stored into "packet". Necessary memory will
*     be allocated.
*
*  INPUTS
*     sge_gdi_packet_class_t ** packet - new GDI packet 
*     lList **answer_list              - answer_list 
*     sge_pack_buffer *pb              - packing buffer 
*
*  RESULT
*     bool - error state
*        true  - success
*        false - error
*
*  NOTES
*     MT-NOTE: sge_gdi_packet_unpack() is MT safe 
*
*  SEE ALSO
*     gdi/request_internal/sge_gdi_packet_get_pb_size() 
*     gdi/request_internal/sge_gdi_packet_pack_task() 
*     gdi/request_internal/sge_gdi_packet_pack()
*******************************************************************************/
bool
sge_gdi_packet_unpack(sge_gdi_packet_class_t **packet, lList **answer_list,
                      sge_pack_buffer *pb)
{
   bool aret = true;
   bool has_next;
   int pack_ret;

   DENTER(TOP_LAYER, "sge_gdi_packet_unpack");
   *packet = sge_gdi_packet_create_base(answer_list);
   if (*packet != NULL) {
      bool first = true;

      do {
         u_long32 target = 0;
         u_long32 command = 0;
         lList *data_list = NULL;
         u_long32 version = 0;
         lList *a_list = NULL;
         lCondition *condition = NULL;
         lEnumeration *enumeration = NULL;
         char *auth_info = NULL;
         u_long32 task_id = 0;
         u_long32 packet_id = 0;
         u_long32 has_next_int = 0;

         if ((pack_ret = unpackint(pb, &(command)))) {
            goto error_with_mapping;
         }
         if ((pack_ret = unpackint(pb, &(target)))) {
            goto error_with_mapping;
         }
         if ((pack_ret = unpackint(pb, &(version)))) {
            goto error_with_mapping;
         }
         /* JG: TODO (322): At this point we should check the version! 
          **                 The existent check function sge_gdi_packet_verify_version
          **                 cannot be called as neccesary data structures are 
          **                 available here (e.g. answer list).
          **                 Better do these changes at a more general place 
          **                 together with (hopefully coming) further communication
          **                 redesign.
          */
         if ((pack_ret = cull_unpack_list(pb, &(data_list)))) {
            goto error_with_mapping;
         }
         if ((pack_ret = cull_unpack_list(pb, &(a_list)))) {
            goto error_with_mapping;
         }
         if ((pack_ret = cull_unpack_cond(pb, &(condition)))) {
            goto error_with_mapping;
         }
         if ((pack_ret = cull_unpack_enum(pb, &(enumeration)))) {
            goto error_with_mapping;
         }
         if ((pack_ret = unpackstr(pb, &(auth_info)))) {
            goto error_with_mapping;
         }
         if ((pack_ret = unpackint(pb, &(task_id)))) {
            goto error_with_mapping;
         }
         if ((pack_ret = unpackint(pb, &(packet_id)))) {
            goto error_with_mapping;
         }
         if ((pack_ret = unpackint(pb, &has_next_int))) {
            goto error_with_mapping;
         }
         has_next = (has_next_int > 0) ? true : false;

         if (first) {
            (*packet)->id = packet_id;
            (*packet)->version = version;
            (*packet)->auth_info = auth_info;
            auth_info = NULL;
            first = false;
         } else {
            auth_info = (char *) sge_free((char *) auth_info);
         }

         /* EB: TODO: ST: cleanup - set last parameter to true */
         aret = sge_gdi_packet_append_task(*packet, &a_list, target,
                                           command, &data_list, &a_list,
                                           &condition, &enumeration,
                                           false, false);
         if (aret == false) {
            goto error;
         }
      } while (has_next);
   }
   DRETURN(aret);
 error_with_mapping:
   aret = sge_gdi_map_pack_errors(pack_ret, answer_list);
 error:
   sge_gdi_packet_free(packet);
   DRETURN(aret);
}