Home | History | Annotate | Download | only in src
      1 /*
      2  INTEL CONFIDENTIAL
      3  Copyright 2009 Intel Corporation All Rights Reserved.
      4  The source code contained or described herein and all documents related to the source code ("Material") are owned by Intel Corporation or its suppliers or licensors. Title to the Material remains with Intel Corporation or its suppliers and licensors. The Material contains trade secrets and proprietary and confidential information of Intel or its suppliers and licensors. The Material is protected by worldwide copyright and trade secret laws and treaty provisions. No part of the Material may be used, copied, reproduced, modified, published, uploaded, posted, transmitted, distributed, or disclosed in any way without Intels prior express written permission.
      5 
      6  No license under any patent, copyright, trade secret or other intellectual property right is granted to or conferred upon you by disclosure or delivery of the Materials, either expressly, by implication, inducement, estoppel or otherwise. Any license under such intellectual property rights must be express and approved by Intel in writing.
      7  */
      8 
      9 /**
     10  * SECTION:mixbufferpool
     11  * @short_description: MI-X Input Buffer Pool
     12  *
     13  * A data object which stores and manipulates a pool of compressed video buffers.
     14  */
     15 
     16 #include "mixvideolog.h"
     17 #include "mixbufferpool.h"
     18 #include "mixbuffer_private.h"
     19 
     20 #define MIX_LOCK(lock) g_mutex_lock(lock);
     21 #define MIX_UNLOCK(lock) g_mutex_unlock(lock);
     22 
     23 #define SAFE_FREE(p) if(p) { g_free(p); p = NULL; }
     24 
     25 static GType _mix_bufferpool_type = 0;
     26 static MixParamsClass *parent_class = NULL;
     27 
     28 #define _do_init { _mix_bufferpool_type = g_define_type_id; }
     29 
     30 gboolean mix_bufferpool_copy(MixParams * target, const MixParams * src);
     31 MixParams *mix_bufferpool_dup(const MixParams * obj);
     32 gboolean mix_bufferpool_equal(MixParams * first, MixParams * second);
     33 static void mix_bufferpool_finalize(MixParams * obj);
     34 
     35 G_DEFINE_TYPE_WITH_CODE (MixBufferPool, mix_bufferpool, MIX_TYPE_PARAMS,
     36 		_do_init);
     37 
     38 static void mix_bufferpool_init(MixBufferPool * self) {
     39 	/* initialize properties here */
     40 	self->free_list = NULL;
     41 	self->in_use_list = NULL;
     42 	self->free_list_max_size = 0;
     43 	self->high_water_mark = 0;
     44 
     45 	self->reserved1 = NULL;
     46 	self->reserved2 = NULL;
     47 	self->reserved3 = NULL;
     48 	self->reserved4 = NULL;
     49 
     50 	// TODO: relocate this mutex allocation -we can't communicate failure in ctor.
     51 	// Note that g_thread_init() has already been called by mix_video_init()
     52 	self->objectlock = g_mutex_new();
     53 
     54 }
     55 
     56 static void mix_bufferpool_class_init(MixBufferPoolClass * klass) {
     57 	MixParamsClass *mixparams_class = MIX_PARAMS_CLASS(klass);
     58 
     59 	/* setup static parent class */
     60 	parent_class = (MixParamsClass *) g_type_class_peek_parent(klass);
     61 
     62 	mixparams_class->finalize = mix_bufferpool_finalize;
     63 	mixparams_class->copy = (MixParamsCopyFunction) mix_bufferpool_copy;
     64 	mixparams_class->dup = (MixParamsDupFunction) mix_bufferpool_dup;
     65 	mixparams_class->equal = (MixParamsEqualFunction) mix_bufferpool_equal;
     66 }
     67 
     68 MixBufferPool *
     69 mix_bufferpool_new(void) {
     70 	MixBufferPool *ret = (MixBufferPool *) g_type_create_instance(
     71 			MIX_TYPE_BUFFERPOOL);
     72 	return ret;
     73 }
     74 
     75 void mix_bufferpool_finalize(MixParams * obj) {
     76 	/* clean up here. */
     77 
     78 	MixBufferPool *self = MIX_BUFFERPOOL(obj);
     79 
     80 	if (self->objectlock) {
     81 		g_mutex_free(self->objectlock);
     82 		self->objectlock = NULL;
     83 	}
     84 
     85 	/* Chain up parent */
     86 	if (parent_class->finalize) {
     87 		parent_class->finalize(obj);
     88 	}
     89 }
     90 
     91 MixBufferPool *
     92 mix_bufferpool_ref(MixBufferPool * mix) {
     93 	return (MixBufferPool *) mix_params_ref(MIX_PARAMS(mix));
     94 }
     95 
     96 /**
     97  * mix_bufferpool_dup:
     98  * @obj: a #MixBufferPool object
     99  * @returns: a newly allocated duplicate of the object.
    100  *
    101  * Copy duplicate of the object.
    102  */
    103 MixParams *
    104 mix_bufferpool_dup(const MixParams * obj) {
    105 	MixParams *ret = NULL;
    106 
    107 	if (MIX_IS_BUFFERPOOL(obj)) {
    108 
    109 		MIX_LOCK(MIX_BUFFERPOOL(obj)->objectlock);
    110 
    111 		MixBufferPool *duplicate = mix_bufferpool_new();
    112 		if (mix_bufferpool_copy(MIX_PARAMS(duplicate), MIX_PARAMS(obj))) {
    113 			ret = MIX_PARAMS(duplicate);
    114 		} else {
    115 			mix_bufferpool_unref(duplicate);
    116 		}
    117 
    118 		MIX_UNLOCK(MIX_BUFFERPOOL(obj)->objectlock);
    119 
    120 	}
    121 	return ret;
    122 }
    123 
    124 /**
    125  * mix_bufferpool_copy:
    126  * @target: copy to target
    127  * @src: copy from src
    128  * @returns: boolean indicates if copy is successful.
    129  *
    130  * Copy instance data from @src to @target.
    131  */
    132 gboolean mix_bufferpool_copy(MixParams * target, const MixParams * src) {
    133 	MixBufferPool *this_target, *this_src;
    134 
    135 	if (MIX_IS_BUFFERPOOL(target) && MIX_IS_BUFFERPOOL(src)) {
    136 
    137 		MIX_LOCK(MIX_BUFFERPOOL(src)->objectlock);
    138 		MIX_LOCK(MIX_BUFFERPOOL(target)->objectlock);
    139 
    140 		// Cast the base object to this child object
    141 		this_target = MIX_BUFFERPOOL(target);
    142 		this_src = MIX_BUFFERPOOL(src);
    143 
    144 		// Free the existing properties
    145 
    146 		// Duplicate string
    147 		this_target->free_list = this_src->free_list;
    148 		this_target->in_use_list = this_src->in_use_list;
    149 		this_target->free_list_max_size = this_src->free_list_max_size;
    150 		this_target->high_water_mark = this_src->high_water_mark;
    151 
    152 		MIX_UNLOCK(MIX_BUFFERPOOL(src)->objectlock);
    153 		MIX_UNLOCK(MIX_BUFFERPOOL(target)->objectlock);
    154 
    155 		// Now chainup base class
    156 		if (parent_class->copy) {
    157 			return parent_class->copy(MIX_PARAMS_CAST(target), MIX_PARAMS_CAST(
    158 					src));
    159 		} else {
    160 			return TRUE;
    161 		}
    162 	}
    163 	return FALSE;
    164 }
    165 
    166 /**
    167  * mix_bufferpool_equal:
    168  * @first: first object to compare
    169  * @second: seond object to compare
    170  * @returns: boolean indicates if instance are equal.
    171  *
    172  * Copy instance data from @src to @target.
    173  */
    174 gboolean mix_bufferpool_equal(MixParams * first, MixParams * second) {
    175 	gboolean ret = FALSE;
    176 	MixBufferPool *this_first, *this_second;
    177 
    178 	if (MIX_IS_BUFFERPOOL(first) && MIX_IS_BUFFERPOOL(second)) {
    179 		// Deep compare
    180 		// Cast the base object to this child object
    181 
    182 		MIX_LOCK(MIX_BUFFERPOOL(first)->objectlock);
    183 		MIX_LOCK(MIX_BUFFERPOOL(second)->objectlock);
    184 
    185 		this_first = MIX_BUFFERPOOL(first);
    186 		this_second = MIX_BUFFERPOOL(second);
    187 
    188 		/* TODO: add comparison for other properties */
    189 		if (this_first->free_list == this_second->free_list
    190 				&& this_first->in_use_list == this_second->in_use_list
    191 				&& this_first->free_list_max_size
    192 						== this_second->free_list_max_size
    193 				&& this_first->high_water_mark == this_second->high_water_mark) {
    194 			// members within this scope equal. chaining up.
    195 			MixParamsClass *klass = MIX_PARAMS_CLASS(parent_class);
    196 			if (klass->equal)
    197 				ret = klass->equal(first, second);
    198 			else
    199 				ret = TRUE;
    200 		}
    201 
    202 		MIX_LOCK(MIX_BUFFERPOOL(first)->objectlock);
    203 		MIX_LOCK(MIX_BUFFERPOOL(second)->objectlock);
    204 
    205 	}
    206 
    207 	return ret;
    208 }
    209 
    210 /*  Class Methods  */
    211 
    212 /**
    213  * mix_bufferpool_initialize:
    214  * @returns: MIX_RESULT_SUCCESS if successful in creating the buffer pool
    215  *
    216  * Use this method to create a new buffer pool, consisting of a GSList of
    217  * buffer objects that represents a pool of buffers.
    218  */
    219 MIX_RESULT mix_bufferpool_initialize(MixBufferPool * obj, guint num_buffers) {
    220 
    221 	LOG_V( "Begin\n");
    222 
    223 	if (obj == NULL)
    224 	return MIX_RESULT_NULL_PTR;
    225 
    226 	MIX_LOCK(obj->objectlock);
    227 
    228 	if ((obj->free_list != NULL) || (obj->in_use_list != NULL)) {
    229 		//buffer pool is in use; return error; need proper cleanup
    230 		//TODO need cleanup here?
    231 
    232 		MIX_UNLOCK(obj->objectlock);
    233 
    234 		return MIX_RESULT_ALREADY_INIT;
    235 	}
    236 
    237 	if (num_buffers == 0) {
    238 		obj->free_list = NULL;
    239 
    240 		obj->in_use_list = NULL;
    241 
    242 		obj->free_list_max_size = num_buffers;
    243 
    244 		obj->high_water_mark = 0;
    245 
    246 		MIX_UNLOCK(obj->objectlock);
    247 
    248 		return MIX_RESULT_SUCCESS;
    249 	}
    250 
    251 	// Initialize the free pool with MixBuffer objects
    252 
    253 	gint i = 0;
    254 	MixBuffer *buffer = NULL;
    255 
    256 	for (; i < num_buffers; i++) {
    257 
    258 		buffer = mix_buffer_new();
    259 
    260 		if (buffer == NULL) {
    261 			//TODO need to log an error here and do cleanup
    262 
    263 			MIX_UNLOCK(obj->objectlock);
    264 
    265 			return MIX_RESULT_NO_MEMORY;
    266 		}
    267 
    268 		// Set the pool reference in the private data of the MixBuffer object
    269 		mix_buffer_set_pool(buffer, obj);
    270 
    271 		//Add each MixBuffer object to the pool list
    272 		obj->free_list = g_slist_append(obj->free_list, buffer);
    273 
    274 	}
    275 
    276 	obj->in_use_list = NULL;
    277 
    278 	obj->free_list_max_size = num_buffers;
    279 
    280 	obj->high_water_mark = 0;
    281 
    282 	MIX_UNLOCK(obj->objectlock);
    283 
    284 	LOG_V( "End\n");
    285 
    286 return MIX_RESULT_SUCCESS;
    287 }
    288 
    289 /**
    290  * mix_bufferpool_put:
    291  * @returns: SUCCESS or FAILURE
    292  *
    293  * Use this method to return a buffer to the free pool
    294  */
    295 MIX_RESULT mix_bufferpool_put(MixBufferPool * obj, MixBuffer * buffer) {
    296 
    297 	if (obj == NULL || buffer == NULL)
    298 		return MIX_RESULT_NULL_PTR;
    299 
    300 	MIX_LOCK(obj->objectlock);
    301 
    302 	if (obj->in_use_list == NULL) {
    303 		//in use list cannot be empty if a buffer is in use
    304 		//TODO need better error code for this
    305 
    306 		MIX_UNLOCK(obj->objectlock);
    307 
    308 		return MIX_RESULT_FAIL;
    309 	}
    310 
    311 	GSList *element = g_slist_find(obj->in_use_list, buffer);
    312 	if (element == NULL) {
    313 		//Integrity error; buffer not found in in use list
    314 		//TODO need better error code and handling for this
    315 
    316 		MIX_UNLOCK(obj->objectlock);
    317 
    318 		return MIX_RESULT_FAIL;
    319 	} else {
    320 		//Remove this element from the in_use_list
    321 		obj->in_use_list = g_slist_remove_link(obj->in_use_list, element);
    322 
    323 		//Concat the element to the free_list
    324 		obj->free_list = g_slist_concat(obj->free_list, element);
    325 	}
    326 
    327 	//Note that we do nothing with the ref count for this.  We want it to
    328 	//stay at 1, which is what triggered it to be added back to the free list.
    329 
    330 	MIX_UNLOCK(obj->objectlock);
    331 
    332 	return MIX_RESULT_SUCCESS;
    333 }
    334 
    335 /**
    336  * mix_bufferpool_get:
    337  * @returns: SUCCESS or FAILURE
    338  *
    339  * Use this method to get a buffer from the free pool
    340  */
    341 MIX_RESULT mix_bufferpool_get(MixBufferPool * obj, MixBuffer ** buffer) {
    342 
    343 	if (obj == NULL || buffer == NULL)
    344 		return MIX_RESULT_NULL_PTR;
    345 
    346 	MIX_LOCK(obj->objectlock);
    347 
    348 	if (obj->free_list == NULL) {
    349 		//We are out of buffers
    350 		//TODO need to log this as well
    351 
    352 		MIX_UNLOCK(obj->objectlock);
    353 
    354 		return MIX_RESULT_POOLEMPTY;
    355 	}
    356 
    357 	//Remove a buffer from the free pool
    358 
    359 	//We just remove the one at the head, since it's convenient
    360 	GSList *element = obj->free_list;
    361 	obj->free_list = g_slist_remove_link(obj->free_list, element);
    362 	if (element == NULL) {
    363 		//Unexpected behavior
    364 		//TODO need better error code and handling for this
    365 
    366 		MIX_UNLOCK(obj->objectlock);
    367 
    368 		return MIX_RESULT_FAIL;
    369 	} else {
    370 		//Concat the element to the in_use_list
    371 		obj->in_use_list = g_slist_concat(obj->in_use_list, element);
    372 
    373 		//TODO replace with proper logging
    374 
    375 		LOG_I( "buffer refcount%d\n",
    376 				MIX_PARAMS(element->data)->refcount);
    377 
    378 		//Set the out buffer pointer
    379 		*buffer = (MixBuffer *) element->data;
    380 
    381 		//Check the high water mark for buffer use
    382 		guint size = g_slist_length(obj->in_use_list);
    383 		if (size > obj->high_water_mark)
    384 			obj->high_water_mark = size;
    385 		//TODO Log this high water mark
    386 	}
    387 
    388 	//Increment the reference count for the buffer
    389 	mix_buffer_ref(*buffer);
    390 
    391 	MIX_UNLOCK(obj->objectlock);
    392 
    393 	return MIX_RESULT_SUCCESS;
    394 }
    395 
    396 /**
    397  * mix_bufferpool_deinitialize:
    398  * @returns: SUCCESS or FAILURE
    399  *
    400  * Use this method to teardown a buffer pool
    401  */
    402 MIX_RESULT mix_bufferpool_deinitialize(MixBufferPool * obj) {
    403 	if (obj == NULL)
    404 		return MIX_RESULT_NULL_PTR;
    405 
    406 	MIX_LOCK(obj->objectlock);
    407 
    408 	if ((obj->in_use_list != NULL) || (g_slist_length(obj->free_list)
    409 			!= obj->free_list_max_size)) {
    410 		//TODO better error code
    411 		//We have outstanding buffer objects in use and they need to be
    412 		//freed before we can deinitialize.
    413 
    414 		MIX_UNLOCK(obj->objectlock);
    415 
    416 		return MIX_RESULT_FAIL;
    417 	}
    418 
    419 	//Now remove buffer objects from the list
    420 
    421 	MixBuffer *buffer = NULL;
    422 
    423 	while (obj->free_list != NULL) {
    424 		//Get the buffer object from the head of the list
    425 		buffer = obj->free_list->data;
    426 		//buffer = g_slist_nth_data(obj->free_list, 0);
    427 
    428 		//Release it
    429 		mix_buffer_unref(buffer);
    430 
    431 		//Delete the head node of the list and store the new head
    432 		obj->free_list = g_slist_delete_link(obj->free_list, obj->free_list);
    433 
    434 		//Repeat until empty
    435 	}
    436 
    437 	obj->free_list_max_size = 0;
    438 
    439 	//May want to log this information for tuning
    440 	obj->high_water_mark = 0;
    441 
    442 	MIX_UNLOCK(obj->objectlock);
    443 
    444 	return MIX_RESULT_SUCCESS;
    445 }
    446 
    447 #define MIX_BUFFERPOOL_SETTER_CHECK_INPUT(obj) \
    448 	if(!obj) return MIX_RESULT_NULL_PTR; \
    449 	if(!MIX_IS_BUFFERPOOL(obj)) return MIX_RESULT_FAIL; \
    450 
    451 #define MIX_BUFFERPOOL_GETTER_CHECK_INPUT(obj, prop) \
    452 	if(!obj || !prop) return MIX_RESULT_NULL_PTR; \
    453 	if(!MIX_IS_BUFFERPOOL(obj)) return MIX_RESULT_FAIL; \
    454 
    455 
    456 MIX_RESULT
    457 mix_bufferpool_dumpbuffer(MixBuffer *buffer)
    458 {
    459 	LOG_I( "\tBuffer %x, ptr %x, refcount %d\n", (guint)buffer,
    460 			(guint)buffer->data, MIX_PARAMS(buffer)->refcount);
    461 	return MIX_RESULT_SUCCESS;
    462 }
    463 
    464 MIX_RESULT
    465 mix_bufferpool_dumpprint (MixBufferPool * obj)
    466 {
    467 	//TODO replace this with proper logging later
    468 
    469 	LOG_I( "BUFFER POOL DUMP:\n");
    470 	LOG_I( "Free list size is %d\n", g_slist_length(obj->free_list));
    471 	LOG_I( "In use list size is %d\n", g_slist_length(obj->in_use_list));
    472 	LOG_I( "High water mark is %lu\n", obj->high_water_mark);
    473 
    474 	//Walk the free list and report the contents
    475 	LOG_I( "Free list contents:\n");
    476 	g_slist_foreach(obj->free_list, (GFunc) mix_bufferpool_dumpbuffer, NULL);
    477 
    478 	//Walk the in_use list and report the contents
    479 	LOG_I( "In Use list contents:\n");
    480 	g_slist_foreach(obj->in_use_list, (GFunc) mix_bufferpool_dumpbuffer, NULL);
    481 
    482 	return MIX_RESULT_SUCCESS;
    483 }
    484 
    485