source: branches/2.0/drmaa2_utils/drmaa_utils/exception.c @ 77

Revision 77, 15.0 KB checked in by mmamonski, 12 years ago (diff)

DRMAA 2.0 utils - first skeleton

Line 
1/* $Id: exception.c 13 2011-04-20 15:41:43Z mmamonski $ */
2/*
3 *  PSNC DRMAA 2.0 utilities library
4 *  Copyright (C) 2012  Poznan Supercomputing and Networking Center
5 *
6 *  This program is free software: you can redistribute it and/or modify
7 *  it under the terms of the GNU General Public License as published by
8 *  the Free Software Foundation, either version 3 of the License, or
9 *  (at your option) any later version.
10 *
11 *  This program is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *  GNU General Public License for more details.
15 *
16 *  You should have received a copy of the GNU General Public License
17 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#ifdef HAVE_CONFIG_H
21#       include <config.h>
22#endif
23
24#include <errno.h>
25#include <string.h>
26#include <stdlib.h>
27
28#include <pthread.h>
29
30#include <drmaa_utils/common.h>
31#include <drmaa_utils/exception.h>
32
33
34#ifndef lint
35static char rcsid[]
36#       ifdef __GNUC__
37                __attribute__ ((unused))
38#       endif
39        = "$Id: exception.c 13 2011-04-20 15:41:43Z mmamonski $";
40#endif
41
42
43int fsd_exc_code( const fsd_exc_t *self );
44const char *fsd_exc_message( const fsd_exc_t *self );
45void fsd_exc_destroy( fsd_exc_t *self );
46
47#define EXC_INITIALIZER( code, message ) \
48 { \
49        fsd_exc_code, fsd_exc_message, fsd_exc_destroy, \
50        code, message, false, false \
51 }
52
53static const fsd_exc_t no_memory_exception \
54        = EXC_INITIALIZER( FSD_ERRNO_NO_MEMORY, "Not enough memory." );
55
56
57/**
58 * Thread specific stack of restore points
59 * @see fsd_exc_try_block_t
60 */
61typedef struct fsd_exc_stack_s {
62        fsd_exc_try_block_t **restore_points;
63        int n_restore_points;
64} fsd_exc_stack_t;
65
66
67static pthread_key_t fsd_exc_stack;
68static pthread_once_t fsd_exc_init_once = PTHREAD_ONCE_INIT;
69
70
71static void
72fsd_exc_stack_destroy( fsd_exc_stack_t *stack );
73
74
75void
76fsd_exc_init(void)
77{
78        int rc;
79        fsd_log_enter((""));
80        rc = pthread_key_create(
81                        &fsd_exc_stack,
82                        (void (*)(void*))fsd_exc_stack_destroy
83                        );
84        if( rc )
85         {
86                char errbuf[256] = "InternalError";
87                (void)strerror_r(errno, errbuf, 256);
88                fsd_log_fatal(( "pthread_key_create: %s",errbuf ));
89                abort();
90         }
91        fsd_log_return((""));
92}
93
94
95fsd_exc_stack_t *
96fsd_exc_get_stack( bool create )
97{
98        fsd_exc_stack_t *stack = NULL;
99        int rc;
100
101        rc = pthread_once( &fsd_exc_init_once, fsd_exc_init );
102        if( rc )
103         {
104                char errbuf[256] = "InternalError";
105                (void)strerror_r(errno, errbuf, 256);
106                fsd_log_fatal(( "pthread_once: %s",errbuf));
107                abort();
108         }
109        stack = (fsd_exc_stack_t*)pthread_getspecific( fsd_exc_stack );
110        if( stack == NULL  &&  create )
111         {
112                rc = fsd_malloc_noraise( stack, fsd_exc_stack_t );
113                if( rc )  return NULL;
114                stack->restore_points = NULL;
115                stack->n_restore_points = 0;
116                rc = pthread_setspecific( fsd_exc_stack, stack );
117                if( rc  &&  errno != ENOMEM )
118                 {
119                        char errbuf[256] = "InternalError";
120                        (void)strerror_r(errno, errbuf, 256);
121                        fsd_log_fatal(( "pthread_setspecific: %s",errbuf ));
122                        abort();
123                 }
124                else if( rc )
125                 {
126                        fsd_exc_stack_destroy( stack );
127                 }
128         }
129        else
130                fsd_assert( stack != NULL );
131        return stack;
132}
133
134
135void
136fsd_exc_stack_destroy( fsd_exc_stack_t *stack )
137{
138        int i;
139        fsd_log_enter((""));
140        for( i = 0;  i < stack->n_restore_points;  i++ )
141         {
142                fsd_exc_try_block_t *b = stack->restore_points[i];
143                if( b->handled_exc != NULL )
144                        b->handled_exc->destroy( b->handled_exc );
145                fsd_free( b );
146         }
147        fsd_free( stack->restore_points );
148        fsd_free( stack );
149        fsd_log_return((""));
150}
151
152
153fsd_exc_try_block_t *
154fsd_exc_try( const char *function, int lineno )
155{
156        fsd_exc_stack_t *stack = NULL;
157        fsd_exc_try_block_t *p = NULL;
158        int rc;
159
160        /* fsd_log_enter(( "(%s, %d)", function, lineno )); */
161        stack = fsd_exc_get_stack( true );
162        if( stack == NULL )
163                return NULL;
164
165        rc = fsd_realloc_noraise(
166                        stack->restore_points, stack->n_restore_points+1,
167                        fsd_exc_try_block_t* );
168        if( rc )
169                return NULL;
170        rc = fsd_malloc_noraise( p, fsd_exc_try_block_t );
171        if( rc )
172                return NULL;
173        p->handled_exc = NULL;
174        p->state = FSD_EXC_ENTER;
175        p->function = function;
176        p->lineno = lineno;
177        stack->restore_points[ stack->n_restore_points++ ] = p;
178        /* fsd_log_return(( " =%p", (void*)p )); */
179        return p;
180}
181
182
183void
184fsd_exc_control( fsd_exc_try_block_t *block, int *rc )
185{
186        /* fsd_log_enter(( "(block=%p, rc=%d)", (void*)block, *rc )); */
187        if( block == NULL  ||  *rc == FSD_ERRNO_EXC_END )
188                return;
189
190        switch( block->state )
191         {
192                case FSD_EXC_ENTER:
193                        block->state = FSD_EXC_TRY_BLOCK;
194                        fsd_assert( *rc == 0 );
195                        /* fsd_log_return(( ": rc=%d => %s:%d",
196                                                *rc, block->function, block->lineno )); */
197                        return;
198
199                case FSD_EXC_TRY_BLOCK:
200                        if( *rc == 0 )
201                         {
202                                block->state = FSD_EXC_ELSE_BLOCK;
203                                /* fsd_log_return(( ": rc=FSD_ERRNO_EXC_ELSE => %s:%d",
204                                                        block->function, block->lineno )); */
205                                *rc = FSD_ERRNO_EXC_ELSE;
206                                return;
207                         }
208                        else
209                         {
210                                fsd_assert( *rc > 0 );
211                                block->state = FSD_EXC_EXCEPTION_HANDLE;
212                                /* fsd_log_return(( ": rc=%d => %s:%d",
213                                                        *rc, block->function, block->lineno )); */
214                                return;
215                         }
216
217                case FSD_EXC_EXCEPTION_HANDLE:
218                case FSD_EXC_ELSE_BLOCK:
219                        block->state = FSD_EXC_FINALLY_BLOCK;
220                        /* fsd_log_return(( ": rc=FSD_ERRNO_EXC_FINALLY => %s:%d",
221                                                block->function, block->lineno )); */
222                        *rc = FSD_ERRNO_EXC_FINALLY;
223                        return;
224
225                case FSD_EXC_FINALLY_BLOCK:
226                 {
227                        fsd_exc_try_block_t *current = NULL;
228                        fsd_exc_try_block_t *upper = NULL;
229                        fsd_exc_stack_t *stack = NULL;
230
231                        block->state = FSD_EXC_LEAVE;
232
233                        stack = fsd_exc_get_stack( false );
234                        current = stack->restore_points[ stack->n_restore_points-1 ];
235                        fsd_assert( block == current );
236                        if( stack->n_restore_points > 1 )
237                                upper = stack->restore_points[ stack->n_restore_points-2 ];
238                        stack->n_restore_points --;
239
240                        if( current->handled_exc  &&  upper )
241                         {
242                                if( upper->handled_exc )
243                                 {
244                                        fsd_assert( upper->state == FSD_EXC_EXCEPTION_HANDLE
245                                                        || upper->state == FSD_EXC_FINALLY_BLOCK );
246                                        if( upper->state == FSD_EXC_FINALLY_BLOCK )
247                                                fsd_log_warning((
248                                                                        "overriding previously raised exception: <%d:%s>",
249                                                                        upper->handled_exc->_code, upper->handled_exc->_message ));
250                                        upper->handled_exc->destroy( upper->handled_exc );
251                                 }
252                                upper->handled_exc = current->handled_exc;
253                                /* current->handled_exc = NULL; */
254                                fsd_free_noraise( current );
255                                /* fsd_log_return(( ": longjmp(..., %d) => %s:%d",
256                                                        upper->handled_exc->_code, upper->function, upper->lineno )); */
257                                longjmp( upper->env, upper->handled_exc->_code );
258                         }
259                        else
260                         {
261                                if( current->handled_exc )
262                                        current->handled_exc->destroy( current->handled_exc );
263                                fsd_free_noraise( current );
264                                /* fsd_log_return(( ": rc=FSD_ERRNO_EXC_END => %s:%d",
265                                                        block->function, block->lineno )); */
266                                *rc = FSD_ERRNO_EXC_END;
267                                return;
268                         }
269                 }
270
271                default:
272                        fsd_assert(false);
273         }
274
275        /* no return */
276}
277
278
279const fsd_exc_t *
280fsd_exc_get(void)
281{
282        fsd_exc_stack_t *stack;
283        fsd_exc_try_block_t *block;
284        stack = fsd_exc_get_stack( false );
285        fsd_assert( stack->n_restore_points > 0 );
286        block = stack->restore_points[ stack->n_restore_points-1 ];
287        return block->handled_exc;
288}
289
290
291void
292fsd_exc_clear(void)
293{
294        fsd_exc_stack_t *stack;
295        fsd_exc_try_block_t *block;
296        fsd_log_enter((""));
297        stack = fsd_exc_get_stack( false );
298        fsd_assert( stack->n_restore_points > 0 );
299        block = stack->restore_points[ stack->n_restore_points-1 ];
300        if( block->handled_exc )
301                block->handled_exc->destroy( block->handled_exc );
302        block->handled_exc = NULL;
303        fsd_log_return((""));
304}
305
306
307fsd_exc_t *
308fsd_exc_new( int code, char *message, bool own_message )
309{
310        fsd_exc_t *exc = NULL;
311        char *volatile message_buffer = NULL;
312
313        if ( code == FSD_DRMAA_ERRNO_EXIT_TIMEOUT || code == FSD_ERRNO_STOP_ITERATION )
314                fsd_log_debug(("fsd_exc_new(%d,%s,%d)", code, message, own_message));
315        else
316                fsd_log_error(("fsd_exc_new(%d,%s,%d)", code, message, own_message));
317
318
319        TRY
320         {
321                if( own_message )
322                        message_buffer = message;
323                fsd_malloc( exc, fsd_exc_t );
324                exc->_code = code;
325                exc->_message = message;
326                exc->_own_message = own_message;
327                exc->_own_self = true;
328                exc->code = fsd_exc_code;
329                exc->message = fsd_exc_message;
330                exc->destroy = fsd_exc_destroy;
331         }
332        EXCEPT_DEFAULT
333         {
334                fsd_free( message_buffer );
335                fsd_exc_reraise();
336         }
337        END_TRY
338        return exc;
339}
340
341int
342fsd_exc_code( const fsd_exc_t *self )
343{
344        return self->_code;
345}
346
347const char *
348fsd_exc_message( const fsd_exc_t *self )
349{
350        return self->_message;
351}
352
353void
354fsd_exc_destroy( fsd_exc_t *self )
355{
356        if( self->_own_message )
357                fsd_free_noraise( self->_message );
358        if( self->_own_self )
359                fsd_free_noraise( self );
360}
361
362
363void
364fsd_exc_raise( fsd_exc_t *exc )
365{
366        fsd_exc_stack_t *stack = NULL;
367        fsd_exc_try_block_t *block = NULL;
368        fsd_assert(( exc->_code > 0 ));
369        stack = fsd_exc_get_stack( false );
370        fsd_assert(( stack->n_restore_points > 0 ));
371        block = stack->restore_points[ stack->n_restore_points - 1 ];
372        if( block->handled_exc )
373                block->handled_exc->destroy( block->handled_exc );
374        block->handled_exc = exc;
375        longjmp( block->env, exc->_code );
376}
377
378
379void
380fsd_exc_raise_code( int error_code )
381{
382        fsd_exc_t *exc;
383
384        if( error_code == FSD_ERRNO_NO_MEMORY )
385                exc = (fsd_exc_t*)&no_memory_exception;
386        else
387                exc = fsd_exc_new( error_code, (char*)fsd_strerror(error_code), false );
388        fsd_exc_raise( exc );
389}
390
391void
392fsd_exc_raise_msg( int error_code, const char *message )
393{
394        fsd_exc_raise(
395                        fsd_exc_new( error_code, fsd_strdup(message), true ) );
396}
397
398void
399fsd_exc_raise_fmt( int error_code, const char *fmt, ... )
400{
401        va_list args;
402        va_start( args, fmt );
403        fsd_exc_raise_fmtv( error_code, fmt, args );
404        va_end( args );
405}
406
407void
408fsd_exc_raise_fmtv( int error_code, const char *fmt, va_list args )
409{
410        fsd_exc_t *exc = NULL;
411        char *volatile message = NULL;
412        TRY
413         {
414                message = fsd_vasprintf( fmt, args );
415                exc = fsd_exc_new( error_code, message, true );
416                message = NULL;
417         }
418        FINALLY
419         {
420                fsd_free( message );
421         }
422        END_TRY
423        fsd_exc_raise( exc );
424}
425
426void
427fsd_exc_raise_sys( int errno_code )
428{
429        fsd_exc_t *exc = NULL;
430
431        if( errno_code == 0 )
432                errno_code = errno;
433        if( errno_code == ENOMEM )
434                exc = (fsd_exc_t*)&no_memory_exception;
435        else
436         {
437                int code;
438                char* volatile message = NULL;
439                volatile bool own_message = false;
440                TRY
441                 {
442                        switch( errno_code )
443                         {
444                                case ETIMEDOUT:  code = FSD_ERRNO_TIMEOUT;  break;
445                                default:         code = FSD_ERRNO_INTERNAL_ERROR;  break;
446                         }
447                        message = (char*)fsd_astrerror( errno_code, (bool*)&own_message );
448                        exc = fsd_exc_new( code, message, own_message );
449                 }
450                EXCEPT_DEFAULT
451                 {
452                        if( message && own_message )
453                                fsd_free( message );
454                        fsd_exc_reraise();
455                 }
456                END_TRY
457         }
458        fsd_exc_raise( exc );
459}
460
461
462void
463fsd_exc_reraise(void)
464{
465        fsd_exc_stack_t *stack = NULL;
466        fsd_exc_try_block_t *block = NULL;
467        stack = fsd_exc_get_stack( false );
468        fsd_assert(( stack->n_restore_points > 0 ));
469        block = stack->restore_points[ stack->n_restore_points - 1 ];
470        fsd_assert(( block->handled_exc->_code > 0 ));
471        longjmp( block->env, block->handled_exc->_code );
472}
473
474
475const char *
476fsd_strerror( int error_code )
477{
478        switch( error_code )
479         {
480                case FSD_ERRNO_SUCCESS:
481                        return "Success.";
482                case FSD_ERRNO_INTERNAL_ERROR:
483                        return "Unexpected or internal error.";
484                case FSD_ERRNO_NO_MEMORY:
485                        return "Not enough memory.";
486                case FSD_ERRNO_INVALID_ARGUMENT:
487                        return "Invalid argument value.";
488                case FSD_ERRNO_INVALID_VALUE:
489                        return "Invalid value.";
490                case FSD_ERRNO_INVALID_VALUE_FORMAT:
491                        return "Invalid value format.";
492                case FSD_ERRNO_STOP_ITERATION:
493                        return "Vector have no more elements.";
494                case FSD_ERRNO_NOT_IMPLEMENTED:
495                        return "Functionality is not implemented.";
496                case FSD_ERRNO_NOT_INITIALIZED:
497                        return "Library is not initialized";
498                case FSD_ERRNO_TIMEOUT:
499                        return "Routine returned due to time-out.";
500                case FSD_ERRNO_AUTH_FAILURE:
501                        return "Authentication failure.";
502                case FSD_ERRNO_AUTHZ_FAILURE:
503                        return "Authorization failure";
504                case FSD_ERRNO_TRY_LATER:
505                        return "System is overloaded.  Try again later.";
506                case FSD_ERRNO_DRM_COMMUNICATION_FAILURE:
507                        return "Could not contact DRM system for this request.";
508                case FSD_ERRNO_DRMS_INIT_FAILED:
509                        return "Unable to initialize DRM system.";
510                case FSD_ERRNO_DRMS_EXIT_ERROR:
511                        return "Disengagement from the DRM system failed.";
512                case FSD_ERRNO_DENIED_BY_DRM:
513                        return "DRM rejected request due to its configuration "
514                                "or request attributes.";
515
516                case FSD_DRMAA_ERRNO_NO_ACTIVE_SESSION:
517                        return "No active DRMAA session.";
518                case FSD_DRMAA_ERRNO_INVALID_CONTACT_STRING:
519                        return "Invalid contact string.";
520                case FSD_DRMAA_ERRNO_DEFAULT_CONTACT_STRING_ERROR:
521                        return "Can not determine default contact to DRM system.";
522                case FSD_DRMAA_ERRNO_NO_DEFAULT_CONTACT_STRING_SELECTED:
523                        return "Contact to DRM must be set explicitly "
524                                "because there is no default.";
525                case FSD_DRMAA_ERRNO_ALREADY_ACTIVE_SESSION:
526                        return "DRMAA session already exist.";
527                case FSD_DRMAA_ERRNO_INVALID_ATTRIBUTE_FORMAT:
528                        return "Invalid format of job attribute.";
529                case FSD_DRMAA_ERRNO_INVALID_ATTRIBUTE_VALUE:
530                        return "Invalid value of job attribute.";
531                case FSD_DRMAA_ERRNO_CONFLICTING_ATTRIBUTE_VALUES:
532                        return "Value of attribute conflicts with other attribute value.";
533                case FSD_DRMAA_ERRNO_INVALID_JOB:
534                        return "Job does not exist in DRMs queue.";
535                case FSD_DRMAA_ERRNO_RESUME_INCONSISTENT_STATE:
536                        return "Can not resume job (not in valid state).";
537                case FSD_DRMAA_ERRNO_SUSPEND_INCONSISTENT_STATE:
538                        return "Can not suspend job (not in valid state).";
539                case FSD_DRMAA_ERRNO_HOLD_INCONSISTENT_STATE:
540                        return "Can not hold job (not in valid state).";
541                case FSD_DRMAA_ERRNO_RELEASE_INCONSISTENT_STATE:
542                        return "Can not release job (not in valid state).";
543                case FSD_DRMAA_ERRNO_EXIT_TIMEOUT:
544                        return "Waiting for job to terminate finished due to time-out.";
545                case FSD_DRMAA_ERRNO_NO_RUSAGE:
546                        return "Job finished but resource usage information "
547                                "and/or termination status could not be provided.";
548
549                case FSD_ARES_ERRNO_INVALID_CONTACT_STRING:
550                        return "Invalid contact string.";
551                case FSD_ARES_ERRNO_INVALID_ATTRIBUTE_FORMAT:
552                        return "Invalid format of job attribute.";
553                case FSD_ARES_ERRNO_INVALID_ATTRIBUTE_VALUE:
554                        return "Invalid value of job attribute.";
555                case FSD_ARES_ERRNO_CONFLICTING_ATTRIBUTE_VALUES:
556                        return "Value of attribute conflicts with other attribute value.";
557                case FSD_ARES_ERRNO_INVALID_ARES:
558                        return "Invalid advance reservation identifier..";
559
560                default:
561                        return "Unknown error code!?";
562         }
563}
564
565
566static const int fsd_stacktrace_length = 32;
567
568void
569fsd_assertion_failed(
570                const char *file, int lineno,
571                const char *function, const char *precondition
572                )
573{
574        char *message = NULL;
575        if( asprintf( &message, "%s:%d: %s: Assertion `%s' failed.",
576                        file, lineno, function, precondition ) == -1 )
577                message = NULL;
578        if( message != NULL )
579                fsd_log_fatal(( "%s", message ));
580        fsd_log_stacktrace( 1, fsd_stacktrace_length );
581        if( message != NULL )
582                free( message );
583        abort();
584}
585
586
587void *
588fsd_exc_try_except(
589                void*(*f)(void*), void *data,
590                int *error_code,
591                char **error_message
592                )
593{
594        void *result = NULL;
595        TRY
596         {
597                result = f( data );
598         }
599        EXCEPT_DEFAULT
600         {
601                const fsd_exc_t *e = fsd_exc_get();
602                *error_code = e->code(e);
603                *error_message = fsd_strdup( e->message(e) );
604         }
605        ELSE
606         {
607                *error_code = FSD_ERRNO_SUCCESS;
608                *error_message = NULL;
609         }
610        END_TRY
611        return result;
612}
613
614
Note: See TracBrowser for help on using the repository browser.