Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Globals/TLS for libatmi
0003  *
0004  * @file atmi_tls.c
0005  */
0006 /* -----------------------------------------------------------------------------
0007  * Enduro/X Middleware Platform for Distributed Transaction Processing
0008  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0009  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0010  * This software is released under one of the following licenses:
0011  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0012  * See LICENSE file for full text.
0013  * -----------------------------------------------------------------------------
0014  * AGPL license:
0015  *
0016  * This program is free software; you can redistribute it and/or modify it under
0017  * the terms of the GNU Affero General Public License, version 3 as published
0018  * by the Free Software Foundation;
0019  *
0020  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0021  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0022  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0023  * for more details.
0024  *
0025  * You should have received a copy of the GNU Affero General Public License along 
0026  * with this program; if not, write to the Free Software Foundation, Inc.,
0027  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0028  *
0029  * -----------------------------------------------------------------------------
0030  * A commercial use license is available from Mavimax, Ltd
0031  * contact@mavimax.com
0032  * -----------------------------------------------------------------------------
0033  */
0034 
0035 /*---------------------------Includes-----------------------------------*/
0036 #include <stdlib.h>
0037 #include <stdio.h>
0038 #include <ndrstandard.h>
0039 #include <atmi.h>
0040 #include <atmi_tls.h>
0041 #include <string.h>
0042 #include "thlock.h"
0043 #include "userlog.h"
0044 #include "utlist.h"
0045 #include <typed_buf.h>
0046 /*---------------------------Externs------------------------------------*/
0047 /*---------------------------Macros-------------------------------------*/
0048 /*---------------------------Enums--------------------------------------*/
0049 /*---------------------------Typedefs-----------------------------------*/
0050 /*---------------------------Globals------------------------------------*/
0051 __thread atmi_tls_t *G_atmi_tls = NULL; /* single place for library TLS storage */
0052 /*---------------------------Statics------------------------------------*/
0053 exprivate pthread_key_t M_atmi_tls_key;
0054 exprivate pthread_key_t M_atmi_switch_key; /* switch the structure */
0055 
0056 exprivate MUTEX_LOCKDECL(M_thdata_init);
0057 exprivate int M_first = EXTRUE;
0058 /*---------------------------Prototypes---------------------------------*/
0059 
0060 /**
0061  * Unlock, unset G_atmi_tls, return pointer to G_atmi_tls
0062  * @return 
0063  */
0064 expublic void * ndrx_atmi_tls_get(long priv_flags)
0065 {
0066     atmi_tls_t *tls = G_atmi_tls;
0067     char *fn = "ndrx_atmi_tls_get";
0068     if (NULL!=tls)
0069     {
0070         /*
0071          * Unset the destructor
0072          */
0073         if (tls->is_auto)
0074         {
0075             pthread_setspecific( M_atmi_tls_key, NULL );
0076         }
0077 
0078         /* suspend the transaction if any in progress: similar to tpsrvgetctxdata() */
0079 #ifdef NDRX_OAPI_DEBUG
0080         
0081         NDRX_LOG(log_debug, "%s: G_atmi_xa_curtx.txinfo: %p", 
0082                      __func__, tls->G_atmi_xa_curtx.txinfo);
0083 #endif
0084         
0085         /* well for java we do not need to suspend the transaction,,
0086          * do we?
0087          */
0088         if (priv_flags & CTXT_PRIV_TRAN && 
0089                 !(G_atmi_env.xa_flags_sys & NDRX_XA_FLAG_SYS_NOAPISUSP))
0090         {
0091             tls->global_tx_suspended = EXFALSE;
0092             
0093             if (tls->G_atmi_xa_curtx.txinfo)
0094             {
0095                 atmi_error_t aerr;
0096                 int aerr_loaded=EXFALSE;
0097                 
0098                 /* suspend current error */
0099                 if (tls->M_atmi_error)
0100                 {
0101                     aerr_loaded=EXTRUE;
0102                     ndrx_TPsave_error(&aerr);
0103                 }
0104                 
0105                 tls->M_atmi_error = 0;
0106                 if (EXSUCCEED!=ndrx_tpsuspend(&tls->tranid, 0, EXTRUE))
0107                 {
0108                     /*
0109                      * Nothing to do here! it will fail next time when user
0110                      * will try to do some DB operation... 
0111                      */
0112                     userlog("ndrx_atmi_tls_get: Failed to suspend transaction: [%s]", 
0113                             tpstrerror(tperrno));
0114                 }
0115                 else
0116                 {
0117                     tls->global_tx_suspended = EXTRUE;
0118                 }
0119                 
0120                 if (aerr_loaded)
0121                 {
0122                     ndrx_TPrestore_error(&aerr);
0123                 }
0124                 
0125             }
0126         }
0127         
0128         /* Disable current thread TLS... */
0129         G_atmi_tls = NULL;
0130 
0131         /* unlock object */
0132         MUTEX_UNLOCK_V(tls->mutex);
0133     }
0134 out:
0135     return (void *)tls;
0136 }
0137 
0138 /**
0139  * Get the lock & set the G_atmi_tls to this one
0140  * @param tls
0141  */
0142 expublic int ndrx_atmi_tls_set(void *data, int flags, long priv_flags)
0143 {
0144     int ret = EXSUCCEED;
0145     atmi_tls_t *tls = (atmi_tls_t *)data;
0146     char *fn = "ndrx_atmi_tls_set";
0147    
0148     if (NULL!=tls)
0149     {
0150         /* extra control... */
0151         if (ATMI_TLS_MAGIG!=tls->magic)
0152         {
0153             userlog("atmi_tls_set: invalid magic! expected: %x got %x", 
0154                     ATMI_TLS_MAGIG, tls->magic);
0155         }
0156 
0157         /* Lock the object 
0158          * TODO: We need PTHREAD_MUTEX_RECURSIVE
0159          * so that we can acquire multiple locks (for example server process calls 
0160          * back tpsrvinit or done which internally may acquire some more locks!
0161          */
0162         MUTEX_LOCK_V(tls->mutex);
0163 
0164         /* Add the additional flags to the user. */
0165         tls->G_last_call.sysflags |= flags;
0166         
0167 #ifdef NDRX_OAPI_DEBUG
0168         NDRX_LOG(log_debug, "%s: G_atmi_xa_curtx.txinfo: %p", 
0169                      __func__, tls->G_atmi_xa_curtx.txinfo);
0170 #endif
0171         G_atmi_tls = tls; /* Must be set, so that tpresume works () - not allocate new.. */
0172         
0173         /* Resume the transaction only if flag is set
0174          * For Object API some of the operations do not request transaction to
0175          * be open.
0176          */
0177         if (priv_flags & CTXT_PRIV_TRAN && 
0178                 !(G_atmi_env.xa_flags_sys & NDRX_XA_FLAG_SYS_NOAPISUSP))
0179         {
0180             if(tls->global_tx_suspended)
0181             {   
0182                 /* reset error */
0183                 tls->M_atmi_error = 0;
0184                 if (EXSUCCEED!=ndrx_tpresume(&tls->tranid, 0))
0185                 {
0186                     userlog("Failed to resume transaction: [%s]", tpstrerror(tperrno));
0187                 }
0188                 else
0189                 {
0190                     tls->global_tx_suspended = EXFALSE;
0191                 }
0192             }
0193         }
0194         
0195         /*
0196          * Destruct automatically if it was auto-tls 
0197          */
0198         if (tls->is_auto)
0199         {
0200             pthread_setspecific( M_atmi_tls_key, (void *)tls );
0201         }
0202     }
0203     else
0204     {
0205         G_atmi_tls = NULL;
0206     }
0207     
0208 out:
0209     return ret;
0210 }
0211 
0212 /**
0213  * Free up the TLS data
0214  * @param tls
0215  * @return 
0216  */
0217 expublic void ndrx_atmi_tls_free(void *data)
0218 {   
0219     atmi_tls_t *tls = (atmi_tls_t *)data;
0220     tpmemq_t *el, *elt;
0221     if (NULL!=data)
0222     {
0223         if (data == G_atmi_tls)
0224         {
0225             if (G_atmi_tls->is_auto)
0226             {
0227                 pthread_setspecific( M_atmi_tls_key, NULL );
0228             }
0229             G_atmi_tls = NULL;
0230         }
0231         
0232         /* de-init mutex & spinlock */
0233         
0234         MUTEX_DESTROY_V(tls->mutex);
0235         
0236         /* shouldn't we free up any  tls->memq ? */
0237         
0238         DL_FOREACH_SAFE(tls->memq, el, elt)
0239         {
0240             if (NULL!=(el->buf))
0241             {
0242                 NDRX_SYSBUF_FREE(el->buf);
0243             }
0244             
0245             NDRX_FPFREE(el);
0246         }
0247         
0248         if (NULL!=tls->qdisk_tls)
0249         {
0250             NDRX_FPFREE(tls->qdisk_tls);
0251         }
0252         
0253         NDRX_FREE((char*)data);
0254     }
0255 }
0256 
0257 /**
0258  * Get the lock & init the data
0259  * @param auto_destroy if set to 1 then when tried exits, thread data will be made free
0260  * @return 
0261  */
0262 expublic void * ndrx_atmi_tls_new(void *tls_in, int auto_destroy, int auto_set)
0263 {
0264     int ret = EXSUCCEED;
0265     atmi_tls_t *tls  = NULL;
0266     
0267     /* init they key storage */
0268     if (M_first)
0269     {
0270         MUTEX_LOCK_V(M_thdata_init);
0271         if (M_first)
0272         {
0273             pthread_key_create( &M_atmi_tls_key, 
0274                     &ndrx_atmi_tls_free );
0275             
0276             /* perform first time library inits..., locks, etc  */
0277             ndrx_tpcall_init_once();
0278             M_first = EXFALSE;
0279         }
0280         MUTEX_UNLOCK_V(M_thdata_init);
0281     }
0282     
0283     if (NULL!=tls_in)
0284     {
0285         tls = (atmi_tls_t *)tls_in;
0286         NDRX_LOG(log_debug, "%s: Reusing TLS storage", __func__);
0287     }
0288     else
0289     {
0290         if (NULL==(tls = (atmi_tls_t *)NDRX_MALLOC(sizeof(atmi_tls_t))))
0291         {
0292             userlog ("%s: failed to malloc", __func__);
0293             EXFAIL_OUT(ret);
0294         }
0295     }
0296     
0297     /* do the common init... */
0298     tls->magic = ATMI_TLS_MAGIG;
0299     
0300     
0301     /* init.c */    
0302     tls->conv_cd=0;/*  Lets start from 0 now... */
0303     
0304     /* reset client info  */
0305     memset(&tls->client_init_data, 0, sizeof(tls->client_init_data));
0306     
0307     /* tls->callseq = 0; ???? */
0308     tls->G_atmi_is_init= 0;/*  Is environment initialised */
0309     memset (tls->G_call_state, 0, sizeof(tls->G_call_state));
0310     tls->tpcall_get_cd=MAX_ASYNC_CALLS-2; /* first available, we want test overlap!*/
0311     tls->memq = NULL; /* In memory messages when tpchkunsol are performed... */
0312     /* tls->tpcall_callseq=0; */
0313     
0314     
0315     memset (tls->G_tp_conversation_status, 0, sizeof(tls->G_tp_conversation_status));
0316     
0317     /* tpcall.c */
0318     tls->M_svc_return_code = 0;
0319     tls->tpcall_first = EXTRUE;
0320     
0321     /* tperror.c */
0322     tls->M_atmi_error_msg_buf[0] = EXEOS;
0323     tls->M_atmi_error = TPMINVAL;
0324     tls->M_atmi_reason = NDRX_XA_ERSN_NONE;
0325     tls->errbuf[0] = EXEOS;
0326     tls->is_associated_with_thread = EXFALSE;
0327     /* xa.c */
0328     tls->M_is_curtx_init = EXFALSE;
0329     tls->global_tx_suspended = EXFALSE;
0330     memset(&tls->G_atmi_conf, 0, sizeof(tls->G_atmi_conf));
0331     memset(&tls->G_atmi_xa_curtx, 0, sizeof(tls->G_atmi_xa_curtx));
0332     
0333     /* unsol msgs */
0334     tls->p_unsol_handler = NULL;
0335     
0336     /* tx related: */
0337     tls->tx_commit_return = TX_COMMIT_COMPLETED;
0338     tls->tx_transaction_control = TX_UNCHAINED;
0339     tls->tx_transaction_timeout = 0;
0340     
0341     tls->nullbuf.autoalloc = EXFALSE;
0342     tls->nullbuf.size=0;
0343     tls->nullbuf.subtype[0]=EXEOS;
0344     tls->nullbuf.type_id=BUF_TYPE_NULL;
0345     tls->nullbuf.callinfobuf=NULL;
0346     tls->nullbuf.callinfobuf_len=0;
0347     memset(&tls->nullbuf.hh, 0, sizeof(tls->nullbuf.hh));
0348     
0349     memset(&tls->integpriv, 0, sizeof(tls->integpriv));
0350     
0351     MUTEX_VAR_INIT(tls->mutex);
0352     
0353     /* reset the hook */
0354     tls->pf_tpacall_noservice_hook = NULL;
0355     
0356     /* no priority set ... */
0357     tls->prio = 0;
0358     tls->prio_flags=0;
0359     tls->prio_last = NDRX_MSGPRIO_DEFAULT;
0360     tls->tmnull_is_open=EXFALSE;
0361     tls->tmnull_rmid=EXFAIL;
0362 
0363     tls->tout = EXFAIL;
0364     tls->tout_next = EXFAIL;
0365     tls->tout_next_eff = EXFAIL;
0366     
0367     tls->qdisk_is_open=EXFALSE;
0368     tls->qdisk_rmid=EXFAIL;
0369     tls->qdisk_tls=NULL;
0370     
0371     tls->atmisrv_reply_type=0;
0372     
0373     /* set callback, when thread dies, we need to get the destructor 
0374      * to be called
0375      */
0376     if (auto_destroy)
0377     {
0378         tls->is_auto = EXTRUE;
0379         pthread_setspecific( M_atmi_tls_key, (void *)tls );
0380     }
0381     else
0382     {
0383         tls->is_auto = EXFALSE;
0384     }
0385     
0386     if (auto_set)
0387     {
0388         ndrx_atmi_tls_set(tls, 0, 0);
0389     }
0390     
0391 out:
0392 
0393     if (EXSUCCEED!=ret && NULL!=tls)
0394     {
0395         ndrx_atmi_tls_free((char *)tls);
0396         tls = NULL;
0397     }
0398 
0399     return (void *)tls;
0400 }
0401 
0402 /**
0403  * Kill the given context,
0404  * Do we need tpterm here?
0405  * @param context
0406  * @param flags
0407  * @return 
0408  */
0409 expublic void ndrx_tpfreectxt(TPCONTEXT_T context)
0410 {
0411     atmi_tls_t * ctx = (atmi_tls_t *)context;
0412     
0413     if (NULL!=ctx)
0414     {
0415         /* Close any open loggers... */
0416         if (G_atmi_tls && G_atmi_tls==context)
0417         {
0418             tplogclosereqfile();
0419             tplogclosethread();
0420             tpterm();
0421         }
0422         
0423         if (NULL!=ctx->p_nstd_tls)
0424         {
0425             ndrx_nstd_tls_free(ctx->p_nstd_tls);
0426         }
0427         
0428         if (NULL!=ctx->p_ubf_tls)
0429         {
0430             ndrx_ubf_tls_free(ctx->p_ubf_tls);
0431         }
0432         
0433         ndrx_atmi_tls_free(ctx);
0434     }
0435 }
0436 
0437 /**
0438  * Internal version of get context
0439  * @param context
0440  * @param flags
0441  * @param priv_flags private flags (for sharing the functionality)
0442  * @return 
0443  */
0444 expublic int ndrx_tpsetctxt(TPCONTEXT_T context, long flags, long priv_flags)
0445 {
0446     int ret = EXSUCCEED;
0447     atmi_tls_t * ctx;
0448     
0449 #ifdef NDRX_OAPI_DEBUG
0450     NDRX_LOG(log_debug, "ENTRY: %s enter, context: %p, current: %p",  __func__, 
0451             context, G_atmi_tls);
0452     
0453     if (NULL!=context)
0454     {
0455         NDRX_LOG(log_debug, "ENTRY: is_associated_with_thread = %d", 
0456             ((atmi_tls_t *)context)->is_associated_with_thread);
0457     }
0458 
0459     NDRX_LOG(log_debug, "ENTRY: CTXT_PRIV_NSTD = %d", 
0460         (priv_flags) & CTXT_PRIV_NSTD );
0461 
0462     NDRX_LOG(log_debug, "ENTRY: CTXT_PRIV_UBF = %d", 
0463         (priv_flags) & CTXT_PRIV_UBF );
0464 
0465     NDRX_LOG(log_debug, "ENTRY: CTXT_PRIV_ATMI = %d", 
0466         (priv_flags) & CTXT_PRIV_ATMI );
0467 
0468     NDRX_LOG(log_debug, "ENTRY: CTXT_PRIV_TRAN = %d", 
0469         (priv_flags) & CTXT_PRIV_TRAN );
0470 
0471     NDRX_LOG(log_debug, "ENTRY: CTXT_PRIV_NOCHK = %d", 
0472         (priv_flags) & CTXT_PRIV_NOCHK );
0473 
0474     NDRX_LOG(log_debug, "ENTRY: CTXT_PRIV_IGN = %d", 
0475         (priv_flags) & CTXT_PRIV_IGN );
0476 #endif
0477 
0478     
0479     if (context == TPNULLCONTEXT)
0480     {
0481         TPCONTEXT_T tmp;
0482         int dealloc = EXFALSE;
0483         
0484         /* deallocate the context (if needed so...) */
0485         
0486         if (NULL!=G_atmi_tls && G_atmi_tls->is_auto)
0487         {
0488             dealloc = EXTRUE;
0489         }
0490         
0491         /* Bug #311: disassociate context */
0492         ndrx_tpgetctxt(&tmp, 0L, priv_flags);
0493         
0494         if (dealloc)
0495         {
0496             /* free the current thread context data (only in case if it was auto) */
0497             ndrx_tpfreectxt((TPCONTEXT_T)tmp);
0498         }
0499         
0500         /* In case if we are already in NULL context, then go out... */
0501         goto out; /* we are done. */
0502     }
0503     
0504     ctx = (atmi_tls_t *)context;
0505     
0506     if (!(priv_flags & CTXT_PRIV_NOCHK))
0507     {
0508         /* have a deep checks */
0509         if (priv_flags & CTXT_PRIV_ATMI && ATMI_TLS_MAGIG!=ctx->magic)
0510         {
0511             ndrx_TPset_error_fmt(TPENOENT, "_tpsetctxt: invalid atmi magic: "
0512                     "expected: %x got %x!", ATMI_TLS_MAGIG, ctx->magic);
0513             EXFAIL_OUT(ret);
0514         }
0515 
0516         if (priv_flags & CTXT_PRIV_NSTD && NULL!=ctx->p_nstd_tls 
0517                 && NSTD_TLS_MAGIG!=ctx->p_nstd_tls->magic)
0518         {
0519             ndrx_TPset_error_fmt(TPENOENT, "_tpsetctxt: invalid nstd magic: "
0520                     "expected: %x got %x!", NSTD_TLS_MAGIG, ctx->p_nstd_tls->magic);
0521             EXFAIL_OUT(ret);
0522         }
0523 
0524         if (priv_flags & CTXT_PRIV_UBF && NULL!=ctx->p_ubf_tls 
0525                 && UBF_TLS_MAGIG!=ctx->p_ubf_tls->magic)
0526         {
0527             ndrx_TPset_error_fmt(TPENOENT, "_tpsetctxt: invalid ubf magic: "
0528                     "expected: %x got %x!", UBF_TLS_MAGIG, ctx->p_ubf_tls->magic);
0529             EXFAIL_OUT(ret);
0530         }
0531     }
0532     
0533     /* free the current context (with tpterm?) 
0534      * if one in progress 
0535      */
0536     if (!(priv_flags & CTXT_PRIV_IGN) && G_atmi_tls!=ctx && NULL!=G_atmi_tls)
0537     {
0538         NDRX_LOG(log_warn, "Free up context %p", G_atmi_tls);
0539         tpterm();
0540         tpfreectxt((TPCONTEXT_T)G_atmi_tls);
0541     }
0542     
0543     
0544     if (priv_flags & CTXT_PRIV_NSTD && NULL!=ctx->p_nstd_tls &&
0545             EXSUCCEED!=ndrx_nstd_tls_set((void *)ctx->p_nstd_tls))
0546     {
0547         ndrx_TPset_error_fmt(TPESYSTEM, "_tpsetctxt: failed to restore libnstd context");
0548         EXFAIL_OUT(ret);
0549     }
0550     
0551     if (priv_flags & CTXT_PRIV_UBF &&  NULL!=ctx->p_ubf_tls &&
0552             EXSUCCEED!=ndrx_ubf_tls_set((void *)ctx->p_ubf_tls))
0553     {
0554         ndrx_TPset_error_fmt(TPESYSTEM, "_tpsetctxt: failed to restore libubf context");
0555         EXFAIL_OUT(ret);
0556     }
0557     
0558     if (priv_flags & CTXT_PRIV_ATMI)
0559     {
0560         if (EXSUCCEED!=ndrx_atmi_tls_set((void *)ctx, flags, priv_flags))
0561         {
0562             ndrx_TPset_error_fmt(TPESYSTEM, "_tpsetctxt: failed to restore libatmi context");
0563             EXFAIL_OUT(ret);
0564         }
0565         
0566         ctx->is_associated_with_thread = EXTRUE;
0567     }
0568     
0569 out:
0570 
0571 #ifdef NDRX_OAPI_DEBUG
0572     NDRX_LOG(log_debug, "RETURN: %s returns %d, context: %p, current: %p",  __func__, 
0573             ret, context, G_atmi_tls);
0574 #endif
0575     return ret;
0576 }
0577 
0578 /**
0579  * Return data from context
0580  * This assumes that ATMI Context currently IS set!
0581  * @param[out] data output data where to store the result
0582  */
0583 expublic ndrx_ctx_priv_t* ndrx_ctx_priv_get(void)
0584 {
0585     if (NULL==G_atmi_tls)
0586     {
0587         return NULL;
0588     }
0589     else
0590     {
0591         return &G_atmi_tls->integpriv;
0592     }
0593 }
0594 
0595 /**
0596  * Internal version of get full context
0597  * This disconnects current thread from TLS.
0598  * @param flags
0599  * @return 
0600  */
0601 expublic int ndrx_tpgetctxt(TPCONTEXT_T *context, long flags, long priv_flags)
0602 {
0603     int ret = TPMULTICONTEXTS; /* default */
0604     atmi_tls_t * ctx;
0605     char *fn="_tpgetctxt";
0606     
0607 #ifdef NDRX_OAPI_DEBUG
0608     NDRX_LOG(log_debug, "ENTRY: %s enter, context: %p, current: %p", 
0609                  __func__, *context, G_atmi_tls);
0610     
0611     NDRX_LOG(log_debug, "ENTRY: CTXT_PRIV_NSTD = %d", 
0612         (priv_flags) & CTXT_PRIV_NSTD );
0613 
0614     NDRX_LOG(log_debug, "ENTRY: CTXT_PRIV_UBF = %d", 
0615         (priv_flags) & CTXT_PRIV_UBF );
0616 
0617     NDRX_LOG(log_debug, "ENTRY: CTXT_PRIV_ATMI = %d", 
0618         (priv_flags) & CTXT_PRIV_ATMI );
0619 
0620     NDRX_LOG(log_debug, "ENTRY: CTXT_PRIV_TRAN = %d", 
0621         (priv_flags) & CTXT_PRIV_TRAN );
0622 
0623     NDRX_LOG(log_debug, "ENTRY: CTXT_PRIV_NOCHK = %d", 
0624         (priv_flags) & CTXT_PRIV_NOCHK );
0625 
0626     NDRX_LOG(log_debug, "ENTRY: CTXT_PRIV_IGN = %d", 
0627         (priv_flags) & CTXT_PRIV_IGN );
0628 #endif
0629     if (NULL==context)
0630     {
0631         ndrx_TPset_error_msg(TPEINVAL, "_tpgetctxt: context must not be NULL!");
0632         EXFAIL_OUT(ret);
0633     }
0634     
0635     if (0!=flags)
0636     {
0637         ndrx_TPset_error_msg(TPEINVAL, "_tpgetctxt: flags must be 0!");
0638         EXFAIL_OUT(ret);
0639     }
0640     
0641     /* if not using ATMI, then use existing context object */
0642     if (priv_flags & CTXT_PRIV_ATMI)
0643     {
0644         ctx = (atmi_tls_t *)ndrx_atmi_tls_get(priv_flags);
0645     }
0646     else   
0647     {
0648         ctx = (TPCONTEXT_T)*context;
0649     }
0650     
0651     if (NULL!=ctx)
0652     {
0653         /* Dis associate */
0654         ctx->is_associated_with_thread = EXFALSE;
0655 
0656         if (priv_flags & CTXT_PRIV_NSTD)
0657         {
0658             ctx->p_nstd_tls = ndrx_nstd_tls_get();
0659         }
0660         
0661         if (priv_flags & CTXT_PRIV_UBF)
0662         {
0663             ctx->p_ubf_tls = ndrx_ubf_tls_get();
0664         }
0665     }
0666     
0667     if (priv_flags & CTXT_PRIV_ATMI)
0668     {
0669         *context = (TPCONTEXT_T)ctx;
0670     }
0671     
0672     if (NULL==ctx)
0673     {
0674         ret = TPNULLCONTEXT;
0675     }
0676 out:
0677 
0678 #ifdef NDRX_OAPI_DEBUG
0679     NDRX_LOG(log_debug, "RETURN: %s returns %d, context: %p, current: %p",  __func__, 
0680             ret, *context, G_atmi_tls);
0681 #endif
0682 
0683     return ret;
0684 }
0685 
0686 /**
0687  * Reconfigure context.
0688  * Current context must be set.
0689  * @param is_auto TRUE -> automatic dealloc, FALSE -> manual context dealloc
0690  */
0691 expublic void ndrx_ctx_auto(int is_auto)
0692 {
0693     G_atmi_tls->is_auto = is_auto;
0694 }
0695 
0696 /* vim: set ts=4 sw=4 et smartindent: */