~ubuntu-branches/ubuntu/utopic/gridengine/utopic

« back to all changes in this revision

Viewing changes to source/daemons/qmaster/sge_thread_jvm.c

  • Committer: Bazaar Package Importer
  • Author(s): Mark Hymers
  • Date: 2008-06-25 22:36:13 UTC
  • Revision ID: james.westby@ubuntu.com-20080625223613-tvd9xlhuoct9kyhm
Tags: upstream-6.2~beta2
ImportĀ upstreamĀ versionĀ 6.2~beta2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*___INFO__MARK_BEGIN__*/
 
2
/*************************************************************************
 
3
 * 
 
4
 *  The Contents of this file are made available subject to the terms of
 
5
 *  the Sun Industry Standards Source License Version 1.2
 
6
 * 
 
7
 *  Sun Microsystems Inc., March, 2001
 
8
 * 
 
9
 * 
 
10
 *  Sun Industry Standards Source License Version 1.2
 
11
 *  =================================================
 
12
 *  The contents of this file are subject to the Sun Industry Standards
 
13
 *  Source License Version 1.2 (the "License"); You may not use this file
 
14
 *  except in compliance with the License. You may obtain a copy of the
 
15
 *  License at http://gridengine.sunsource.net/Gridengine_SISSL_license.html
 
16
 * 
 
17
 *  Software provided under this License is provided on an "AS IS" basis,
 
18
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 
19
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 
20
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 
21
 *  See the License for the specific provisions governing your rights and
 
22
 *  obligations concerning the Software.
 
23
 * 
 
24
 *   The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 
25
 * 
 
26
 *   Copyright: 2003 by Sun Microsystems, Inc.
 
27
 * 
 
28
 *   All Rights Reserved.
 
29
 * 
 
30
 ************************************************************************/
 
31
/*___INFO__MARK_END__*/
 
32
 
 
33
#include <signal.h>
 
34
#include <pthread.h>
 
35
#include <string.h>
 
36
#include <errno.h>
 
37
#include <fcntl.h>
 
38
 
 
39
#ifndef NO_JNI
 
40
 
 
41
#include "basis_types.h"
 
42
#include "sge_qmaster_threads.h"
 
43
#include "sgermon.h"
 
44
#include "sge_mt_init.h"
 
45
#include "sge_prog.h"
 
46
#include "sge_log.h"
 
47
#include "sge_unistd.h"
 
48
#include "sge_answer.h"
 
49
#include "setup_qmaster.h"
 
50
#include "sge_security.h"
 
51
#include "sge_manop.h"
 
52
#include "sge_mtutil.h"
 
53
#include "sge_lock.h"
 
54
#include "sge_qmaster_process_message.h"
 
55
#include "sge_event_master.h"
 
56
#include "sge_persistence_qmaster.h"
 
57
#include "sge_reporting_qmaster.h"
 
58
#include "sge_qmaster_timed_event.h"
 
59
#include "sge_host_qmaster.h"
 
60
#include "sge_userprj_qmaster.h"
 
61
#include "sge_give_jobs.h"
 
62
#include "sge_all_listsL.h"
 
63
#include "sge_calendar_qmaster.h"
 
64
#include "sge_time.h"
 
65
#include "lock.h"
 
66
#include "qmaster_heartbeat.h"
 
67
#include "shutdown.h"
 
68
#include "sge_spool.h"
 
69
#include "cl_commlib.h"
 
70
#include "sge_uidgid.h"
 
71
#include "sge_bootstrap.h"
 
72
#include "msg_common.h"
 
73
#include "msg_qmaster.h"
 
74
#include "msg_daemons_common.h"
 
75
#include "msg_utilib.h"  /* remove once 'sge_daemonize_qmaster' did become 'sge_daemonize' */
 
76
#include "sge.h"
 
77
#include "sge_qmod_qmaster.h"
 
78
#include "reschedule.h"
 
79
#include "sge_job_qmaster.h"
 
80
#include "sge_profiling.h"
 
81
#include "sgeobj/sge_conf.h"
 
82
#include "qm_name.h"
 
83
#include "setup_path.h"
 
84
#include "sge_advance_reservation_qmaster.h"
 
85
#include "sge_sched_process_events.h"
 
86
#include "sge_follow.h"
 
87
#include "configuration_qmaster.h"
 
88
#include "sge_thread_main.h"
 
89
#include "sge_thread_jvm.h"
 
90
 
 
91
#include "uti/sge_os.h"
 
92
#include "uti/sge_string.h"
 
93
#include "uti/sge_thread_ctrl.h"
 
94
#include "uti/sge_dstring.h"
 
95
 
 
96
#include "sgeobj/config.h"
 
97
 
 
98
 
 
99
master_jvm_class_t Master_Jvm = {
 
100
   PTHREAD_MUTEX_INITIALIZER,
 
101
   PTHREAD_COND_INITIALIZER,
 
102
   false,
 
103
   0,
 
104
   true,
 
105
   false
 
106
};
 
107
 
 
108
static bool shutdown_main(void);
 
109
static void *sge_jvm_main(void *arg);
 
110
 
 
111
/****** qmaster/threads/sge_jvm_terminate() ***********************************
 
112
*  NAME
 
113
*     sge_jvm_terminate() -- trigger termination of JVM 
 
114
*
 
115
*  SYNOPSIS
 
116
*     void sge_jvm_terminate(sge_gdi_ctx_class_t *ctx) 
 
117
*
 
118
*  FUNCTION
 
119
*     A call of this function triggers the termination of the JVM thread .
 
120
*  
 
121
*     If ther JVM is running then JVM will be notified to terminate.
 
122
*     The thread running the JVM will get a cancel signal.
 
123
*
 
124
*     If the JVM should be running but if it was not able to start due
 
125
*     to some reason (missing library; wrong jvm parameters; ...) then
 
126
*     the JVM thread is waiting only for a termination call which will be 
 
127
*     send by this function.
 
128
*
 
129
*     'Master_Scheduler' is accessed by this function.
 
130
*
 
131
*  INPUTS
 
132
*     sge_gdi_ctx_class_t *ctx - context object 
 
133
*     lList **answer_list      - answer list
 
134
*
 
135
*  RESULT
 
136
*     void - None
 
137
*
 
138
*  NOTES
 
139
*     MT-NOTE: sge_jvm_terminate() is MT safe 
 
140
*
 
141
*  SEE ALSO
 
142
*     qmaster/threads/sge_jvm_initialize() 
 
143
*     qmaster/threads/sge_jvm_cleanup_thread() 
 
144
*     qmaster/threads/sge_jvm_terminate() 
 
145
*     qmaster/threads/sge_jvm_wait_for_terminate()
 
146
*     qmaster/threads/sge_jvm_main() 
 
147
*******************************************************************************/
 
