Beispiel #1
0
/*
 * prop_object_release --
 *	Decrement the reference count on an object.
 *
 *	Free the object if we are releasing the final
 *	reference.
 */
void
prop_object_release(prop_object_t obj)
{
	struct _prop_object *po;
	struct _prop_stack stack;
	void (*unlock)(void); 
	int ret;
	uint32_t ocnt;

	_prop_stack_init(&stack);

	do {
		do {
			po = obj;
			_PROP_ASSERT(obj);

			if (po->po_type->pot_lock != NULL)
				po->po_type->pot_lock();

			/* Save pointer to object unlock function */
			unlock = po->po_type->pot_unlock;
			
			_PROP_ATOMIC_DEC32_NV(&po->po_refcnt, ocnt);
			ocnt++;
			_PROP_ASSERT(ocnt != 0);

			if (ocnt != 1) {
				ret = 0;
				if (unlock != NULL)
					unlock();
				break;
			}
			
			ret = (po->po_type->pot_free)(&stack, &obj);

			if (unlock != NULL)
				unlock();

			if (ret == _PROP_OBJECT_FREE_DONE)
				break;
			
			_PROP_ATOMIC_INC32(&po->po_refcnt);
		} while (ret == _PROP_OBJECT_FREE_RECURSE);
		if (ret == _PROP_OBJECT_FREE_FAILED)
			prop_object_release_emergency(obj);
	} while (_prop_stack_pop(&stack, &obj, NULL, NULL, NULL));
}
Beispiel #2
0
static void
_prop_array_emergency_free(prop_object_t obj)
{
	prop_array_t pa = obj;

	_PROP_ASSERT(pa->pa_count != 0);
	--pa->pa_count;
}
Beispiel #3
0
static _prop_object_free_rv_t
_prop_array_free(prop_stack_t stack, prop_object_t *obj)
{
	prop_array_t pa = *obj;
	prop_object_t po;

	_PROP_ASSERT(pa->pa_count <= pa->pa_capacity);
	_PROP_ASSERT((pa->pa_capacity == 0 && pa->pa_array == NULL) ||
		     (pa->pa_capacity != 0 && pa->pa_array != NULL));

	/* The easy case is an empty array, just free and return. */
	if (pa->pa_count == 0) {
		if (pa->pa_array != NULL)
			_PROP_FREE(pa->pa_array, M_PROP_ARRAY);

		_PROP_RWLOCK_DESTROY(pa->pa_rwlock);

		_PROP_POOL_PUT(_prop_array_pool, pa);

		return (_PROP_OBJECT_FREE_DONE);
	}
	if (pa->pa_array == NULL)
		return _PROP_OBJECT_FREE_DONE;

	po = pa->pa_array[pa->pa_count - 1];
	_PROP_ASSERT(po != NULL);

	if (stack == NULL) {
		/*
		 * If we are in emergency release mode,
		 * just let caller recurse down.
		 */
		*obj = po;
		return (_PROP_OBJECT_FREE_FAILED);
	}

	/* Otherwise, try to push the current object on the stack. */
	if (!_prop_stack_push(stack, pa, NULL, NULL, NULL)) {
		/* Push failed, entering emergency release mode. */
		return (_PROP_OBJECT_FREE_FAILED);
	}
	/* Object pushed on stack, caller will release it. */
	--pa->pa_count;
	*obj = po;
	return (_PROP_OBJECT_FREE_RECURSE);
}
Beispiel #4
0
/*
 * prop_object_retain --
 *	Increment the reference count on an object.
 */
