Files
cdesktop/cde/lib/tt/lib/mp/mp_c_mp.C
2018-04-28 12:36:44 -06:00

443 lines
12 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
//%% (c) Copyright 1993, 1994 Hewlett-Packard Company
//%% (c) Copyright 1993, 1994 International Business Machines Corp.
//%% (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc.
//%% (c) Copyright 1993, 1994 Novell, Inc.
//%% $TOG: mp_c_mp.C /main/6 1999/10/14 18:41:09 mgreess $
/*
*
* mp_c_mp.cc
*
* Implementations of client-only members of _Tt_mp object.
*
* Copyright (c) 1992 by Sun Microsystems, Inc.
*/
#include "mp/mp_c_global.h"
#include "mp/mp_c_mp.h"
#include "mp/mp_c_session.h"
#include "mp/mp_c_procid.h"
#include "mp/mp_rpc_interface.h"
#include "util/tt_global_env.h"
#include "util/tt_port.h"
#include "util/tt_threadspecific.h"
_Tt_c_mp *_tt_c_mp = (_Tt_c_mp *)0;
_Tt_c_mp::
_Tt_c_mp() : _Tt_mp()
{
_flags &= ~(1<<_TT_MP_IN_SERVER);
initial_session = initial_c_session =
default_c_session = new _Tt_c_session;
}
_Tt_c_mp::
~_Tt_c_mp()
{
}
//
// Initializes the _Tt_c_mp object. This initializes all the caches
// maintained by this object as well as the "initial" session which is
// the "default" session for a ToolTalk client.
//
// Returns:
// TT_OK
// TT_ERR_NOMP - the initial session could not be initialized.
Tt_status _Tt_c_mp::
c_init()
{
Tt_status status;
if (_flags&(1<<_TT_MP_INIT_DONE)) {
return(TT_OK);
}
_file_cache = new _Tt_file_table( _Tt_file::networkPath_ );
// initialize "initial" session which is the server session in
// server mode and the "default" session in client mode.
status = initial_c_session->c_init();
if (status == TT_ERR_NOMP) {
if (default_c_session.is_eq(initial_c_session)) {
default_c_session = 0;
}
#ifdef OPT_XTHREADS
_Tt_threadspecific* tss = (_Tt_threadspecific *) 0;
xthread_get_specific(_tt_global->threadkey, (void **) &tss);
if (!tss) {
// thread-specific storage not yet initialized -- do it
tss = new _Tt_threadspecific(default_c_session,
_default_c_procid);
xthread_set_specific(_tt_global->threadkey, tss);
}
_Tt_c_session_ptr cs = tss->thread_c_session();
_Tt_c_session_ptr nullsess = (_Tt_c_session *) 0;
if (!cs.is_null() && cs.is_eq(initial_c_session)) {
tss->set_thread_c_session(nullsess);
}
#endif
initial_session = initial_c_session = 0;
}
if (status == TT_OK && !in_server()) {
// enter session object in session table
_session_cache->insert(initial_session);
}
_flags |= (1<<_TT_MP_INIT_DONE);
return(status);
}
_Tt_procid_ptr & _Tt_c_mp::
default_procid()
{
// XXX: (futures) For clients using multi-threading, this
// function should index the default procid off the current
// thread id so that there are no conflicts with other
// threads.
return(default_c_procid());
}
_Tt_c_procid_ptr & _Tt_c_mp::
default_c_procid()
{
#ifdef OPT_XTHREADS
// Return a thread-specific procid if one is set and libthread
// has actually been linked in
if (_tt_global->multithreaded()) {
_Tt_threadspecific* tss = (_Tt_threadspecific *) 0;
xthread_get_specific(_tt_global->threadkey, (void **) &tss);
if (!tss) {
// thread-specific storage not yet initialized -- do it
tss = new _Tt_threadspecific(default_c_session,
_default_c_procid);
xthread_set_specific(_tt_global->threadkey, tss);
}
if (tss->thread_c_procid().is_null()) {
tss->set_thread_c_procid(_default_c_procid);
}
return tss->thread_c_procid();
}
#endif
return(_default_c_procid);
}
Tt_status _Tt_c_mp::
set_default_procid(
_Tt_string id,
int
#ifdef OPT_XTHREADS
thread_only
#endif
)
{
_Tt_procid_ptr p;
if (id.len() == 0) {
return(TT_ERR_PROCID);
}
p = active_procs->lookup(id);
if (p.is_null()) {
return(TT_ERR_PROCID);
}
_Tt_c_procid_ptr pp = (_Tt_c_procid *) p.c_pointer();
#ifdef OPT_XTHREADS
if (thread_only) {
_Tt_threadspecific* tss = (_Tt_threadspecific *) 0;
xthread_get_specific(_tt_global->threadkey, (void **) &tss);
if (!tss) {
// thread-specific storage not yet initialized -- do it
tss = new _Tt_threadspecific(default_c_session, pp);
xthread_set_specific(_tt_global->threadkey, tss);
} else {
tss->set_thread_c_procid(pp);
}
}
else // fall through to set _default_c_procid
#endif
_default_c_procid = pp;
return(TT_OK);
}
//
// A client-only method that removes a procid from the active procid
// cache and also deallocates any resources/network connections held by
// the procid. If this is the last active procid to be removed then the
// default session is also shut down. This method operates in this
// fashion in order for it to be suitable for the semantics of the
// "tt_close" api call which overloads the call to mean "close the last
// procid" and "deallocate tooltalk resources (if no more procids left)".
//
Tt_status _Tt_c_mp::
c_remove_procid(_Tt_procid_ptr &proc)
{
_Tt_session_ptr d_session;
Tt_status rstatus;
Tt_status status = TT_OK;
_Tt_procid_table_cursor procs;
int remove_session;
_Tt_c_procid *cp;
if (proc.is_null()) {
return(TT_ERR_INVALID);
}
cp = (_Tt_c_procid *)proc.c_pointer();
cp->close();
// remove from list of active procs
active_procs->remove(proc->id());
d_session = cp->default_session();
if (d_session.is_null()) {
return(TT_ERR_SESSION);
}
rstatus = d_session->call(TT_RPC_CLOSE_PROCID,
(xdrproc_t)tt_xdr_procid,
(char *)&proc,
(xdrproc_t)xdr_int,
(char *)&status);
if (!d_session.is_eq(initial_session)) {
// check to see if this is the last procid to
// reference this session (this could be done quicker
// by just checking the _refcount_ on the session but
// then we'd have to be careful not to have any other
// references to this session or else we'd fail to
// remove it from the session cache)
procs.reset(active_procs);
remove_session = 1;
while (procs.next()) {
cp = (_Tt_c_procid *)(*procs).c_pointer();
if (cp->default_session()->address_string() ==
d_session->address_string()) {
remove_session = 0;
break;
}
}
// unlink d_session and remove from session cache if
// this is the last procid to be using it.
if (remove_session) {
_session_cache->remove(d_session->address_string());
}
}
// this should cause the session to be disconnected if
// remove_session is set since the last remaining
// pointer to the session should be _default_session.
// unless it's the initial session in which case it
// should stay around.
_Tt_string nullprocid = (char*)0;
cp->set_default_session(nullprocid);
// Zero out the default procid if it matches the passed-in -- i.e.
// thread-specific -- procid.
if (proc.is_eq(_default_c_procid)) {
_default_c_procid = (_Tt_c_procid *)0;
}
#ifdef OPT_XTHREADS
// Free the storage for the thread-specific procid
_Tt_threadspecific* tss = (_Tt_threadspecific *) 0;
xthread_get_specific(_tt_global->threadkey, (void **) &tss);
if (tss) {
tss->free_procid();
}
#endif
if (rstatus != TT_OK) {
status = rstatus;
}
return(status);
}
//
// Creates a new procid. If this is the first procid to be created then
// we need to check for the start token being set which indicates this
// procid was activated in response to a tooltalk start message. If this
// is the case then this procid is "commited" to the default session.
//
Tt_status _Tt_c_mp::
create_new_procid()
{
Tt_status status;
const char *start_token;
int commit = 0;
_Tt_string session;
_Tt_c_procid *cp = new _Tt_c_procid();
_Tt_c_procid_ptr cpp = cp;
// initialize default procid
_default_c_procid = cp;
#ifdef OPT_XTHREADS
if (_tt_global->multithreaded()){
_Tt_threadspecific* tss = (_Tt_threadspecific *) 0;
xthread_get_specific(_tt_global->threadkey, (void **) &tss);
if (!tss) {
// thread-specific storage not yet initialized -- do it
tss = new _Tt_threadspecific(default_c_session, cpp);
xthread_set_specific(_tt_global->threadkey, tss);
} else {
tss->set_thread_c_procid(cpp);
}
}
#endif
//
// Check if there is a START_MESSAGE for us.
//
start_token = _tt_get_first_set_env_var(2, TT_CDE_START_TOKEN, TT_START_TOKEN);
session = _tt_get_first_set_env_var(2, TT_CDE_XATOM_NAME, TT_XATOM_NAME);
if ((start_token != 0 && *start_token != 0 )
&& default_c_session->has_id(session)) {
cp->set_start_token(start_token);
commit = 1;
//
// now clear the value of this environment variable so
// that subsequent children of this process don't get
// confused.
//
// This is done in a really ugly fashion, because older
// versions of the ToolTalk library on Sun assumed that the
// token was there if the _TT_TOKEN environment variable
// existed, even if the value (after the '=') was null.
// Unfortunately there is no portable way to completely
// remove a environment variable from the environment. The
// best we can do is change the environment variable name.
// Since we're already being ugly, we do this in the brutal
// fashion of just backing up from the environment variable
// value into the name and punching over one of the
// characters. In particular, we change the 4th character
// in front of the equals sign (the 5th character in front
// of the value) to an "A". This changes _TT_TOKEN to
// _TT_TAKEN and _SUN_TT_TOKEN to _SUN_TT_TAKEN. This looks
// OK enough (the token's been taken) that maybe people
// looking in the environment won't be upset.
char *p;
p = getenv(TT_CDE_START_TOKEN);
if (p) {
*(p-5) = 'A';
}
p = getenv(TT_START_TOKEN);
if (p) {
*(p-5) = 'A';
}
}
status = cp->init();
if (commit) {
// we should check for TT_CDE_START_TOKEN or
// TT_START_TOKEN to be set. If
// so then we commit this procid which is required to
// join the session which caused this process to be
// started.
(void)cp->commit();
}
if (status != TT_OK) {
_default_c_procid = (_Tt_c_procid *)0;
#ifdef OPT_XTHREADS
_Tt_threadspecific* tss = (_Tt_threadspecific *) 0;
xthread_get_specific(_tt_global->threadkey, (void **) &tss);
if (!tss) {
// thread-specific storage not yet initialized -- do it
tss = new _Tt_threadspecific(default_c_session,
(_Tt_c_procid *) 0);
xthread_set_specific(_tt_global->threadkey, tss);
}
else {
tss->free_procid();
}
#endif
return(status);
}
active_procs->insert(default_c_procid());
return(TT_OK);
}
//
// Returns a count of how many procids are in the active procid cache.
//
int _Tt_c_mp::
procid_count()
{
if (active_procs.is_null()) {
return(0);
} else {
return(active_procs->count());
}
}
#ifdef OPT_XTHREADS
//
// Initializes structures needed for multithreading
//
void _Tt_c_mp::
set_multithreaded()
{
if (_tt_global->multithreaded()) {
_Tt_threadspecific* tss =
new _Tt_threadspecific(default_c_session,
(_Tt_c_procid *) 0);
xthread_set_specific(_tt_global->threadkey, tss);
}
}
#endif