148
void
 
149
sge_jvm_terminate(sge_gdi_ctx_class_t *ctx, lList **answer_list)
 
150
{
 
151
 
 
152
   DENTER(TOP_LAYER, "sge_jvm_terminate");
 
153
 
 
154
   sge_mutex_lock("master jvm struct", SGE_FUNC, __LINE__, &(Master_Jvm.mutex));
 
155
 
 
156
   if (Master_Jvm.is_running) {
 
157
      pthread_t thread_id; 
 
158
      cl_thread_settings_t* thread = NULL;
 
159
 
 
160
      /*
 
161
       * store thread id to use it later on
 
162
       */
 
163
      thread = cl_thread_list_get_first_thread(Main_Control.jvm_thread_pool);
 
164
      thread_id = *(thread->thread_pointer);
 
165
 
 
166
      /* 
 
167
       * send cancel signal
 
168
       * trigger shutdown in the JVM
 
169
       * and signal the continuation to realease the JVM thread if it was unable to setup the JVM 
 
170
       */
 
171
      pthread_cancel(thread_id);
 
172
      shutdown_main();
 
173
      Master_Jvm.shutdown_started = true;
 
174
      pthread_cond_broadcast(&Master_Jvm.cond_var);
 
175
 
 
176
      /*
 
177
       * cl_thread deletion and cl_thread_pool deletion will be done at 
 
178
       * JVM threads cancelation point in sge_jvm_cleanup_thread() ...
 
179
       * ... therefore we have nothing more to do.
 
180
       */
 
181
      sge_mutex_unlock("master jvm struct", SGE_FUNC, __LINE__, &(Master_Jvm.mutex));
 
182
 
 
183
      /* 
 
184
       * after releasing the lock it is safe to wait for the termination. 
 
185
       * doing this inside the critical section (before the lock) could 
 
186
       * rise a deadlock situtaion this function would be called within a GDI request!
 
187
       */
 
188
      pthread_join(thread_id, NULL);
 
189
 
 
190
      INFO((SGE_EVENT, MSG_THREAD_XTERMINATED_S, threadnames[JVM_THREAD]));
 
191
      answer_list_add(answer_list, SGE_EVENT, STATUS_EUNKNOWN, ANSWER_QUALITY_INFO);
 
192
   } else {
 
193
      sge_mutex_unlock("master jvm struct", SGE_FUNC, __LINE__, &(Master_Jvm.mutex));
 
194
 
 
195
      ERROR((SGE_EVENT, MSG_THREAD_XNOTRUNNING_S, threadnames[JVM_THREAD]));
 
196
      answer_list_add(answer_list, SGE_EVENT, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR);
 
197
   }
 
198
 
 
199
   DRETURN_VOID;
 
200
}
 
201
 
 
202
/****** qmaster/threads/sge_jvm_initialize() ************************************
 
203
*  NAME
 
204
*     sge_jvm_initialize() -- setup and start the JVM thread 
 
205
*
 
206
*  SYNOPSIS
 
207
*     void sge_jvm_initialize(sge_gdi_ctx_class_t *ctx) 
 
208
*
 
209
*  FUNCTION
 
210
*     A call to this function initializes the JVM thread if it is not
 
211
*     already running.
 
212
*
 
213
*     The first call to this function (during qmaster start) starts
 
214
*     the JVM thread only if it is enabled in bootstrap configuration
 
215
*     file. Otherwise the JVM will not be started.
 
216
*
 
217
*     Each subsequent call (triggered via GDI) will definitely try to
 
218
*     start the JVM tread if it is not running.
 
219
*
 
220
*     Main routine for the created thread is sge_jvm_main().
 
221
*
 
222
*     'Master_Jvm' is accessed by this function.
 
223
*
 
224
*  INPUTS
 
225
*     sge_gdi_ctx_class_t *ctx - context object 
 
226
*     lList **answer_list      - answer list
 
227
*
 
228
*  RESULT
 
229
*     void - None
 
230
*
 
231
*  NOTES
 
232
*     MT-NOTE: sge_jvm_initialize() is MT safe 
 
233
*
 
234
*  SEE ALSO
 
235
*     qmaster/threads/sge_jvm_initialize() 
 
236
*     qmaster/threads/sge_jvm_cleanup_thread() 
 
237
*     qmaster/threads/sge_jvm_terminate() 
 
238
*     qmaster/threads/sge_jvm_wait_for_terminate()
 
239
*     qmaster/threads/sge_jvm_main() 
 
240
*******************************************************************************/
 
241
void
 
242
sge_jvm_initialize(sge_gdi_ctx_class_t *ctx, lList **answer_list)
 