void
prop_object_retain(prop_object_t obj)
{
	struct _prop_object *po = obj;
	uint32_t ncnt;

	ncnt = atomic_inc_32_nv(&po->po_refcnt);
	_PROP_ASSERT(ncnt != 0);
}
Beispiel #5
0
bool
prop_object_equals_with_error(prop_object_t obj1, prop_object_t obj2,
    bool *error_flag)
{
	struct _prop_object *po1;
	struct _prop_object *po2;
	void *stored_pointer1, *stored_pointer2;
	prop_object_t next_obj1, next_obj2;
	struct _prop_stack stack;
	_prop_object_equals_rv_t ret;

	_prop_stack_init(&stack);
	if (error_flag)
		*error_flag = false;

 start_subtree:
	stored_pointer1 = NULL;
	stored_pointer2 = NULL;
	po1 = obj1;
	po2 = obj2;

	if (po1->po_type != po2->po_type)
		return (false);
    
 continue_subtree:
	ret = (*po1->po_type->pot_equals)(obj1, obj2,
					  &stored_pointer1, &stored_pointer2,
					  &next_obj1, &next_obj2);
	if (ret == _PROP_OBJECT_EQUALS_FALSE)
		goto finish;
	if (ret == _PROP_OBJECT_EQUALS_TRUE) {
		if (!_prop_stack_pop(&stack, &obj1, &obj2,
				     &stored_pointer1, &stored_pointer2))
			return true;
		po1 = obj1;
		po2 = obj2;
		goto continue_subtree;
	}
	_PROP_ASSERT(ret == _PROP_OBJECT_EQUALS_RECURSE);

	if (!_prop_stack_push(&stack, obj1, obj2,
			      stored_pointer1, stored_pointer2)) {
		if (error_flag)
			*error_flag = true;
		goto finish;
	}
	obj1 = next_obj1;
	obj2 = next_obj2;
	goto start_subtree;

finish:
	while (_prop_stack_pop(&stack, &obj1, &obj2, NULL, NULL)) {
		po1 = obj1;
		(*po1->po_type->pot_equals_finish)(obj1, obj2);
	}
	return (false);		
}
Beispiel #6
0
/*
 * prop_object_retain --
 *	Increment the reference count on an object.
 */
void
prop_object_retain(prop_object_t obj)
{
	struct _prop_object *po = obj;
	uint32_t ncnt __unused;

	_PROP_ATOMIC_INC32_NV(&po->po_refcnt, ncnt);
	_PROP_ASSERT(ncnt != 0);
}
Beispiel #7
0
static void
_prop_array_iterator_reset_locked(void *v)
{
	struct _prop_array_iterator *pai = v;
	prop_array_t pa = pai->pai_base.pi_obj;

	_PROP_ASSERT(prop_object_is_array(pa));

	pai->pai_index = 0;
	pai->pai_base.pi_version = pa->pa_version;
}
Beispiel #8
0
static void
_prop_array_iterator_reset(void *v)
{
	struct _prop_array_iterator *pai = v;
	prop_array_t pa = pai->pai_base.pi_obj;

	_PROP_ASSERT(prop_object_is_array(pa));

	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
	_prop_array_iterator_reset_locked(pai);
	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
}
Beispiel #9
0
/*
 * prop_object_retain --
 *	Increment the reference count on an object.
 */
void
prop_object_retain(prop_object_t obj)
{
	struct _prop_object *po = obj;
	uint32_t ocnt;

	_PROP_REFCNT_LOCK();
	ocnt = po->po_refcnt++;
	_PROP_REFCNT_UNLOCK();

	_PROP_ASSERT(ocnt != 0xffffffffU);
}
Beispiel #10
0
static bool
_prop_array_externalize(struct _prop_object_externalize_context *ctx,
			void *v)
{
	prop_array_t pa = v;
	struct _prop_object *po;
	prop_object_iterator_t pi;
	unsigned int i;
	bool rv = false;

	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);

	if (pa->pa_count == 0) {
		_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
		return (_prop_object_externalize_empty_tag(ctx, "array"));
	}

	/* XXXJRT Hint "count" for the internalize step? */
	if (_prop_object_externalize_start_tag(ctx, "array") == false ||
	    _prop_object_externalize_append_char(ctx, '\n') == false)
		goto out;

	pi = _prop_array_iterator_locked(pa);
	if (pi == NULL)
		goto out;

	ctx->poec_depth++;
	_PROP_ASSERT(ctx->poec_depth != 0);

	while ((po = _prop_array_iterator_next_object_locked(pi)) != NULL) {
		if ((*po->po_type->pot_extern)(ctx, po) == false) {
			prop_object_iterator_release(pi);
			goto out;
		}
	}

	prop_object_iterator_release(pi);

	ctx->poec_depth--;
	for (i = 0; i < ctx->poec_depth; i++) {
		if (_prop_object_externalize_append_char(ctx, '\t') == false)
			goto out;
	}
	if (_prop_object_externalize_end_tag(ctx, "array") == false)
		goto out;

	rv = true;

 out:
	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
	return (rv);
}
Beispiel #11
0
/*
 * prop_object_release --
 *	Decrement the reference count on an object.
 *
 *	Free the object if we are releasing the final
 *	reference.
 */
