/*{ ** Name: MOset - set value associated with an instance ** ** Description: ** ** Attempts to set the value associated with the instance. ** ** If the call succeeds, it must also call the monitors for the ** class with the MO_SET event, the instance id, and the new value. ** Inputs: ** valid_perms ** the roles currently in effect, to be and-ed with object ** permissions to determine access rights. ** class ** the class whose value should be altered. ** instance ** the instance in question. ** val ** pointer to the string containing the new value. ** Outputs: ** none ** Returns: ** OK ** if the value was set ** MO_NO_INSTANCE ** if the class is not attached ** MO_NO_WRITE ** if the class may not be changed. ** other ** error status returned by a method. ** History: ** 23-sep-92 (daveb) ** documented ** 6-Apr-04 (gordy) ** Permit access if MO_ANY_WRITE attribute is set. ** 24-Oct-05 (toumi01) BUG 115449 ** Don't hold onto MO mutex if class' processing will try ** to take the mutex, and would thus deadlock on ourself. */ STATUS MOset(i4 valperms, char *classid, char *instance, char *val ) { STATUS stat = OK; MO_CLASS *cp; PTR idata; MO_once(); stat = MO_mutex(); if( stat != OK ) return( stat ); MO_nset++; /* get class and instance data */ if( OK == (stat = MO_getclass( classid, &cp ) ) ) { if( (cp->perms & MO_ANY_WRITE) != 0 || (valperms & MO_WRITE & cp->perms) != 0 ) stat = (*cp->idx)( MO_GET, cp->cdata, 0, instance, &idata ); else stat = MO_NO_WRITE; } if( stat == OK ) { if (cp->cflags & MO_NO_MUTEX) (VOID) MO_unmutex(); stat = (*cp->set)( cp->offset, 0, val, cp->size, idata ); if (cp->cflags & MO_NO_MUTEX) { stat = MO_mutex(); if( stat != OK ) return( stat ); } } if( stat == OK ) (VOID) MO_tell_class( cp, instance, val, MO_SET ); (VOID) MO_unmutex(); return( stat ); }
VOID MO_once(void) { i4 state; if( MO_classes == NULL ) { /* tricky recursion problem here -- i_sem wants to do an attach, but we aren't ready. This means no monitoring of MO_sem, sigh. FIXME. */ state = MO_disabled; MO_disabled = MO_DISABLE; (VOID) MUi_semaphore( &MO_sem ); MUn_semaphore( &MO_sem, "MO" ); MO_semcnt = 0; MO_disabled = (state) ? TRUE : FALSE; (VOID) MO_mutex(); MUn_semaphore( &MO_sem, "MO" ); MO_classes = SPinit( &MOclass_tree, STcompare ); MO_instances = SPinit( &MOinstance_tree, MO_instance_compare ); MO_strings = SPinit( &MOstring_tree, STcompare ); MO_monitors = SPinit( &MOmonitor_tree, MO_mon_compare ); (VOID) MO_unmutex(); /* MO classes */ (void) MOclassdef( MAXI2, MO_cdefs ); (void) MOclassdef( MAXI2, MO_mem_classes ); (void) MOclassdef( MAXI2, MO_meta_classes ); (void) MOclassdef( MAXI2, MO_mon_classes ); (void) MOclassdef( MAXI2, MO_str_classes ); (void) MOclassdef( MAXI4, MO_tree_classes ); /* tables */ MO_classes->name = "mo_classes"; MO_instances->name = "mo_instances"; MO_strings->name = "mo_strings"; MO_monitors->name = "mo_monitors"; (void) MOsptree_attach( MO_classes ); (void) MOsptree_attach( MO_instances ); (void) MOsptree_attach( MO_strings ); (void) MOsptree_attach( MO_monitors ); } }
STATUS MOon_off( i4 operation, i4 *old_state ) { STATUS stat = OK; stat = MO_mutex(); if( stat != OK ) return( stat ); *old_state = MO_disabled; if( operation != MO_INQUIRE ) MO_disabled = (operation) ? TRUE : FALSE; (VOID) MO_unmutex(); return( stat ); }
STATUS MOget(i4 valperms, char *classid, char *instance, i4 *lsbufp, char *sbuf, i4 *operms ) { STATUS stat; MO_once(); stat = MO_mutex(); if( stat == OK ) { stat = MO_get( valperms, classid, instance, lsbufp, sbuf, operms ); (VOID) MO_unmutex(); } return( stat ); }
STATUS MOtell_monitor( char *classid, char *instance, char *value, i4 msg ) { MO_CLASS *cp; STATUS ret_val = OK; MO_once(); ret_val = MO_mutex(); if( ret_val == OK ) { ret_val = MO_getclass( classid, &cp ); if( ret_val == OK && cp->monitor != NULL ) ret_val = MO_tell_class( cp, instance, value, msg ); (VOID) MO_unmutex(); } return( ret_val ); }
/*{ ** Name: MOdetach - detach an attached instance ** ** Description: ** ** Detaches an attached instance. Subsequent attempts to get or ** set it will fail, and an attempts to attach it will succeed. ** ** Frees memory allocated by MOattach using MEfree. ** ** If the call succeeds, it must also call the monitors for the ** class with the MO_DETACH event, the instance id, and a NULL ** value. ** ** Inputs: ** classid ** the classid of the object. ** instance ** the instance of the object. ** Outputs: ** none ** Returns: ** OK ** if the classid was detached. ** MO_NO_INSTANCE ** if classid is not attached. ** MO_NO_DETACH ** if the object was attached as MO_PERMANENT. ** ** History: ** 15-jul-92 (daveb) ** Go back to single-instance attach/detach, as with ** MOcdata_index most bulky static one-offs will be ** right in the class definitions anyway, and this ** is simpler for the dynamic attach. ** 02-sep-1999 (somsa01) ** We were calling MO_tell_class AFTER releasing the MO mutex. */ STATUS MOdetach( char *classid, char *instance ) { MO_INSTANCE *ip; MO_CLASS *cp; STATUS stat = OK; STATUS mutex_stat = OK; MO_once(); mutex_stat = MO_mutex(); do { if( mutex_stat != OK ) /* got mutex */ break; MO_ndetach++; ip = MO_getinstance( classid, instance ); if( NULL == ip ) { stat = MO_NO_INSTANCE; break; } cp = ip->classdef; if( cp->perms & MO_PERMANENT ) { stat = MO_NO_DETACH; break; } /* ** We have detachable instance, do it */ /* detach twin, if any, giving up it it won't go away */ if( CMalpha( classid ) && NULL != cp->twin && (stat = MOdetach( cp->twin->node.key, ip->instance)) != OK ) break; /* delete saved instance string */ if( (ip->iflags & MO_INSTANCE_VAR) != 0 ) MO_delstring( ip->instance ); /* and finally delete this node */ SPdelete( &ip->node, MO_instances ); MO_free( (PTR)ip, sizeof(*ip) ); } while( FALSE ); if( mutex_stat == OK ) (VOID) MO_unmutex(); else stat = mutex_stat; if( stat == OK ) { if ( (stat = MO_mutex()) == OK) { (VOID) MO_tell_class( cp, instance, (char *)NULL, MO_DETACH ); MO_unmutex (); } } return( stat ); }
STATUS MOattach( i4 flags, char *classid, char *instance, PTR idata ) { MO_INSTANCE *ip; MO_CLASS *cp; STATUS stat; stat = OK; if( MO_disabled ) return( stat ); MO_once(); stat = MO_mutex(); if( stat == OK ) /* got mutex */ { do { if( stat != OK ) break; MO_nattach++; # ifdef xDEBUG SIprintf("attach %s:%s object %p\n", classid, instance, idata ); # endif /* check for special error cases */ ip = MO_getinstance( classid, instance ); if( ip != NULL ) { stat = MO_ALREADY_ATTACHED; break; } /* Get class, error if missing */ if( OK != MO_getclass( classid, &cp ) ) { stat = MO_NO_CLASSID; break; } /* Release mutex to prevent deadlock in MO_alloc call */ (VOID) MO_unmutex(); ip = (MO_INSTANCE *)MO_alloc( sizeof(*ip), &stat ); stat = MO_mutex(); if( NULL == ip ) break; ip->classdef = cp; ip->iflags = flags; if( (flags & MO_INSTANCE_VAR) == 0 ) { ip->instance = instance; } else { ip->instance = MO_defstring( instance, &stat ); if( ip->instance == NULL ) { MO_free( (PTR)ip, sizeof(*ip) ); break; } } ip->idata = idata; ip->node.key = (PTR)ip; (VOID) SPenq( &ip->node, MO_instances ); } while( FALSE ); (VOID) MO_unmutex(); /* Attach twin if needed */ if( stat == OK && cp->twin != NULL && !CMdigit( (char *)cp->node.key ) ) stat = MOattach( flags, cp->twin->node.key, instance, idata ); } # if xDEBUG if( stat != OK ) TRdisplay("attach (%s:%s) failed status %d\n", classid, instance, stat ); # endif if( stat == OK ) { if ( (stat = MO_mutex()) == OK) { (VOID) MO_tell_class( cp, instance, (char *)NULL, MO_ATTACH ); MO_unmutex (); } } return( stat ); }
STATUS MOset_monitor( char *classid, PTR mon_data, char *qual_regexp, MO_MONITOR_FUNC *monitor, MO_MONITOR_FUNC **old_monitor ) { MO_MON_BLOCK *mp; /* our monitor block */ MO_MON_BLOCK *fmp; /* first monitor block */ MO_MON_BLOCK *pmp; /* previous monitor block */ MO_CLASS *cp; /* class in question (not classid) */ char *saved_qual = NULL; STATUS ret_val = OK; STATUS mutex_stat; mutex_stat = MO_mutex(); do { if( mutex_stat != OK ) break; /* if we'll need it, save any qual_regexp string */ if( monitor != NULL && qual_regexp != NULL ) { saved_qual = MO_defstring( qual_regexp, &ret_val ); if( saved_qual == NULL ) break; /* FIXME maybe compile it here too? */ } /* locate the class def, we need it everywhere */ if( (ret_val = MO_getclass( classid, &cp )) != OK ) break; /* see if this is a replacement for an existing monitor */ mp = NULL; if( (mp = MO_getmon( cp, mon_data ) ) != NULL ) { /* yes, replace it with new values as appropriate */ *old_monitor = mp->monitor; if( monitor == NULL ) /* delete this monitor */ { MO_delmon( mp ); } else /* replace this one's values */ { mp->monitor = monitor; mp->mon_data = mon_data; /* delete old qual string */ if( mp->qual_regexp != NULL ) MO_delstring( mp->qual_regexp ); mp->qual_regexp = saved_qual; } } else if( monitor == NULL ) /* huh!? */ { ret_val = MO_BAD_MONITOR; break; } else /* make a new one and link it in. */ { *old_monitor = NULL; /* if it's an OID, get the class def instead */ if( CMdigit( (char *)cp->node.key ) && cp->twin != NULL ) cp = cp->twin; /* get a new monitor block */ mp = (MO_MON_BLOCK *)MO_alloc( sizeof( *mp ), &ret_val ); if( mp == NULL ) break; /* fill in the new block, and link in to the tree */ mp->node.key = (PTR)mp; mp->mo_class = cp; mp->monitor = monitor; mp->mon_data = mon_data; mp->qual_regexp = saved_qual; (void) SPenq( &mp->node, MO_monitors ); /* Fill in the class with first monitor for the class. The loop below goes backwards until pmp is null or doesn't have the same class definition. When it exits, fmp is at the first monitor block for the class */ for( fmp = mp; (pmp = (MO_MON_BLOCK *)SPfprev( &fmp->node )) != NULL && pmp->mo_class == cp; fmp = pmp ) continue; fmp->mo_class->monitor = fmp; if( cp->twin ) cp->twin->monitor = fmp; } } while ( FALSE ); if( mutex_stat != OK ) { ret_val = mutex_stat; } else { if( ret_val == OK ) MO_nset_monitor++; else if( saved_qual != NULL ) MO_delstring( saved_qual ); (void) MO_unmutex(); } return( ret_val ); }