243
{
 
244
   DENTER(TOP_LAYER, "sge_jvm_initialize");
 
245
 
 
246
   sge_mutex_lock("master jvm struct", SGE_FUNC, __LINE__, &(Master_Jvm.mutex));
 
247
  
 
248
   if (Master_Jvm.is_running == false) {
 
249
      bool start_thread = true;
 
250
 
 
251
      /* 
 
252
       * when this function is called the first time we will use the setting from
 
253
       * the bootstrap file to identify if the Jvm should be started or not
 
254
       * otherwise we have to start the thread due to a manual request through GDI.
 
255
       * There is no option. We have to start it.
 
256
       */
 
257
      if (Master_Jvm.use_bootstrap == true) {
 
258
         start_thread = ((ctx->get_jvm_thread_count(ctx) > 0) ? true : false);
 
259
         Master_Jvm.use_bootstrap = false;
 
260
      }
 
261
 
 
262
      if (start_thread == true) {
 
263
         cl_thread_settings_t* dummy_thread_p = NULL;
 
264
         dstring thread_name = DSTRING_INIT;
 
265
 
 
266
         /*
 
267
          * initialize the thread pool
 
268
          */
 
269
         cl_thread_list_setup(&(Main_Control.jvm_thread_pool), "thread pool");
 
270
  
 
271
         /* 
 
272
          * prepare a unique jvm thread name for each instance 
 
273
          */
 
274
         sge_dstring_sprintf(&thread_name, "%s%03d", threadnames[JVM_THREAD],
 
275
                             Master_Jvm.thread_id);
 
276
 
 
277
         /*
 
278
          * start the JVM thread 
 
279
          */
 
280
         cl_thread_list_create_thread(Main_Control.jvm_thread_pool, &dummy_thread_p,
 
281
                                      NULL, sge_dstring_get_string(&thread_name),
 
282
                                      Master_Jvm.thread_id, sge_jvm_main, NULL, NULL);
 
283
         sge_dstring_free(&thread_name);
 
284
 
 
285
         /*
 
286
          * Increase the thread id so that the next instance of a jvm will have a 
 
287
          * different name and flag that jvm is running and that shutdown has not been
 
288
          * triggered
 
289
          */
 
290
         Master_Jvm.shutdown_started = false;
 
291
         Master_Jvm.thread_id++;
 
292
         Master_Jvm.is_running = true;
 
293
 
 
294
         INFO((SGE_EVENT, MSG_THREAD_XHASSTARTED_S, threadnames[JVM_THREAD]));
 
295
         answer_list_add(answer_list, SGE_EVENT, STATUS_EUNKNOWN, ANSWER_QUALITY_INFO);
 
296
      } else {
 
297
         INFO((SGE_EVENT, MSG_THREAD_XSTARTDISABLED_S, threadnames[JVM_THREAD]));
 
298
         answer_list_add(answer_list, SGE_EVENT, STATUS_EUNKNOWN, ANSWER_QUALITY_INFO);
 
299
      }
 
300
   } else {
 
301
      ERROR((SGE_EVENT, MSG_THREAD_XISRUNNING_S, threadnames[JVM_THREAD]));
 
302
      answer_list_add(answer_list, SGE_EVENT, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR);
 
303
   }
 
304
   sge_mutex_unlock("master jvm struct", SGE_FUNC, __LINE__, &(Master_Jvm.mutex));
 
305
 
 
306
   DRETURN_VOID;
 
307
}
 
308
 
 
309
 
 
310
#include <jni.h>
 
311
 
 
312
#ifdef LINUX
 
313
#ifndef __USE_GNU
 
314
#define __USE_GNU
 
315
#endif
 
316
#endif
 
317
 
 
318
#include <dlfcn.h>
 
319
#include <string.h>
 
320
 
 
321
#ifdef LINUX
 
322
#ifdef __USE_GNU
 
323
#undef __USE_GNU
 
324
#endif
 
325
#endif
 
326
 
 
327
#ifdef SOLARIS
 
328
#include <link.h>
 
329
#endif
 
330
 
 
331
typedef int (*JNI_CreateJavaVM_Func)(JavaVM **pvm, void **penv, void *args);
 
332
typedef int (*JNI_GetCreatedJavaVMs_Func)(JavaVM **pvm, jsize size, jsize *real_size);
 
333
 
 
334
static void *libjvm_handle = NULL;
 
335
static JNI_CreateJavaVM_Func sge_JNI_CreateJavaVM = NULL;
 
336
static JNI_GetCreatedJavaVMs_Func sge_JNI_GetCreatedJavaVMs = NULL;
 
337
static pthread_mutex_t libjvm_mutex = PTHREAD_MUTEX_INITIALIZER;
 
338
 
 
339
static JavaVM* myjvm = NULL;
 
340
static pthread_mutex_t myjvm_mutex = PTHREAD_MUTEX_INITIALIZER;
 
341
 
 
342
static JNIEnv* create_vm(const char *libjvm_path, int argc, char** argv);
 
343
static int invoke_main(JNIEnv* env, jclass main_class, int argc, char** argv);
 
344
 
 
345
 
 
346
#ifdef DARWIN
 
347
int JNI_CreateJavaVM_Impl(JavaVM **pvm, void **penv, void *args);
 
348
#endif
 
349
 
 
350
static bool
 
351
sge_run_jvm(sge_gdi_ctx_class_t *ctx, void *anArg, monitoring_t *monitor);
 
352
 
 
353
static void
 
354
sge_jvm_cleanup_monitor(monitoring_t *monitor)
 
355
{
 
356
   DENTER(TOP_LAYER, "cleanup_monitor");
 
357
   sge_monitor_free(monitor);
 
358
   DRETURN_VOID;
 
359
}
 
360
 
 
361
/*-------------------------------------------------------------------------*
 
362
 * NAME
 
363
 *   shutdown_main - invoke the shutdown method of com.sun.grid.jgdi.management.JGDIAgent
 
364
 * PARAMETER
 
365
 *  env  - the JNI environment
 
366
 *  argc - number of arguments for the main method
 
367
 *  argv - the arguments for the main method
 
368
 *
 
369
 * RETURN
 
370
 *
 
371
 *  exit code of the JVM
 
372
 *
 
373
 * EXTERNAL
 
374
 *
 
375
 * DESCRIPTION
 
376
 *-------------------------------------------------------------------------*/
 
377
static bool shutdown_main(void) 
 