void
prop_object_release(prop_object_t obj)
{
	struct _prop_object *po;
	struct _prop_stack stack;
	int ret;
	uint32_t ocnt;

	_prop_stack_init(&stack);

	do {
		do {
			po = obj;
			_PROP_ASSERT(obj);

			_PROP_REFCNT_LOCK();
			ocnt = po->po_refcnt--;
			_PROP_REFCNT_UNLOCK();

			_PROP_ASSERT(ocnt != 0);
			if (ocnt != 1) {
				ret = 0;
				break;
			}

			ret = (po->po_type->pot_free)(&stack, &obj);

			if (ret == _PROP_OBJECT_FREE_DONE)
				break;
			
			_PROP_REFCNT_LOCK();
			++po->po_refcnt;
			_PROP_REFCNT_UNLOCK();
		} while (ret == _PROP_OBJECT_FREE_RECURSE);
		if (ret == _PROP_OBJECT_FREE_FAILED)
			prop_object_release_emergency(obj);
	} while (_prop_stack_pop(&stack, &obj, NULL, NULL, NULL));
}
Beispiel #12
0
/*
 * _prop_object_externalize_append_char --
 *	Append a single character to the externalize buffer.
 */
bool
_prop_object_externalize_append_char(
    struct _prop_object_externalize_context *ctx, unsigned char c)
{

	_PROP_ASSERT(ctx->poec_capacity != 0);
	_PROP_ASSERT(ctx->poec_buf != NULL);
	_PROP_ASSERT(ctx->poec_len <= ctx->poec_capacity);

	if (ctx->poec_len == ctx->poec_capacity) {
		char *cp = _PROP_REALLOC(ctx->poec_buf,
					 ctx->poec_capacity + BUF_EXPAND,
					 M_TEMP);
		if (cp == NULL)
			return (false);
		ctx->poec_capacity = ctx->poec_capacity + BUF_EXPAND;
		ctx->poec_buf = cp;
	}

	ctx->poec_buf[ctx->poec_len++] = c;

	return (true);
}
Beispiel #13
0
static prop_object_t
_prop_array_iterator_next_object_locked(void *v)
{
	struct _prop_array_iterator *pai = v;
	prop_array_t pa = pai->pai_base.pi_obj;
	prop_object_t po = NULL;

	_PROP_ASSERT(prop_object_is_array(pa));

	if (pa->pa_version != pai->pai_base.pi_version)
		goto out;	/* array changed during iteration */

	_PROP_ASSERT(pai->pai_index <= pa->pa_count);

	if (pai->pai_index == pa->pa_count)
		goto out;	/* we've iterated all objects */

	po = pa->pa_array[pai->pai_index];
	pai->pai_index++;

 out:
	return (po);
}
Beispiel #14
0
static prop_object_t
_prop_array_iterator_next_object(void *v)
{
	struct _prop_array_iterator *pai = v;
	prop_array_t pa = pai->pai_base.pi_obj;
	prop_object_t po;

	_PROP_ASSERT(prop_object_is_array(pa));

	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
	po = _prop_array_iterator_next_object_locked(pai);
	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
	return (po);
}
Beispiel #15
0
/*
 * prop_array_set --
 *	Store a reference to an object at the specified array index.
 *	This method is not allowed to create holes in the array; the
 *	caller must either be setting the object just beyond the existing
 *	count or replacing an already existing object reference.
 */
