1 /*
2 * Portions of this file Copyright 1999-2005 University of Chicago
3 * Portions of this file Copyright 1999-2005 The University of Southern California.
4 *
5 * This file or a portion of this file is licensed under the
6 * terms of the Globus Toolkit Public License, found at
7 * http://www.globus.org/toolkit/download/license.html.
8 * If you redistribute this file, with or without
9 * modifications, you must include this notice in the file.
10 */
11
12 #include "globus_soap_message.h"
13 #include "globus_i_wsrf_resource.h"
14
15 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
16 /**
17 * @file globus_wsrf_resource.c
18 *
19 * Module implementation and resource creation/destruction functions.
20 */
21 static
22 int
23 globus_l_wsrf_resource_activate(void);
24
25 static
26 int
27 globus_l_wsrf_resource_deactivate(void);
28
29 static
30 void
31 globus_l_wsrf_resource_hashtable_destroy(
32 void * datum);
33
34 static
35 void
36 globus_l_resource_destroy(
37 globus_resource_t resource);
38
39 static
40 void
41 globus_l_resource_property_destroy(
42 void * datum);
43
44 static
45 void
46 globus_l_resource_lifetime_expired(
47 void * arg);
48
49 /**
50 * Table mapping resource id strings to resource instances.
51 */
52 static globus_hashtable_t globus_l_wsrf_resources;
53 /**
54 * Lock for resource table.
55 */
56 static globus_mutex_t globus_l_wsrf_resource_lock;
57
58 globus_module_descriptor_t
59 globus_i_wsrf_resource_module =
60 {
61 "globus_wsrf_resource",
62 globus_l_wsrf_resource_activate,
63 globus_l_wsrf_resource_deactivate
64 };
65
66 /**
67 * Activate the WSRF Resource module.
68 *
69 * Activate modules this one uses, create the resource ID : resource hashtable
70 * and lock.
71 *
72 * @retval GLOBUS_SUCCESS
73 * Module successfully activated.
74 * @retval 1
75 * Unable to activate module.
76 */
77 static
78 int
79 globus_l_wsrf_resource_activate(void)
80 101 {
81 int rc;
82
83 101 rc = globus_module_activate(GLOBUS_COMMON_MODULE);
84 101 if (rc != GLOBUS_SUCCESS)
85 {
86 101 goto error;
87 }
88 101 rc = globus_module_activate(GLOBUS_SOAP_MESSAGE_MODULE);
89
90 101 if (rc != GLOBUS_SUCCESS)
91 {
92 101 goto deactivate_common_error;
93 }
94
95 101 rc = globus_hashtable_init(&globus_l_wsrf_resources,
96 16,
97 globus_hashtable_string_hash,
98 globus_hashtable_string_keyeq);
99
100 101 if (rc != GLOBUS_SUCCESS)
101 {
102 101 goto deactivate_message_error;
103 }
104
105 101 rc = globus_mutex_init(&globus_l_wsrf_resource_lock, NULL);
106 101 if (rc != GLOBUS_SUCCESS)
107 {
108 101 goto destroy_hashtable_error;
109 }
110
111 101 return GLOBUS_SUCCESS;
112
113 0 destroy_hashtable_error:
114 0 globus_hashtable_destroy(&globus_l_wsrf_resources);
115 0 deactivate_message_error:
116 0 globus_module_deactivate(GLOBUS_SOAP_MESSAGE_MODULE);
117 0 deactivate_common_error:
118 0 globus_module_deactivate(GLOBUS_COMMON_MODULE);
119 0 error:
120 0 return 1;
121 }
122 /* globus_l_wsrf_resource_activate() */
123
124 static
125 int
126 globus_l_wsrf_resource_deactivate(void)
127 73 {
128 73 globus_mutex_lock(&globus_l_wsrf_resource_lock);
129
130 73 globus_hashtable_destroy_all(
131 &globus_l_wsrf_resources,
132 globus_l_wsrf_resource_hashtable_destroy);
133
134 73 globus_mutex_unlock(&globus_l_wsrf_resource_lock);
135 73 globus_mutex_destroy(&globus_l_wsrf_resource_lock);
136 73 globus_module_deactivate(GLOBUS_SOAP_MESSAGE_MODULE);
137 73 globus_module_deactivate(GLOBUS_COMMON_MODULE);
138
139 73 return 0;
140 }
141 /* globus_l_wsrf_resource_deactivate() */
142 #endif /* GLOBUS_DONT_DOCUMENT_INTERNAL */
143
144 /**
145 * Create a new WSRF Resource.
146 * @ingroup resource
147 *
148 * Allocate a new reference-counted WSRF resource. Calls to
149 * globus_resource_find() and globus_resource_finish() manipulate the resource
150 * count. Every call to globus_resource_find() must be paired with a call to
151 * globus_resource_finish(). The service which
152 * calls globus_resource_create() must call globus_resource_destroy() or
153 * globus_resource_set_destroy_time() to destroy the resource.
154 *
155 * @param id
156 * Identifier to use for the new resource.
157 * @param resource
158 * Pointer to be set to the newly created resource handle.
159 *
160 * @retval GLOBUS_SUCCESS
161 * New resource created successfully.
162 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
163 * One of the parameters to this function was NULL.
164 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_DUPLICATE_RESOURCE
165 * Another resource with the specified id already exists, so a new one
166 * could not be created.
167 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_OUT_OF_MEMORY
168 * Insufficient memory to create the new resource.
169 *
170 * @see globus_resource_find(), globus_resource_finish()
171 */
172 globus_result_t
173 globus_resource_create(
174 const char * id,
175 globus_resource_t * resource)
176 348 {
177 globus_resource_t iresource;
178 348 globus_result_t result = GLOBUS_SUCCESS;
179 int rc;
180 GlobusFuncName(globus_resource_create);
181
182 348 if (id == NULL || resource == NULL)
183 {
184 3 result = GLOBUS_RESOURCE_ERROR_NULL_PARAM();
185 3 goto error;
186 }
187
188 345 globus_mutex_lock(&globus_l_wsrf_resource_lock);
189
190 345 iresource = globus_hashtable_lookup(&globus_l_wsrf_resources, (void *) id);
191
192 345 if (iresource != NULL)
193 {
194 1 result = GLOBUS_RESOURCE_ERROR_DUPLICATE_RESOURCE(id);
195
196 1 goto unlock_error;
197 }
198
199 344 iresource = globus_calloc(1, sizeof(struct globus_resource_s));
200 344 if (iresource == NULL)
201 {
202 0 result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
203
204 0 goto unlock_error;
205 }
206
207 344 iresource->id = globus_libc_strdup(id);
208 344 if (iresource->id == NULL)
209 {
210 0 result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
211
212 0 goto free_resource_error;
213 }
214
215 344 rc = globus_hashtable_init(&iresource->resource_properties,
216 31,
217 xsd_QName_hash,
218 xsd_QName_keyeq);
219
220 344 if (rc != GLOBUS_SUCCESS)
221 {
222 0 result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
223
224 0 goto free_id_out;
225 }
226
227 344 globus_cond_init(&iresource->cond, NULL);
228 344 iresource->lifetime_callback = GLOBUS_NULL_HANDLE;
229 344 iresource->destroy_blocking = GLOBUS_FALSE;
230
231 344 rc = globus_hashtable_insert(
232 &globus_l_wsrf_resources,
233 iresource->id,
234 iresource);
235
236 344 if (rc != GLOBUS_SUCCESS)
237 {
238 0 result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
239
240 0 goto destroy_resource_error;
241 }
242
243 344 *resource = iresource;
244
245 344 globus_mutex_unlock(&globus_l_wsrf_resource_lock);
246 344 return result;
247
248 0 destroy_resource_error:
249 0 globus_hashtable_destroy(&iresource->resource_properties);
250 0 globus_cond_destroy(&iresource->cond);
251 0 free_id_out:
252 0 globus_libc_free(iresource->id);
253 0 free_resource_error:
254 0 globus_libc_free(iresource);
255 1 unlock_error:
256 1 globus_mutex_unlock(&globus_l_wsrf_resource_lock);
257 4 error:
258 4 return result;
259 }
260 /* globus_resource_create() */
261
262 /**
263 * Find the resource associated with a resource identifier.
264 * @ingroup resource
265 *
266 * Returns a reference to the resource associated with the id.
267 * Destroy this reference by calling #globus_resource_finish().
268 *
269 * @param id
270 * Resource identifier for the desired resource.
271 * @param resource
272 * Pointer to a resource which will modified to point to the
273 * named resource if it is found.
274 *
275 * @retval GLOBUS_SUCCESS
276 * The resource associated with the specified id was found and a reference
277 * to it was returned in the @a resource parameter.
278 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
279 * One of the parameters to this function was NULL.
280 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_RESOURCE
281 * No resource with the specified id exists.
282 * @see #globus_resource_create()
283 */
284 globus_result_t
285 globus_resource_find(
286 const char * id,
287 globus_resource_t * resource)
288 2115 {
289 globus_resource_t iresource;
290 globus_result_t result;
291 GlobusFuncName(globus_resource_find);
292
293 2115 if (id == NULL || resource == NULL)
294 {
295 0 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
296 }
297
298 2115 globus_mutex_lock(&globus_l_wsrf_resource_lock);
299
300 2115 iresource = globus_hashtable_lookup(&globus_l_wsrf_resources, (void *) id);
301
302 2115 if (iresource == NULL || iresource->destroy_blocking)
303 {
304 3 result = GLOBUS_RESOURCE_ERROR_UNKNOWN_RESOURCE(id);
305
306 3 goto unlock_error;
307 }
308 2112 iresource->references++;
309
310 2112 *resource = iresource;
311 2112 globus_mutex_unlock(&globus_l_wsrf_resource_lock);
312
313 2112 return GLOBUS_SUCCESS;
314 3 unlock_error:
315 3 globus_mutex_unlock(&globus_l_wsrf_resource_lock);
316
317 3 return result;
318 }
319 /* globus_resource_find() */
320
321 /**
322 * Release a reference to a resource.
323 * @ingroup resource
324 *
325 * The caller must no longer access the resource reference once this function
326 * returns. This function destroys the resource when all references to the
327 * resource have been finished and globus_resource_destroy() or the time
328 * passed to globus_resource_set_destroy_time() has elapsed.
329 *
330 * @param resource
331 * Resource handle which is no longer being used.
332 *
333 * @retval GLOBUS_SUCCESS
334 * Successfully finished using the resource handle.
335 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
336 * Null resource handle passed to this function.
337 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NO_REFERENCES
338 * No references to resource exist.
339 *
340 * @see #globus_resource_find(), #globus_resource_create()
341 */
342 globus_result_t
343 globus_resource_finish(
344 globus_resource_t resource)
345 2074 {
346 2074 globus_result_t result = GLOBUS_SUCCESS;
347 GlobusFuncName(globus_resource_finish);
348
349 2074 if (resource == NULL)
350 {
351 1 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
352 }
353
354 2073 globus_mutex_lock(&globus_l_wsrf_resource_lock);
355
356 2073 if (resource->references <= 0)
357 {
358 1 result = GLOBUS_RESOURCE_ERROR_NO_REFERENCES(resource->id);
359
360 1 goto out;
361 }
362 2072 resource->references--;
363
364 2072 globus_assert(resource->references >= 0);
365
366 2072 if (resource->references == 0)
367 {
368 2072 if (resource->destroy_blocking)
369 {
370 0 globus_cond_signal(&resource->cond);
371 }
372 }
373 2073 out:
374 2073 globus_mutex_unlock(&globus_l_wsrf_resource_lock);
375
376 2073 return result;
377 }
378 /* globus_resource_finish() */
379
380 /**
381 * Destroy the resource after the final reference has been finished.
382 * @ingroup resource
383 *
384 * This function blocks until all references to the resource have been
385 * finished and then destroys the contents of the resource. This destruction
386 * will take precedence over a not yet elapsed delayed destruction time set by
387 * #globus_resource_set_destroy_time(). It is an
388 * error to access the resource once this function returns. All subsequent
389 * attempts to find this resource will fail.
390 *
391 *
392 * @param resource
393 * Resource handle which is no longer being used.
394 *
395 * @retval GLOBUS_SUCCESS
396 * Successfully destroyed the resource handle.
397 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
398 * Null resource handle passed to this function.
399 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_ALREADY_DESTROYED
400 * The resource has already been destroyed.
401 *
402 * @see globus_resource_create(), globus_resource_finish_and_destroy(),
403 * #globus_resource_set_destroy_time()
404 */
405 globus_result_t
406 globus_resource_destroy(
407 globus_resource_t resource)
408 37 {
409 globus_result_t result;
410 globus_bool_t active;
411 GlobusFuncName(globus_resource_destroy);
412
413 37 if (resource == NULL)
414 {
415 1 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
416 }
417
418 36 globus_mutex_lock(&globus_l_wsrf_resource_lock);
419 36 if (resource->destroy_blocking)
420 {
421 0 result = GLOBUS_RESOURCE_ERROR_ALREADY_DESTROYED();
422
423 0 goto out;
424 }
425
426 36 if (resource->lifetime_callback != GLOBUS_NULL_HANDLE)
427 {
428 /* Try to cancel the lifetime callback */
429 1 result = globus_callback_unregister(
430 resource->lifetime_callback,
431 NULL,
432 NULL,
433 &active);
434
435 1 if (result != GLOBUS_SUCCESS || active)
436 {
437 /* Callback can't be stopped---we'll rely on it to destroy the
438 * service
439 */
440 goto out;
441 }
442 1 resource->lifetime_callback = GLOBUS_NULL_HANDLE;
443 }
444
445 36 resource->destroy_blocking = GLOBUS_TRUE;
446
447 72 while (resource->references > 0)
448 {
449 0 globus_cond_wait(&resource->cond, &globus_l_wsrf_resource_lock);
450 }
451 36 (void) globus_hashtable_remove(&globus_l_wsrf_resources,
452 resource->id);
453
454 36 globus_l_resource_destroy(resource);
455
456 36 out:
457 36 globus_mutex_unlock(&globus_l_wsrf_resource_lock);
458 36 return GLOBUS_SUCCESS;
459 }
460 /* globus_resource_destroy() */
461
462 /**
463 * Schedule delayed destruction of a resource.
464 * @ingroup resource
465 *
466 * When the time indicated by the @a timestamp parameter has been reached, the
467 * resource will be destroyed once all remaining references to the resource
468 * have been finished.
469 *
470 * If globus_resource_destroy() is called before this time has been reached,
471 * the timestamp is effectively ignored.
472 *
473 * @param resource
474 * Resource handle which is no longer being used.
475 * @param timestamp
476 * Time when the resource should be destroyed.
477 *
478 * @retval GLOBUS_SUCCESS
479 * Successfully set the destroy timeout for the resource handle.
480 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
481 * Null resource handle passed to this function.
482 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_ALREADY_DESTROYED
483 * The resource has already been destroyed.
484 *
485 * @see #globus_resource_create(), #globus_resource_destroy(),
486 * #globus_resource_finish_and_destroy()
487 */
488 globus_result_t
489 globus_resource_set_destroy_time(
490 globus_resource_t resource,
491 const globus_abstime_t * timestamp)
492 20 {
493 globus_result_t result;
494 globus_bool_t active;
495 globus_abstime_t now;
496 globus_reltime_t delay;
497 GlobusFuncName(globus_resource_set_destroy_time);
498
499 20 if (resource == NULL || timestamp == NULL)
500 {
501 2 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
502 }
503
504 18 globus_mutex_lock(&globus_l_wsrf_resource_lock);
505
506 18 if (resource->destroy_blocking)
507 {
508 0 result = GLOBUS_RESOURCE_ERROR_ALREADY_DESTROYED();
509
510 0 goto out;
511 }
512
513 18 if (resource->lifetime_callback != GLOBUS_NULL_HANDLE)
514 {
515 /* Try to cancel the previous instance of the lifetime callback */
516 0 result = globus_callback_unregister(
517 resource->lifetime_callback,
518 NULL,
519 NULL,
520 &active);
521
522 0 if (result != GLOBUS_SUCCESS || active)
523 {
524 /* Callback can't be stopped---assume this resource is already
525 * going to be destroyed very soon.
526 */
527 0 result = GLOBUS_RESOURCE_ERROR_ALREADY_DESTROYED();
528
529 0 goto out;
530 }
531 0 resource->lifetime_callback = GLOBUS_NULL_HANDLE;
532 }
533
534 18 GlobusTimeAbstimeSet(now, 0, 0);
535
536 18 if (globus_abstime_cmp(&now, timestamp) >= 0)
537 {
538 0 delay.tv_sec = 0;
539 0 delay.tv_usec = 0;
540 }
541 else
542 {
543 18 GlobusTimeAbstimeDiff(delay, *timestamp, now);
544 }
545
546 18 result = globus_callback_register_oneshot(
547 &resource->lifetime_callback,
548 &delay,
549 globus_l_resource_lifetime_expired,
550 resource);
551
552 18 out:
553 18 globus_mutex_unlock(&globus_l_wsrf_resource_lock);
554
555 18 return result;
556 }
557 /* globus_resource_set_destroy_time() */
558
559 /**
560 * Finish one reference and then destroy the resource.
561 * @ingroup resource
562 *
563 * This function acts identically to globus_resource_destroy() except it
564 * first finishes one reference to the resource. This allows applications to
565 * use code like this:
566 * @code
567 * globus_resource_find(resource_id, &resource);
568 * ...
569 * globus_resource_finish_and_destroy(resource);
570 * @endcode
571 * to avoid a race condition between calling globus_resource_finish() and
572 * globus_resource_destroy() during which the reference to the resource
573 * would be invalid.
574 *
575 * If another thread is currently blocked trying to destroy this resource, then
576 * this function acts like #globus_resource_finish().
577 *
578 * @param resource
579 * Resource handle which is no longer being used.
580 *
581 * @retval GLOBUS_SUCCESS
582 * Successfully finished using the resource handle.
583 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
584 * Null resource handle passed to this function.
585 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_ALREADY_DESTROYED
586 * The resource has already been destroyed.
587 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NO_REFERENCES
588 * No references to resource exist.
589 *
590 * @see #globus_resource_create(), #globus_resource_destroy(),
591 * #globus_resource_set_destroy_time()
592 */
593 globus_result_t
594 globus_resource_finish_and_destroy(
595 globus_resource_t resource)
596 42 {
597 42 globus_result_t result = GLOBUS_SUCCESS;
598 globus_bool_t active;
599 GlobusFuncName(globus_resource_finish_and_destroy);
600
601 42 if (resource == NULL)
602 {
603 1 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
604 }
605
606 41 globus_mutex_lock(&globus_l_wsrf_resource_lock);
607
608 41 if (resource->references <= 0)
609 {
610 1 result = GLOBUS_RESOURCE_ERROR_NO_REFERENCES(resource->id);
611
612 1 goto out;
613 }
614
615 40 resource->references--;
616
617 40 if (resource->destroy_blocking)
618 {
619 /* If another thread is calling destroy, this acts like
620 * globus_resource_finish()
621 */
622 40 goto out;
623 }
624
625 40 if (resource->lifetime_callback != GLOBUS_NULL_HANDLE)
626 {
627 /* Try to cancel the lifetime callback */
628 12 result = globus_callback_unregister(
629 resource->lifetime_callback,
630 NULL,
631 NULL,
632 &active);
633
634 12 if (result != GLOBUS_SUCCESS || active)
635 {
636 /* Callback can't be stopped---we'll rely on it to destroy the
637 * service
638 */
639 goto out;
640 }
641 12 resource->lifetime_callback = GLOBUS_NULL_HANDLE;
642 }
643
644 40 resource->destroy_blocking = GLOBUS_TRUE;
645
646 80 while (resource->references > 0)
647 {
648 0 globus_cond_wait(&resource->cond, &globus_l_wsrf_resource_lock);
649 }
650 40 (void) globus_hashtable_remove(&globus_l_wsrf_resources,
651 resource->id);
652
653 40 globus_l_resource_destroy(resource);
654
655 41 out:
656 41 globus_mutex_unlock(&globus_l_wsrf_resource_lock);
657
658 41 return result;
659 }
660 /* globus_resource_finish_and_destroy() */
661
662 /**
663 * Retrieve resource-specific data from a resource handle.
664 * @ingroup resource
665 *
666 * @param resource
667 * Resource handle to query for data.
668 * @param data
669 * Pointer to be set to the value of resource-specific data.
670 *
671 * @retval GLOBUS_SUCCESS
672 * Resource specific data successfully retrieved.
673 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
674 * Null parameter passed to this function. The value of @a data is
675 * undefined when this value is returned.
676 *
677 * @see #globus_resource_set_resource_specific()
678 */
679 globus_result_t
680 globus_resource_get_resource_specific(
681 const globus_resource_t resource,
682 void ** data)
683 15 {
684 GlobusFuncName(globus_resource_get_resource_specific);
685
686 15 if (resource == NULL || data == NULL)
687 {
688 2 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
689 }
690 13 *data = resource->data;
691
692 13 return GLOBUS_SUCCESS;
693 }
694 /* globus_resource_get_resource_specific() */
695
696 /**
697 * Set resource-specific data for a resource handle.
698 * @ingroup resource
699 *
700 * @param resource
701 * Resource handle to modify.
702 * @param data
703 * New value of the resource-specific data. If a non-NULL value was
704 * previously set as resource-specific data, it will be destroyed.
705 * @param destroy_func
706 * Function pointer of a function to call to destroy the resource-specific
707 * data. This will be called either when a new instance of
708 * resource-specific data is set by calling this function again, or when
709 * the resource is destroyed because of globus_resource_finish() being
710 * called.
711 *
712 * @retval GLOBUS_SUCCESS
713 * Resource specific data successfully set.
714 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
715 * Null parameter passed to this function.
716 *
717 * @see #globus_resource_get_resource_specific(), #globus_resource_finish()
718 */
719 globus_result_t
720 globus_resource_set_resource_specific(
721 globus_resource_t resource,
722 void * data,
723 globus_resource_destroy_t destroy_func)
724 8 {
725 GlobusFuncName(globus_resource_set_resource_specific);
726
727 8 if (resource == NULL)
728 {
729 1 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
730 }
731
732 7 if ((resource->data != NULL) && (resource->data_destroy_func != NULL))
733 {
734 1 (resource->data_destroy_func)(resource->data);
735 }
736
737 7 resource->data = data;
738 7 resource->data_destroy_func = destroy_func;
739
740 7 return GLOBUS_SUCCESS;
741 }
742 /* globus_resource_set_resource_specific() */
743
744 /**
745 * Retrieve resource-specific type registry from a resource handle.
746 * @ingroup resource
747 *
748 * @param resource
749 * Resource handle to query for data.
750 * @param registry
751 * Pointer to be set to the value of type registry.
752 *
753 * @retval GLOBUS_SUCCESS
754 * Type registry successfully retrieved.
755 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
756 * Null parameter passed to this function. The value of @a registry is
757 * undefined when this value is returned.
758 *
759 * @see #globus_resource_set_type_registry()
760 */
761 globus_result_t
762 globus_resource_get_type_registry(
763 globus_resource_t resource,
764 globus_xsd_type_registry_t * registry)
765 4 {
766 GlobusFuncName(globus_resource_get_type_registry);
767
768 4 if (resource == NULL || registry == NULL)
769 {
770 2 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
771 }
772 2 *registry = resource->registry;
773
774 2 return GLOBUS_SUCCESS;
775 }
776 /* globus_resource_get_type_registry() */
777
778 /**
779 * Set type registry associated with a resource handle.
780 * @ingroup resource
781 *
782 * @param resource
783 * Resource handle to modify.
784 * @param registry
785 * New value for the resource's type registry.
786 *
787 * @retval GLOBUS_SUCCESS
788 * Resource's type registry successfully set.
789 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
790 * Null parameter passed to this function.
791 *
792 * @see #globus_resource_get_type_registry()
793 */
794 globus_result_t
795 globus_resource_set_type_registry(
796 globus_resource_t resource,
797 globus_xsd_type_registry_t registry)
798 1 {
799 GlobusFuncName(globus_resource_set_type_registry);
800
801 1 if (resource == NULL || registry == NULL)
802 {
803 0 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
804 }
805
806 1 resource->registry = registry;
807
808 1 return GLOBUS_SUCCESS;
809 }
810 /* globus_resource_set_type_registry() */
811
812 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
813 /**
814 * Destroy a resource stored in the resource hashtable at deactivation time.
815 * Resources could have
816 * - references from finds which were not finished
817 * - other threads blocking in globus_resource_destroy()
818 * - other threads blocking in a callback from
819 * globus_resource_set_destroy_time()
820 * This function is called with the resource mutex locked.
821 */
822 static
823 void
824 globus_l_wsrf_resource_hashtable_destroy(
825 void * datum)
826 259 {
827 259 globus_resource_t resource = datum;
828 259 globus_bool_t active = GLOBUS_FALSE;
829
830 /* If a callback is registered, try to remove it; if that fails, then
831 * the callback code will try to destroy the resource, so we'll act
832 * later as if a destroy call was already blocking.
833 */
834 259 if (resource->lifetime_callback != GLOBUS_NULL_HANDLE)
835 {
836 1 globus_callback_unregister(
837 resource->lifetime_callback,
838 NULL,
839 NULL,
840 &active);
841
842 1 resource->lifetime_callback = GLOBUS_NULL_HANDLE;
843 }
844
845 259 if (active || resource->destroy_blocking)
846 {
847 /* If destroy_blocking is true or a callback is waiting for the lock,
848 * then another thread is going to try to destroy this, or is waiting
849 * for the referece count to reach 0 already. We'll help that out.
850 */
851 0 resource->references = 0;
852 0 globus_cond_signal(&resource->cond);
853
854 0 return;
855 }
856 else
857 {
858 /* Otherwise, no destroy is in progress for this resource, so we must
859 * free it ourselves.
860 */
861 259 globus_l_resource_destroy(resource);
862 }
863 }
864 /* globus_l_wsrf_resource_hashtable_destroy() */
865
866 /**
867 * Free memory associated with a resource handle.
868 * When this function is called for a resource, all callbacks and threads
869 * blocking on the condition of this resource must be finished, otherwise
870 * weird things may happen in those threads.
871 *
872 * This function is called with the mutex locked.
873 *
874 * @param datum
875 * Pointer to the resource.
876 */
877 static
878 void
879 globus_l_resource_destroy(
880 globus_resource_t resource)
881 336 {
882
883 336 if (resource->resource_properties != NULL)
884 {
885 336 globus_hashtable_destroy_all(
886 &resource->resource_properties,
887 globus_l_resource_property_destroy);
888 }
889 336 globus_libc_free(resource->id);
890
891 336 if (resource->data && resource->data_destroy_func)
892 {
893 5 resource->data_destroy_func(resource->data);
894 }
895 336 globus_cond_destroy(&resource->cond);
896
897 336 if (resource->lifetime_callback != GLOBUS_NULL_HANDLE)
898 {
899 1 globus_callback_unregister(
900 resource->lifetime_callback,
901 NULL,
902 NULL,
903 NULL);
904 }
905
906 336 globus_libc_free(resource);
907 }
908 /* globus_l_resource_destroy() */
909
910 /**
911 * Free memory associated with a resource property.
912 *
913 * Function signature uses a void * to match the globus_hashtable_destroy_all()
914 * prototype.
915 *
916 * @param datum
917 * Pointer to a globus_resource_property_t to destroy.
918 */
919 static
920 void
921 globus_l_resource_property_destroy(
922 void * datum)
923 346 {
924 346 globus_resource_property_t * prop = datum;
925
926 346 if (prop->property)
927 {
928 62 prop->type_info->destroy(prop->property);
929 }
930 346 if (prop->name.Namespace)
931 {
932 346 globus_libc_free(prop->name.Namespace);
933 }
934 346 if (prop->name.local)
935 {
936 346 globus_libc_free(prop->name.local);
937 }
938 346 globus_libc_free(prop);
939 }
940 /* globus_l_resource_property_destroy() */
941
942 static
943 void
944 globus_l_resource_lifetime_expired(
945 void * arg)
946 1 {
947 1 globus_resource_t resource = arg;
948
949 1 globus_mutex_lock(&globus_l_wsrf_resource_lock);
950
951 1 resource->destroy_blocking = GLOBUS_TRUE;
952
953 2 while (resource->references > 0)
954 {
955 0 globus_cond_wait(&resource->cond, &globus_l_wsrf_resource_lock);
956 }
957 1 (void) globus_hashtable_remove(&globus_l_wsrf_resources,
958 resource->id);
959
960 1 globus_l_resource_destroy(resource);
961 1 globus_mutex_unlock(&globus_l_wsrf_resource_lock);
962 }
963 /* globus_l_resource_lifetime_expired() */