378
{
 
379
   char main_class_name[] = "com/sun/grid/jgdi/management/JGDIAgent";
 
380
        jmethodID shutdown_mid = NULL;
 
381
   JNIEnv *env;
 
382
   jclass main_class;
 
383
   int ret = 0;
 
384
   bool error_occured = false;
 
385
   JavaVMAttachArgs attach_args = { JNI_VERSION_1_2, NULL, NULL };
 
386
 
 
387
   DENTER(TOP_LAYER, "shutdown_main");
 
388
 
 
389
   pthread_mutex_lock(&myjvm_mutex);
 
390
 
 
391
   if (myjvm == NULL) {
 
392
      pthread_mutex_unlock(&myjvm_mutex);
 
393
      DRETURN(true);
 
394
   }
 
395
 
 
396
   ret = (*myjvm)->AttachCurrentThread(myjvm, (void**) &env, &attach_args);
 
397
 
 
398
   if (ret < 0) { 
 
399
      CRITICAL((SGE_EVENT, "could not attach thread to vm\n"));
 
400
      pthread_mutex_unlock(&myjvm_mutex);
 
401
      DRETURN(false);
 
402
   }   
 
403
 
 
404
   if (env != NULL) {
 
405
      main_class = (*env)->FindClass(env, main_class_name);
 
406
      if (main_class != NULL) {
 
407
              shutdown_mid = (*env)->GetStaticMethodID(env, main_class, "shutdown", "()V");
 
408
         if (shutdown_mid == NULL) {
 
409
            CRITICAL((SGE_EVENT, "class has no shutdown method\n"));
 
410
            error_occured = true;
 
411
         }
 
412
      } else {
 
413
         CRITICAL((SGE_EVENT, "main_class is NULL\n"));
 
414
         error_occured = true;
 
415
      }  
 
416
 
 
417
      if (!error_occured) {
 
418
         (*env)->CallStaticVoidMethod(env, main_class, shutdown_mid);
 
419
 
 
420
         if ((*env)->ExceptionOccurred(env)) {
 
421
            (*env)->ExceptionClear(env);
 
422
            CRITICAL((SGE_EVENT, "unexpected jvm exception\n"));
 
423
            error_occured = true;
 
424
         }
 
425
      }   
 
426
   }
 
427
 
 
428
   ret = (*myjvm)->DetachCurrentThread(myjvm);
 
429
   if (ret < 0) { 
 
430
      CRITICAL((SGE_EVENT, "could not detach thread from vm\n"));
 
431
      error_occured = true;
 
432
   }   
 
433
 
 
434
   pthread_mutex_unlock(&myjvm_mutex);
 
435
 
 
436
   if (error_occured) {
 
437
      DRETURN(false);
 
438
   } else {
 
439
      DRETURN(true);
 
440
   }
 
441
}
 
442
 
 
443
static jint (JNICALL printVMErrors)(FILE *fp, const char *format, va_list args) {
 
444
   jint rc = 0;
 
445
   const char* str = NULL;
 
446
   dstring ds = DSTRING_INIT;
 
447
 
 
448
   DENTER(TOP_LAYER, "printVMErrors");
 
449
   str = sge_dstring_vsprintf(&ds, format, args);
 
450
   if (str != NULL) {
 
451
      rc = strlen(str);
 
452
      DPRINTF(("%s\n", str));
 
453
      CRITICAL((SGE_EVENT, "JVM message: %s", str));
 
454
   }
 
455
   sge_dstring_free(&ds);
 
456
   DRETURN(rc);
 
457
}
 
458
 
 
459
#if 0
 
460
static void (JNICALL exitVM)(jint code) {
 
461
    DENTER(TOP_LAYER, "exitVM");
 
462
    DPRINTF(("CALLED exitVM %d\n", (int)code));
 
463
    fflush(stdout);
 
464
    DRETURN_VOID;
 
465
}
 
466
#endif
 
467
 
 
468
 
 
469
/*-------------------------------------------------------------------------*
 
470
 * NAME
 
471
 *   create_vm - create a jvm
 
472
 * PARAMETER
 
473
 *  argc - number of arguments for the jvm
 
474
 *  argv - arguments for the jvm
 
475
 *
 
476
 * RETURN
 
477
 *
 
478
 *   NULL -  jvm could not be created
 
479
 *   else -  jvm has been created
 
480
 *
 
481
 * EXTERNAL
 
482
 *
 
483
 * DESCRIPTION
 
484
 * #if 0
 
485
 *   options[1].optionString = "exit";
 
486
 *   options[1].extraInfo = exitVM;
 
487
 * #endif   
 
488
 *-------------------------------------------------------------------------*/
 
489
static JNIEnv* create_vm(const char *libjvm_path, int argc, char** argv)
 