bool
prop_array_set(prop_array_t pa, unsigned int idx, prop_object_t po)
{
	prop_object_t opo;
	bool rv = false;

	if (! prop_object_is_array(pa))
		return (false);

	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);

	if (prop_array_is_immutable(pa))
		goto out;

	if (idx == pa->pa_count) {
		rv = _prop_array_add(pa, po);
		goto out;
	}

	_PROP_ASSERT(idx < pa->pa_count);

	opo = pa->pa_array[idx];
	_PROP_ASSERT(opo != NULL);

	prop_object_retain(po);
	pa->pa_array[idx] = po;
	pa->pa_version++;

	prop_object_release(opo);

	rv = true;

 out:
	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
	return (rv);
}
Beispiel #16
0
/*
 * prop_array_get --
 *	Return the object stored at the specified array index.
 */
prop_object_t
prop_array_get(prop_array_t pa, unsigned int idx)
{
	prop_object_t po = NULL;

	if (! prop_object_is_array(pa))
		return (NULL);

	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
	if (idx >= pa->pa_count)
		goto out;
	po = pa->pa_array[idx];
	_PROP_ASSERT(po != NULL);
 out:
	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
	return (po);
}
Beispiel #17
0
static bool
_prop_array_add(prop_array_t pa, prop_object_t po)
{

	/*
	 * Array must be WRITE-LOCKED.
	 */

	_PROP_ASSERT(pa->pa_count <= pa->pa_capacity);

	if (prop_array_is_immutable(pa) ||
	    (pa->pa_count == pa->pa_capacity &&
	    _prop_array_expand(pa, pa->pa_capacity + EXPAND_STEP) == false))
		return (false);

	prop_object_retain(po);
	pa->pa_array[pa->pa_count++] = po;
	pa->pa_version++;

	return (true);
}
Beispiel #18
0
/*
 * _prop_object_internalize_decode_string --
 *	Decode an encoded string.
 */
bool
_prop_object_internalize_decode_string(
				struct _prop_object_internalize_context *ctx,
				char *target, size_t targsize, size_t *sizep,
				const char **cpp)
{
	const char *src;
	size_t tarindex;
	char c;
	
	tarindex = 0;
	src = ctx->poic_cp;

	for (;;) {
		if (_PROP_EOF(*src))
			return (false);
		if (*src == '<') {
			break;
		}

		if ((c = *src) == '&') {
			if (src[1] == 'a' &&
			    src[2] == 'm' &&
			    src[3] == 'p' &&
			    src[4] == ';') {
			    	c = '&';
				src += 5;
			} else if (src[1] == 'l' &&
				   src[2] == 't' &&
				   src[3] == ';') {
				c = '<';
				src += 4;
			} else if (src[1] == 'g' &&
				   src[2] == 't' &&
				   src[3] == ';') {
				c = '>';
				src += 4;
			} else if (src[1] == 'a' &&
				   src[2] == 'p' &&
				   src[3] == 'o' &&
				   src[4] == 's' &&
				   src[5] == ';') {
				c = '\'';
				src += 6;
			} else if (src[1] == 'q' &&
				   src[2] == 'u' &&
				   src[3] == 'o' &&
				   src[4] == 't' &&
				   src[5] == ';') {
				c = '\"';
				src += 6;
			} else
				return (false);
		} else
			src++;
		if (target) {
			if (tarindex >= targsize)
				return (false);
			target[tarindex] = c;
		}
		tarindex++;
	}

	_PROP_ASSERT(*src == '<');
	if (sizep != NULL)
		*sizep = tarindex;
	if (cpp != NULL)
		*cpp = src;
	
	return (true);
}
Beispiel #19
0
/*
 * _prop_object_internalize_find_tag --
 *	Find the next tag in an XML stream.  Optionally compare the found
 *	tag to an expected tag name.  State of the context is undefined
 *	if this routine returns false.  Upon success, the context points
 *	to the first octet after the tag.
 */