490
{
 
491
   bool ok = true;
 
492
        JNIEnv* env = NULL;
 
493
        JavaVMInitArgs args;
 
494
   int i = 0;
 
495
        JavaVMOption* options = NULL;
 
496
   const int extraOptionCount = 1;
 
497
 
 
498
   DENTER(GDI_LAYER, "create_vm");
 
499
 
 
500
   options = (JavaVMOption*)malloc((argc+extraOptionCount)*sizeof(JavaVMOption));
 
501
 
 
502
        /* There is a new JNI_VERSION_1_4, but it doesn't add anything for the purposes of our example. */
 
503
        args.version = JNI_VERSION_1_2;
 
504
        args.nOptions = argc+extraOptionCount;
 
505
   options[0].optionString = "vfprintf";
 
506
   options[0].extraInfo = (void*)printVMErrors;
 
507
   for(i=0; i < argc; i++) {
 
508
      /*printf("argv[%d] = %s\n", i, argv[i]);*/
 
509
      options[i+extraOptionCount].optionString = argv[i];
 
510
   }
 
511
 
 
512
        args.options = options;
 
513
        args.ignoreUnrecognized = JNI_FALSE;
 
514
 
 
515
   pthread_mutex_lock(&libjvm_mutex);
 
516
   if (libjvm_handle == NULL) {
 
517
      /* build the full name of the shared lib - append architecture dependent
 
518
       * shlib postfix 
 
519
       */
 
520
#ifdef HP1164
 
521
      /*
 
522
      ** need to switch to start user for HP
 
523
      */
 
524
      sge_switch2start_user();
 
525
#endif   
 
526
 
 
527
      /* open the shared lib */
 
528
      # if defined(DARWIN)
 
529
      # ifdef RTLD_NODELETE
 
530
      libjvm_handle = dlopen(libjvm_path, RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE);
 
531
      # else
 
532
      libjvm_handle = dlopen(libjvm_path, RTLD_NOW | RTLD_GLOBAL );
 
533
      # endif /* RTLD_NODELETE */
 
534
      # elif defined(HP11) || defined(HP1164)
 
535
      # ifdef RTLD_NODELETE
 
536
      libjvm_handle = dlopen(libjvm_path, RTLD_LAZY | RTLD_NODELETE);
 
537
      # else
 
538
      libjvm_handle = dlopen(libjvm_path, RTLD_LAZY );
 
539
      # endif /* RTLD_NODELETE */
 
540
      # else
 
541
      # ifdef RTLD_NODELETE
 
542
      libjvm_handle = dlopen(libjvm_path, RTLD_LAZY | RTLD_NODELETE);
 
543
      # else
 
544
      libjvm_handle = dlopen(libjvm_path, RTLD_LAZY);
 
545
      # endif /* RTLD_NODELETE */
 
546
      #endif
 
547
 
 
548
#ifdef HP1164
 
549
      /*
 
550
      ** switch back to admin user for HP
 
551
      */
 
552
      sge_switch2admin_user();
 
553
#endif
 
554
      if (libjvm_handle == NULL) {
 
555
         CRITICAL((SGE_EVENT, "could not load libjvm %s", dlerror()));
 
556
         ok = false;
 
557
      }
 
558
 
 
559
      /* retrieve function pointer of get_method function in shared lib */
 
560
      if (ok) {
 
561
#ifdef DARWIN
 
562
         /*
 
563
         ** for darwin there exists no JNI_CreateJavaVM, Why not maybe a fix in the future ???
 
564
         */
 
565
         const char* JNI_CreateJavaVM_FuncName = "JNI_CreateJavaVM_Impl";
 
566
         const char* JNI_GetCreatedJavaVMs_FuncName = "JNI_GetCreatedJavaVMs_Impl";
 
567
#else
 
568
         const char* JNI_CreateJavaVM_FuncName = "JNI_CreateJavaVM";
 
569
         const char* JNI_GetCreatedJavaVMs_FuncName = "JNI_GetCreatedJavaVMs";
 
570
#endif
 
571
         sge_JNI_CreateJavaVM = (JNI_CreateJavaVM_Func)dlsym(libjvm_handle, JNI_CreateJavaVM_FuncName);
 
572
         if (sge_JNI_CreateJavaVM == NULL) {
 
573
            CRITICAL((SGE_EVENT, "could not load sge_JNI_CreateJavaVM %s", dlerror()));
 
574
            ok = false;
 
575
         }
 
576
      
 
577
         sge_JNI_GetCreatedJavaVMs = (JNI_GetCreatedJavaVMs_Func)dlsym(libjvm_handle, JNI_GetCreatedJavaVMs_FuncName);
 
578
         if (sge_JNI_GetCreatedJavaVMs == NULL) {
 
579
            CRITICAL((SGE_EVENT, "could not load sge_JNI_GetCreatedJavaVMs %s", dlerror()));
 
580
            ok = false;
 
581
         }
 
582
      }
 
583
   }
 
584
   pthread_mutex_unlock(&libjvm_mutex);
 
585
 
 
586
 
 
587
   if (ok) {
 
588
      JavaVMAttachArgs attach_args = { JNI_VERSION_1_2, NULL, NULL };
 
589
      jsize have_jvm = 0;
 
590
           JavaVM* jvm = NULL;
 
591
      pthread_mutex_lock(&myjvm_mutex);
 
592
      i = sge_JNI_GetCreatedJavaVMs(&jvm, 1, &have_jvm); 
 
593
 
 
594
      if (have_jvm && jvm != NULL) {
 
595
         if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2) == JNI_EDETACHED) {
 
596
            if ((i = (*jvm)->AttachCurrentThread(jvm, (void**) &env, &attach_args)) < 0) {
 
597
               CRITICAL((SGE_EVENT, "can not get JNIEnv (error code %d)\n", i));
 
598
               env = NULL;
 
599
               myjvm = NULL;
 
600
            } else {
 
601
               myjvm = jvm;
 
602
            }
 
603
         } else {
 
604
            myjvm = jvm;
 
605
         }
 
606
      } else {
 
607
         if ((i = sge_JNI_CreateJavaVM(&jvm, (void **)&env, &args)) < 0) {
 
608
            CRITICAL((SGE_EVENT, "can not create JVM (error code %d)\n", i));
 
609
            env = NULL;
 
610
            myjvm = NULL;
 
611
         } else {
 
612
            myjvm = jvm;
 
613
         }  
 
614
      }
 
615
      pthread_mutex_unlock(&myjvm_mutex);
 
616
 
 
617
   }
 
618
   free(options);
 
619
        DRETURN(env);
 
620
}
 
621
 
 
622
/*-------------------------------------------------------------------------*
 
623
 * NAME
 
624
 *   invoke_main - invoke the main method of com.sun.grid.jgdi.management.JGDIAgent
 
625
 * PARAMETER
 
626
 *  env  - the JNI environment
 
627
 *  argc - number of arguments for the main method
 
628
 *  argv - the arguments for the main method
 
629
 *
 
630
 * RETURN
 
631
 *
 
632
 *  exit code of the JVM
 
633
 *
 
634
 * EXTERNAL
 
635
 *
 
636
 * DESCRIPTION
 
637
 *-------------------------------------------------------------------------*/
 
638
static int invoke_main(JNIEnv* env, jclass main_class, int argc, char** argv) 
 
639
{
 
640
        jmethodID main_mid;
 
641
        jobjectArray main_args;
 
642
   int i = 0;
 
643
 
 
644
   DENTER(TOP_LAYER, "invoke_main");
 
645
   
 
646
        main_mid = (*env)->GetStaticMethodID(env, main_class, "main", "([Ljava/lang/String;)V");
 
647
   if (main_mid == NULL) {
 
648
      CRITICAL((SGE_EVENT, "class has no main method\n"));
 
649
      DRETURN(1);
 
650
   }
 
651
 
 
652
        main_args = (*env)->NewObjectArray(env, argc, (*env)->FindClass(env, "java/lang/String"), NULL);
 
653
   
 
654
   for(i=0; i < argc; i++) {
 
655
      jstring str = (*env)->NewStringUTF(env, argv[i]);
 
656
      DPRINTF(("argv[%d] = %s\n", i, argv[i]));
 
657
      (*env)->SetObjectArrayElement(env, main_args, i, str);
 
658
   }
 
659
 
 
660
   INFO((SGE_EVENT, "Starting up jvm thread\n"));
 
661
        (*env)->CallStaticVoidMethod(env, main_class, main_mid, main_args);
 
662
   
 
663
   if ((*env)->ExceptionOccurred(env)) {
 
664
      (*env)->ExceptionClear(env);
 
665
      CRITICAL((SGE_EVENT, "unexpected exception in invoke_main\n"));
 
666
      DRETURN(1);
 
667
   }
 
668
 
 
669
   DRETURN(0);
 
670
}
 
671
 
 
672
 
 
673
static bool
 
674
sge_run_jvm(sge_gdi_ctx_class_t *ctx, void *anArg, monitoring_t *monitor)
 
675
{
 
676
 
 
677
   dstring ds = DSTRING_INIT;
 
678
   const char *libjvm_path = NULL;
 
679
   char **jvm_argv;
 
680
   int jvm_argc = 0;
 
681
   char *main_argv[1];
 
682
   int i;
 
683
   char main_class_name[] = "com/sun/grid/jgdi/management/JGDIAgent";
 
684
   JNIEnv* env = NULL;
 
685
   jobject main_class = NULL;
 
686
   char* additional_jvm_args = NULL;
 
687
   char** additional_jvm_argv = NULL;
 
688
   int additional_jvm_argc = 0;
 
689
   lListElem *confEntry = NULL;
 
690
   const int fixed_jvm_argc = 16;
 
691
   bool ret = true;
 
692
 
 
693
   DENTER(TOP_LAYER, "sge_run_jvm");
 
694
 
 
695
   confEntry = sge_get_configuration_entry_by_name(ctx->get_qualified_hostname(ctx), "libjvm_path");
 
696
   if (confEntry != NULL) {
 
697
      const char *confVal = lGetString(confEntry, CF_value);
 
698
      if (confVal && *confVal != '\0') {
 
699
         libjvm_path = strdup(confVal);
 
700
      }   
 
701
      lFreeElem(&confEntry);
 
702
   }   
 
703
 
 
704
   if (libjvm_path == NULL) {
 
705
      WARNING((SGE_EVENT, "libjvm_path is NULL\n"));
 
706
      DRETURN(false);
 
707
   }  
 
708
 
 
709
   /*
 
710
   ** get additional jvm args from configuration
 
711
   */
 
712
   confEntry = sge_get_configuration_entry_by_name(ctx->get_qualified_hostname(ctx), "additional_jvm_args");
 
713
   if (confEntry != NULL) {
 
714
      const char *confVal = lGetString(confEntry, CF_value);
 
715
      if (confVal && *confVal != '\0') {
 
716
         additional_jvm_args = strdup(confVal);
 
717
      }
 
718
      lFreeElem(&confEntry);
 
719
   }   
 
720
 
 
721
   if (additional_jvm_args != NULL) {
 
722
        DPRINTF(("additional_jvm_args: >%s<\n", additional_jvm_args));
 
723
        additional_jvm_argv = string_list(additional_jvm_args, " ", NULL);
 
724
 
 
725
        for (i=0; additional_jvm_argv[i] != NULL; i++) {
 
726
           DPRINTF(("additional jvm arg[%d]: %s\n", i, additional_jvm_argv[i]));
 
727
           additional_jvm_argc++;
 
728
        }
 
729
        jvm_argc = fixed_jvm_argc + additional_jvm_argc;
 
730
   } else {
 
731
      additional_jvm_argv = NULL;
 
732
      jvm_argc = fixed_jvm_argc;
 
733
      additional_jvm_argc = 0;
 
734
   }
 
735
 
 
736
   DPRINTF(("fixed_jvm_argc + additional_jvm_argc = jvm_argc: %d + %d = %d\n", fixed_jvm_argc, additional_jvm_argc, jvm_argc));
 
737
  
 
738
   jvm_argv = (char**)sge_malloc(jvm_argc * sizeof(char*));
 
739
   /*
 
740
   ** adjust fixed_jvm_argc if an additional fixed argument line is added
 
741
   */
 
742
   jvm_argv[0] = strdup(sge_dstring_sprintf(&ds, "-Dcom.sun.grid.jgdi.sgeRoot=%s", ctx->get_sge_root(ctx)));
 
743
   jvm_argv[1] = strdup(sge_dstring_sprintf(&ds, "-Dcom.sun.grid.jgdi.sgeCell=%s", ctx->get_default_cell(ctx)));
 
744
   jvm_argv[2] = strdup(sge_dstring_sprintf(&ds, "-Dcom.sun.grid.jgdi.caTop=%s", ctx->get_ca_root(ctx)));
 
745
   jvm_argv[3] = strdup(sge_dstring_sprintf(&ds, "-Dcom.sun.grid.jgdi.serverKeystore=%s/private/keystore", ctx->get_ca_local_root(ctx)));
 
746
   jvm_argv[4] = strdup(sge_dstring_sprintf(&ds, "-Dcom.sun.grid.jgdi.sgeQmasterSpoolDir=%s", ctx->get_qmaster_spool_dir(ctx)));
 
747
   jvm_argv[5] = strdup(sge_dstring_sprintf(&ds, "-Djava.class.path=%s/lib/jgdi.jar:%s/lib/juti.jar", ctx->get_sge_root(ctx), ctx->get_sge_root(ctx)));
 
748
   jvm_argv[6] = strdup(sge_dstring_sprintf(&ds, "-Djava.security.policy=%s/common/jmx/java.policy", ctx->get_cell_root(ctx)));
 
749
   jvm_argv[7] = strdup("-Djava.security.manager=com.sun.grid.jgdi.management.JGDISecurityManager");
 
750
   jvm_argv[8] = strdup(sge_dstring_sprintf(&ds, "-Djava.rmi.server.codebase=file://%s/lib/jgdi.jar file://%s/lib/juti.jar", ctx->get_sge_root(ctx), ctx->get_sge_root(ctx)));
 
751
   jvm_argv[9] = strdup(sge_dstring_sprintf(&ds, "-Djava.library.path=%s/lib/%s", ctx->get_sge_root(ctx), sge_get_arch()));
 
752
   jvm_argv[10] = strdup(sge_dstring_sprintf(&ds, "-Dcom.sun.management.jmxremote.access.file=%s/common/jmx/jmxremote.access", ctx->get_cell_root(ctx)));
 
753
   jvm_argv[11] = strdup(sge_dstring_sprintf(&ds, "-Dcom.sun.management.jmxremote.password.file=%s/common/jmx/jmxremote.password", ctx->get_cell_root(ctx)));
 
754
   jvm_argv[12] = strdup(sge_dstring_sprintf(&ds, "-Djava.security.auth.login.config=%s/common/jmx/jaas.config", ctx->get_cell_root(ctx)));
 
755
   jvm_argv[13] = strdup(sge_dstring_sprintf(&ds, "-Djava.util.logging.config.file=%s/common/jmx/logging.properties", ctx->get_cell_root(ctx)));
 
756
/*    jvm_argv[13] = strdup("-Djava.util.logging.manager=com.sun.grid.jgdi.util.JGDILogManager"); */
 
757
   jvm_argv[14] = strdup("-Djava.util.logging.manager=java.util.logging.LogManager");
 
758
   jvm_argv[15] = strdup("-Xrs");
 
759
 
 
760
   /*
 
761
   ** add additional_jvm_args
 
762
   */
 
763
   for (i=0; i < additional_jvm_argc; i++) {
 
764
      jvm_argv[fixed_jvm_argc+i] = strdup(additional_jvm_argv[i]);
 
765
      additional_jvm_argv[i] = NULL;
 
766
   }
 
767
   FREE(additional_jvm_argv);
 
768
 
 
769
   /*
 
770
   ** process arguments of main method
 
771
   */
 
772
   main_argv[0] = strdup(sge_dstring_sprintf(&ds, "internal://%s@%s:"sge_u32, ctx->get_sge_root(ctx),
 
773
                         ctx->get_default_cell(ctx), ctx->get_sge_qmaster_port(ctx)));
 
774
 
 
775
   sge_dstring_free(&ds);
 
776
 
 
777
 
 
778
   /*
 
779
   ** for debugging
 
780
   */
 
781
   for (i=0; i<jvm_argc; i++) {
 
782
      DPRINTF(("jvm_argv[%d]: %s\n", i, jvm_argv[i]));
 
783
   }  
 
784
 
 
785
   for (i=0; i<sizeof(main_argv)/sizeof(char*); i++) {
 
786
      DPRINTF(("main_argv[%d]: %s\n", i, main_argv[i]));
 
787
   }  
 
788
 
 
789
   env = create_vm(libjvm_path, jvm_argc, jvm_argv);
 
790
   FREE(libjvm_path);
 
791
 
 
792
   if (env != NULL) {
 
793
      main_class = (*env)->FindClass(env, main_class_name);
 
794
      if (main_class != NULL) {
 
795
         if (invoke_main(env, main_class, sizeof(main_argv)/sizeof(char*), main_argv) != 0) {
 
796
            CRITICAL((SGE_EVENT, "invoke_main failed\n"));
 
797
            ret = false;
 
798
         }
 
799
      } else {
 
800
         CRITICAL((SGE_EVENT, "main_class is NULL\n"));
 
801
         ret = false;
 
802
      }  
 
803
   } else {
 
804
      ret = false;
 
805
   }
 
806
 
 
807
 
 
808
   /*
 
809
   ** free allocated jvm args
 
810
   */
 
811
   for (i=0; i<jvm_argc; i++) {
 
812
      FREE(jvm_argv[i]);
 
813
   }  
 
814
   FREE(jvm_argv);
 
815
 
 
816
   /*
 
817
   ** free main_argv[0] argument
 
818
   */
 
819
   FREE(main_argv[0]);
 
820
 
 
821
   DRETURN(ret);
 
822
}
 