bool
_prop_object_internalize_find_tag(struct _prop_object_internalize_context *ctx,
		      const char *tag, _prop_tag_type_t type)
{
	const char *cp;
	size_t taglen;

	if (tag != NULL)
		taglen = strlen(tag);
	else
		taglen = 0;

 start_over:
	cp = ctx->poic_cp;

	/*
	 * Find the start of the tag.
	 */
	while (_PROP_ISSPACE(*cp))
		cp++;
	if (_PROP_EOF(*cp))
		return (false);

	if (*cp != '<')
		return (false);

	ctx->poic_tag_start = cp++;
	if (_PROP_EOF(*cp))
		return (false);

	if (*cp == '!') {
		if (cp[1] != '-' || cp[2] != '-')
			return (false);
		/*
		 * Comment block -- only allowed if we are allowed to
		 * return a start tag.
		 */
		if (type == _PROP_TAG_TYPE_END)
			return (false);
		ctx->poic_cp = cp + 3;
		if (_prop_object_internalize_skip_comment(ctx) == false)
			return (false);
		goto start_over;
	}

	if (*cp == '/') {
		if (type != _PROP_TAG_TYPE_END &&
		    type != _PROP_TAG_TYPE_EITHER)
			return (false);
		cp++;
		if (_PROP_EOF(*cp))
			return (false);
		ctx->poic_tag_type = _PROP_TAG_TYPE_END;
	} else {
		if (type != _PROP_TAG_TYPE_START &&
		    type != _PROP_TAG_TYPE_EITHER)
			return (false);
		ctx->poic_tag_type = _PROP_TAG_TYPE_START;
	}

	ctx->poic_tagname = cp;

	while (!_PROP_ISSPACE(*cp) && *cp != '/' && *cp != '>')
		cp++;
	if (_PROP_EOF(*cp))
		return (false);

	ctx->poic_tagname_len = cp - ctx->poic_tagname;

	/* Make sure this is the tag we're looking for. */
	if (tag != NULL &&
	    (taglen != ctx->poic_tagname_len ||
	     memcmp(tag, ctx->poic_tagname, taglen) != 0))
		return (false);
	
	/* Check for empty tag. */
	if (*cp == '/') {
		if (ctx->poic_tag_type != _PROP_TAG_TYPE_START)
			return(false);		/* only valid on start tags */
		ctx->poic_is_empty_element = true;
		cp++;
		if (_PROP_EOF(*cp) || *cp != '>')
			return (false);
	} else
		ctx->poic_is_empty_element = false;

	/* Easy case of no arguments. */
	if (*cp == '>') {
		ctx->poic_tagattr = NULL;
		ctx->poic_tagattr_len = 0;
		ctx->poic_tagattrval = NULL;
		ctx->poic_tagattrval_len = 0;
		ctx->poic_cp = cp + 1;
		return (true);
	}

	_PROP_ASSERT(!_PROP_EOF(*cp));
	cp++;
	if (_PROP_EOF(*cp))
		return (false);

	while (_PROP_ISSPACE(*cp))
		cp++;
	if (_PROP_EOF(*cp))
		return (false);

	ctx->poic_tagattr = cp;

	while (!_PROP_ISSPACE(*cp) && *cp != '=')
		cp++;
	if (_PROP_EOF(*cp))
		return (false);

	ctx->poic_tagattr_len = cp - ctx->poic_tagattr;
	
	cp++;
	if (*cp != '\"')
		return (false);
	cp++;
	if (_PROP_EOF(*cp))
		return (false);
	
	ctx->poic_tagattrval = cp;
	while (*cp != '\"')
		cp++;
	if (_PROP_EOF(*cp))
		return (false);
	ctx->poic_tagattrval_len = cp - ctx->poic_tagattrval;
	
	cp++;
	if (*cp != '>')
		return (false);

	ctx->poic_cp = cp + 1;
	return (true);
}