823
 
 
824
/****** qmaster/threads/sge_jvm_wait_for_terminate() ****************************
 
825
*  NAME
 
826
*     sge_jvm_wait_for_terminate() -- blocks the executing thread till shutdown 
 
827
*
 
828
*  SYNOPSIS
 
829
*     void sge_jvm_wait_for_terminate(void) 
 
830
*
 
831
*  FUNCTION
 
832
*     A call of this finction blocks the executing thread until termination
 
833
*     is signalled.
 
834
*
 
835
*     The sign to continue execution can be triggered by signalling the
 
836
*     condition 'Master_Jvm.cond_var'. 
 
837
*
 
838
*     This function should only be called thy the JVM thread.
 
839
*
 
840
*  INPUTS
 
841
*     void - None 
 
842
*
 
843
*  RESULT
 
844
*     void - None
 
845
*
 
846
*  NOTES
 
847
*     MT-NOTE: sge_jvm_wait_for_terminate() is MT safe 
 
848
*
 
849
*  SEE ALSO
 
850
*     qmaster/threads/sge_jvm_initialize() 
 
851
*     qmaster/threads/sge_jvm_cleanup_thread() 
 
852
*     qmaster/threads/sge_jvm_terminate() 
 
853
*     qmaster/threads/sge_jvm_wait_for_terminate()
 
854
*     qmaster/threads/sge_jvm_main() 
 
855
*******************************************************************************/
 
856
void                          
 
857
sge_jvm_wait_for_terminate(void)
 
858
{        
 
859
   DENTER(TOP_LAYER, "sge_thread_wait_for_signal");
 
860
         
 
861
   sge_mutex_lock("master jvm struct", SGE_FUNC, __LINE__, &Master_Jvm.mutex);
 
862
            
 
863
   while (Master_Jvm.shutdown_started == false) {
 
864
      pthread_cond_wait(&Master_Jvm.cond_var, &Master_Jvm.mutex);
 
865
   }     
 
866
            
 
867
   sge_mutex_unlock("master jvm struct", SGE_FUNC, __LINE__, &Master_Jvm.mutex);
 
868
 
 
869
   DEXIT;
 
870
   return;
 
871
}
 
872
 
 
873
/****** qmaster/threads/sge_jvm_cleanup_thread() ********************************
 
874
*  NAME
 
875
*     sge_jvm_cleanup_thread() -- cleanup routine for the JVM thread 
 
876
*
 
877
*  SYNOPSIS
 
878
*     void sge_jvm_cleanup_thread(void) 
 
879
*
 
880
*  FUNCTION
 
881
*     Cleanup JVM thread related stuff. 
 
882
*
 
883
*     This function has to be executed only by the JVM thread.
 
884
*     Ideally it should be the last function executed when the
 
885
*     pthreads cancelation point is passed.
 
886
*
 
887
*     'Master_Jvm' is accessed by this function. 
 
888
*
 
889
*  INPUTS
 
890
*     void - None 
 
891
*
 
892
*  RESULT
 
893
*     void - None
 
894
*
 
895
*  NOTES
 
896
*     MT-NOTE: sge_jvm_wait_for_terminate() is MT safe 
 
897
*
 
898
*  SEE ALSO
 
899
*     qmaster/threads/sge_jvm_initialize() 
 
900
*     qmaster/threads/sge_jvm_cleanup_thread() 
 
901
*     qmaster/threads/sge_jvm_terminate() 
 
902
*     qmaster/threads/sge_jvm_wait_for_terminate()
 
903
*     qmaster/threads/sge_jvm_main() 
 
904
*******************************************************************************/
 
905
static void
 
906
sge_jvm_cleanup_thread(void *ctx_ref)
 
907
{
 
908
   DENTER(TOP_LAYER, "sge_jvm_cleanup_thread");
 
909
 
 
910
   sge_mutex_lock("master jvm struct", SGE_FUNC, __LINE__, &(Master_Jvm.mutex));
 
911
 
 
912
   if (Master_Jvm.is_running) {
 
913
      cl_thread_settings_t* thread = NULL;
 
914
 
 
915
      /* 
 
916
       * The JVM thread itself executes this function (sge_jvm_cleanup_thread())
 
917
       * at the cancelation point as part of the cleanup. 
 
918
       * Therefore it has to unset the thread config before the
 
919
       * cl_thread is deleted. Otherwise we might run into a race condition when logging
 
920
       * is used after the call of cl_thread_list_delete_thread_without_join() 
 
921
       */
 
922
      cl_thread_unset_thread_config();
 
923
 
 
924
      /*
 
925
       * Delete the jvm thread but don't wait for termination
 
926
       */
 
927
      thread = cl_thread_list_get_first_thread(Main_Control.jvm_thread_pool);
 
928
      cl_thread_list_delete_thread_without_join(Main_Control.jvm_thread_pool, thread);
 
929
 
 
930
      /* 
 
931
       * Trash the thread pool 
 
932
       */
 
933
      cl_thread_list_cleanup(&Main_Control.jvm_thread_pool);
 
934
 
 
935
      /*
 
936
       * now a new jvm can start
 
937
       */
 
938
      Master_Jvm.is_running = false;
 
939
 
 
940
      /*
 
941
      ** free the ctx too
 
942
      */
 
943
      sge_gdi_ctx_class_destroy((sge_gdi_ctx_class_t **)ctx_ref);
 
944
   }
 
945
 
 
946
   sge_mutex_unlock("master jvm struct", SGE_FUNC, __LINE__, &(Master_Jvm.mutex));
 
947
 
 
948
   DRETURN_VOID;
 
949
}
 
950
 
 
951
 
 
952
/****** qmaster/threads/sge_jvm_main() ******************************************
 
953
*  NAME
 
954
*     sge_jvm_main() -- jvm thread function 
 
955
*
 
956
*  SYNOPSIS
 
957
*     static void* sge_jvm_main(void* arg) 
 
958
*
 
959
*  FUNCTION
 
960
*     The main function for the JVM thread 
 
961
*
 
962
*  INPUTS
 
963
*     void* arg - NULL 
 
964
*
 
965
*  RESULT
 
966
*     void* - none 
 
967
*
 
968
*  NOTES
 
969
*     MT-NOTE: sge_scheduler_main() is MT safe 
 
970
*
 
971
*     MT-NOTE: this is a thread function. Do NOT use this function
 
972
*     MT-NOTE: in any other way!
 
973
*
 
974
*  SEE ALSO
 
975
*     qmaster/threads/sge_jvm_initialize() 
 
976
*     qmaster/threads/sge_jvm_cleanup_thread() 
 
977
*     qmaster/threads/sge_jvm_terminate() 
 
978
*     qmaster/threads/sge_jvm_wait_for_terminate()
 
979
*     qmaster/threads/sge_jvm_main() 
 
980
*******************************************************************************/
 
981
static void *
 
982
sge_jvm_main(void *arg)
 
983
{
 
984
   cl_thread_settings_t *thread_config = (cl_thread_settings_t*)arg;
 
985
   time_t next_prof_output = 0;
 
986
   monitoring_t monitor;
 
987
   sge_gdi_ctx_class_t *ctx = NULL;
 
988
   bool jvm_started = false;
 
989
   bool do_endlessly = true;
 
990
 
 
991
   DENTER(TOP_LAYER, "sge_jvm_main");
 
992
 
 
993
   cl_thread_func_startup(thread_config);
 
994
   sge_monitor_init(&monitor, thread_config->thread_name, GDI_EXT, MT_WARNING, MT_ERROR);
 
995
   sge_qmaster_thread_init(&ctx, QMASTER, JVM_THREAD, true);
 
996
 
 
997
   set_thread_name(pthread_self(), "JVM Thread");
 
998
   conf_update_thread_profiling("JVM Thread");
 
999
 
 
1000
   /*
 
1001
    * main loop of the JVM thread
 
1002
    */
 
1003
   while (do_endlessly) {
 
1004
      int execute = 0;
 
1005
 
 
1006
      thread_start_stop_profiling();
 
1007
 
 
1008
      if (jvm_started == false) {
 
1009
         jvm_started = sge_run_jvm(ctx, arg, &monitor);
 
1010
      }
 
1011
 
 
1012
      thread_output_profiling("JVM thread profiling summary:\n", &next_prof_output);
 
1013
      sge_monitor_output(&monitor);
 
1014
 
 
1015
      /* 
 
1016
       * to prevent high cpu load if jvm is not started
 
1017
       */
 
1018
      sge_jvm_wait_for_terminate();
 
1019
 
 
1020
      /* 
 
1021
       * pthread cancelation point 
 
1022
       */
 
1023
      do {
 
1024
         /* 
 
1025
          * sge_jvm_cleanup_thread() is the last function which should 
 
1026
          * be called so it is pushed first 
 
1027
          */
 
1028
         pthread_cleanup_push(sge_jvm_cleanup_thread, (void*)&ctx);
 
1029
         pthread_cleanup_push((void (*)(void *))sge_jvm_cleanup_monitor, (void *)&monitor);
 
1030
         cl_thread_func_testcancel(thread_config);
 
1031
         pthread_cleanup_pop(execute);
 
1032
         pthread_cleanup_pop(execute);
 
1033
      } while (sge_thread_has_shutdown_started()); 
 
1034
   }
 
1035
 
 
1036
   /*
 
1037
    * Don't add cleanup code here. It will never be executed. Instead register
 
1038
    * a cleanup function with pthread_cleanup_push()/pthread_cleanup_pop() before 
 
1039
    * the call of cl_thread_func_testcancel()
 
1040
    *
 
1041
    * NOTE: number of pthread_cleanup_push() and pthread_cleanup_pop() calls have
 
1042
    *       no be equivalent. If this is not the case you might get funny 
 
1043
    *       COMPILER ERRORS here.
 
1044
    */
 
1045
   DRETURN(NULL); 
 
1046
 
1047
 
 
1048
#endif
 
1049