]> git.proxmox.com Git - mirror_corosync.git/blob - lib/sam.c
Fix some "set but not used" warnings [-Wunused-but-set-variable]
[mirror_corosync.git] / lib / sam.c
1 /*
2 * Copyright (c) 2009-2010 Red Hat, Inc.
3 *
4 * All rights reserved.
5 *
6 * Author: Jan Friesse (jfriesse@redhat.com)
7 *
8 * This software licensed under BSD license, the text of which follows:
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * - Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * - Neither the name of the Red Hat, Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived from this
20 * software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 /*
36 * Provides a SAM API
37 */
38
39 #include <config.h>
40
41 #include <limits.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <sys/time.h>
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <errno.h>
49
50 #include <corosync/corotypes.h>
51 #include <corosync/coroipc_types.h>
52 #include <corosync/coroipcc.h>
53 #include <corosync/corodefs.h>
54 #include <corosync/confdb.h>
55 #include <corosync/hdb.h>
56 #include <corosync/quorum.h>
57
58 #include <corosync/sam.h>
59
60 #include "util.h"
61
62 #include <stdio.h>
63 #include <sys/wait.h>
64 #include <signal.h>
65
66 #define SAM_CONFDB_S_FAILED "failed"
67 #define SAM_CONFDB_S_REGISTERED "stopped"
68 #define SAM_CONFDB_S_STARTED "running"
69 #define SAM_CONFDB_S_Q_WAIT "waiting for quorum"
70
71 #define SAM_RP_MASK_Q(pol) (pol & (~SAM_RECOVERY_POLICY_QUORUM))
72 #define SAM_RP_MASK_C(pol) (pol & (~SAM_RECOVERY_POLICY_CONFDB))
73 #define SAM_RP_MASK(pol) (pol & (~(SAM_RECOVERY_POLICY_QUORUM | SAM_RECOVERY_POLICY_CONFDB)))
74
75 enum sam_internal_status_t {
76 SAM_INTERNAL_STATUS_NOT_INITIALIZED = 0,
77 SAM_INTERNAL_STATUS_INITIALIZED,
78 SAM_INTERNAL_STATUS_REGISTERED,
79 SAM_INTERNAL_STATUS_STARTED,
80 SAM_INTERNAL_STATUS_FINALIZED
81 };
82
83 enum sam_command_t {
84 SAM_COMMAND_START,
85 SAM_COMMAND_STOP,
86 SAM_COMMAND_HB,
87 SAM_COMMAND_DATA_STORE,
88 SAM_COMMAND_WARN_SIGNAL_SET,
89 SAM_COMMAND_MARK_FAILED,
90 };
91
92 enum sam_reply_t {
93 SAM_REPLY_OK,
94 SAM_REPLY_ERROR,
95 };
96
97 enum sam_parent_action_t {
98 SAM_PARENT_ACTION_ERROR,
99 SAM_PARENT_ACTION_RECOVERY,
100 SAM_PARENT_ACTION_QUIT,
101 SAM_PARENT_ACTION_CONTINUE
102 };
103
104 enum sam_confdb_key_t {
105 SAM_CONFDB_KEY_RECOVERY,
106 SAM_CONFDB_KEY_HC_PERIOD,
107 SAM_CONFDB_KEY_LAST_HC,
108 SAM_CONFDB_KEY_STATE,
109 };
110
111 static struct {
112 int time_interval;
113 sam_recovery_policy_t recovery_policy;
114 enum sam_internal_status_t internal_status;
115 unsigned int instance_id;
116 int child_fd_out;
117 int child_fd_in;
118 int term_send;
119 int warn_signal;
120 int am_i_child;
121
122 sam_hc_callback_t hc_callback;
123 pthread_t cb_thread;
124 int cb_rpipe_fd, cb_wpipe_fd;
125 int cb_registered;
126
127 void *user_data;
128 size_t user_data_size;
129 size_t user_data_allocated;
130
131 pthread_mutex_t lock;
132
133 quorum_handle_t quorum_handle;
134 uint32_t quorate;
135 int quorum_fd;
136
137 confdb_handle_t confdb_handle;
138 hdb_handle_t confdb_pid_handle;
139 } sam_internal_data;
140
141 extern const char *__progname;
142
143 static cs_error_t sam_confdb_update_key (enum sam_confdb_key_t key, const char *value)
144 {
145 cs_error_t err;
146 const char *svalue;
147 uint64_t hc_period, last_hc;
148 const char *ssvalue[] = { [SAM_RECOVERY_POLICY_QUIT] = "quit", [SAM_RECOVERY_POLICY_RESTART] = "restart" };
149
150 switch (key) {
151 case SAM_CONFDB_KEY_RECOVERY:
152 svalue = ssvalue[SAM_RP_MASK (sam_internal_data.recovery_policy)];
153
154 if ((err = confdb_key_create_typed (sam_internal_data.confdb_handle, sam_internal_data.confdb_pid_handle,
155 "recovery", svalue, strlen ((const char *)svalue), CONFDB_VALUETYPE_STRING)) != CS_OK) {
156 goto exit_error;
157 }
158 break;
159 case SAM_CONFDB_KEY_HC_PERIOD:
160 hc_period = sam_internal_data.time_interval;
161
162 if ((err = confdb_key_create_typed (sam_internal_data.confdb_handle, sam_internal_data.confdb_pid_handle,
163 "poll_period", &hc_period, sizeof (hc_period), CONFDB_VALUETYPE_UINT64)) != CS_OK) {
164 goto exit_error;
165 }
166 break;
167 case SAM_CONFDB_KEY_LAST_HC:
168 last_hc = cs_timestamp_get();
169
170 if ((err = confdb_key_create_typed (sam_internal_data.confdb_handle, sam_internal_data.confdb_pid_handle,
171 "last_updated", &last_hc, sizeof (last_hc), CONFDB_VALUETYPE_UINT64)) != CS_OK) {
172 goto exit_error;
173 }
174 break;
175 case SAM_CONFDB_KEY_STATE:
176 svalue = value;
177 if ((err = confdb_key_create_typed (sam_internal_data.confdb_handle, sam_internal_data.confdb_pid_handle,
178 "state", svalue, strlen ((const char *)svalue), CONFDB_VALUETYPE_STRING)) != CS_OK) {
179 goto exit_error;
180 }
181 break;
182 }
183
184 return (CS_OK);
185
186 exit_error:
187 return (err);
188 }
189
190 static cs_error_t sam_confdb_destroy_pid_obj (void)
191 {
192 return (confdb_object_destroy (sam_internal_data.confdb_handle, sam_internal_data.confdb_pid_handle));
193 }
194
195 static cs_error_t sam_confdb_register (void)
196 {
197 const char *obj_name;
198 cs_error_t err;
199 confdb_handle_t confdb_handle;
200 hdb_handle_t resource_handle, process_handle, pid_handle, obj_handle;
201 hdb_handle_t *res_handle;
202 char tmp_obj[PATH_MAX];
203 int i;
204
205 if ((err = confdb_initialize (&confdb_handle, NULL)) != CS_OK) {
206 return (err);
207 }
208
209 for (i = 0; i < 3; i++) {
210 switch (i) {
211 case 0:
212 obj_name = "resources";
213 obj_handle = OBJECT_PARENT_HANDLE;
214 res_handle = &resource_handle;
215 break;
216 case 1:
217 obj_name = "process";
218 obj_handle = resource_handle;
219 res_handle = &process_handle;
220 break;
221 case 2:
222 if (snprintf (tmp_obj, sizeof (tmp_obj), "%s:%d", __progname, getpid ()) >= sizeof (tmp_obj)) {
223 snprintf (tmp_obj, sizeof (tmp_obj), "%d", getpid ());
224 }
225
226 obj_name = tmp_obj;
227 obj_handle = process_handle;
228 res_handle = &pid_handle;
229 break;
230 }
231
232 if ((err = confdb_object_find_start (confdb_handle, obj_handle)) != CS_OK) {
233 goto finalize_error;
234 }
235
236 if ((err = confdb_object_find (confdb_handle, obj_handle, obj_name, strlen (obj_name),
237 res_handle)) != CS_OK) {
238 if (err == CONFDB_ERR_ACCESS) {
239 /*
240 * Try to create object
241 */
242 if ((err = confdb_object_create (confdb_handle, obj_handle, obj_name,
243 strlen (obj_name), res_handle)) != CS_OK) {
244 goto finalize_error;
245 }
246 } else {
247 goto finalize_error;
248 }
249 } else {
250 if ((err = confdb_object_find_destroy (confdb_handle, obj_handle)) != CS_OK) {
251 goto finalize_error;
252 }
253 }
254 }
255
256 sam_internal_data.confdb_pid_handle = pid_handle;
257 sam_internal_data.confdb_handle = confdb_handle;
258
259 if ((err = sam_confdb_update_key (SAM_CONFDB_KEY_RECOVERY, NULL)) != CS_OK) {
260 goto destroy_finalize_error;
261 }
262
263 if ((err = sam_confdb_update_key (SAM_CONFDB_KEY_HC_PERIOD, NULL)) != CS_OK) {
264 goto destroy_finalize_error;
265 }
266
267 return (CS_OK);
268
269 destroy_finalize_error:
270 sam_confdb_destroy_pid_obj ();
271 finalize_error:
272 confdb_finalize (confdb_handle);
273 return (err);
274 }
275
276 static void quorum_notification_fn (
277 quorum_handle_t handle,
278 uint32_t quorate,
279 uint64_t ring_id,
280 uint32_t view_list_entries,
281 uint32_t *view_list)
282 {
283 sam_internal_data.quorate = quorate;
284 }
285
286 cs_error_t sam_initialize (
287 int time_interval,
288 sam_recovery_policy_t recovery_policy)
289 {
290 quorum_callbacks_t quorum_callbacks;
291 cs_error_t err;
292
293 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_NOT_INITIALIZED) {
294 return (CS_ERR_BAD_HANDLE);
295 }
296
297 if (SAM_RP_MASK (recovery_policy) != SAM_RECOVERY_POLICY_QUIT &&
298 SAM_RP_MASK (recovery_policy) != SAM_RECOVERY_POLICY_RESTART) {
299 return (CS_ERR_INVALID_PARAM);
300 }
301
302 if (recovery_policy & SAM_RECOVERY_POLICY_QUORUM) {
303 /*
304 * Initialize quorum
305 */
306 quorum_callbacks.quorum_notify_fn = quorum_notification_fn;
307 if ((err = quorum_initialize (&sam_internal_data.quorum_handle, &quorum_callbacks)) != CS_OK) {
308 goto exit_error;
309 }
310
311 if ((err = quorum_trackstart (sam_internal_data.quorum_handle, CS_TRACK_CHANGES)) != CS_OK) {
312 goto exit_error_quorum;
313 }
314
315 if ((err = quorum_fd_get (sam_internal_data.quorum_handle, &sam_internal_data.quorum_fd)) != CS_OK) {
316 goto exit_error_quorum;
317 }
318
319 /*
320 * Dispatch initial quorate state
321 */
322 if ((err = quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ONE)) != CS_OK) {
323 goto exit_error_quorum;
324 }
325 }
326 sam_internal_data.recovery_policy = recovery_policy;
327
328 sam_internal_data.time_interval = time_interval;
329
330 sam_internal_data.internal_status = SAM_INTERNAL_STATUS_INITIALIZED;
331
332 sam_internal_data.warn_signal = SIGTERM;
333
334 sam_internal_data.am_i_child = 0;
335
336 sam_internal_data.user_data = NULL;
337 sam_internal_data.user_data_size = 0;
338 sam_internal_data.user_data_allocated = 0;
339
340 pthread_mutex_init (&sam_internal_data.lock, NULL);
341
342 return (CS_OK);
343
344 exit_error_quorum:
345 quorum_finalize (sam_internal_data.quorum_handle);
346 exit_error:
347 return (err);
348 }
349
350 /*
351 * Wrapper on top of write(2) function. It handles EAGAIN and EINTR states and sends whole buffer if possible.
352 */
353 static size_t sam_safe_write (
354 int d,
355 const void *buf,
356 size_t nbyte)
357 {
358 ssize_t bytes_write;
359 ssize_t tmp_bytes_write;
360
361 bytes_write = 0;
362
363 do {
364 tmp_bytes_write = write (d, (const char *)buf + bytes_write,
365 (nbyte - bytes_write > SSIZE_MAX) ? SSIZE_MAX : nbyte - bytes_write);
366
367 if (tmp_bytes_write == -1) {
368 if (!(errno == EAGAIN || errno == EINTR))
369 return -1;
370 } else {
371 bytes_write += tmp_bytes_write;
372 }
373 } while (bytes_write != nbyte);
374
375 return (bytes_write);
376 }
377
378 /*
379 * Wrapper on top of read(2) function. It handles EAGAIN and EINTR states and reads whole buffer if possible.
380 */
381 static size_t sam_safe_read (
382 int d,
383 void *buf,
384 size_t nbyte)
385 {
386 ssize_t bytes_read;
387 ssize_t tmp_bytes_read;
388
389 bytes_read = 0;
390
391 do {
392 tmp_bytes_read = read (d, (char *)buf + bytes_read,
393 (nbyte - bytes_read > SSIZE_MAX) ? SSIZE_MAX : nbyte - bytes_read);
394
395 if (tmp_bytes_read == -1) {
396 if (!(errno == EAGAIN || errno == EINTR))
397 return -1;
398 } else {
399 bytes_read += tmp_bytes_read;
400 }
401
402 } while (bytes_read != nbyte && tmp_bytes_read != 0);
403
404 return (bytes_read);
405 }
406
407 static cs_error_t sam_read_reply (
408 int child_fd_in)
409 {
410 char reply;
411 cs_error_t err;
412
413 if (sam_safe_read (sam_internal_data.child_fd_in, &reply, sizeof (reply)) != sizeof (reply)) {
414 return (CS_ERR_LIBRARY);
415 }
416
417 switch (reply) {
418 case SAM_REPLY_ERROR:
419 /*
420 * Read error and return that
421 */
422 if (sam_safe_read (sam_internal_data.child_fd_in, &err, sizeof (err)) != sizeof (err)) {
423 return (CS_ERR_LIBRARY);
424 }
425
426 return (err);
427 break;
428 case SAM_REPLY_OK:
429 /*
430 * Everything correct
431 */
432 break;
433 default:
434 return (CS_ERR_LIBRARY);
435 break;
436 }
437
438 return (CS_OK);
439 }
440
441 cs_error_t sam_data_getsize (size_t *size)
442 {
443 if (size == NULL) {
444 return (CS_ERR_INVALID_PARAM);
445 }
446
447 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED &&
448 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED &&
449 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
450
451 return (CS_ERR_BAD_HANDLE);
452 }
453
454 pthread_mutex_lock (&sam_internal_data.lock);
455
456 *size = sam_internal_data.user_data_size;
457
458 pthread_mutex_unlock (&sam_internal_data.lock);
459
460 return (CS_OK);
461 }
462
463 cs_error_t sam_data_restore (
464 void *data,
465 size_t size)
466 {
467 cs_error_t err;
468
469 err = CS_OK;
470
471 if (data == NULL) {
472 return (CS_ERR_INVALID_PARAM);
473 }
474
475 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED &&
476 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED &&
477 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
478
479 return (CS_ERR_BAD_HANDLE);
480 }
481
482 pthread_mutex_lock (&sam_internal_data.lock);
483
484 if (sam_internal_data.user_data_size == 0) {
485 err = CS_OK;
486
487 goto error_unlock;
488 }
489
490 if (size < sam_internal_data.user_data_size) {
491 err = CS_ERR_INVALID_PARAM;
492
493 goto error_unlock;
494 }
495
496 memcpy (data, sam_internal_data.user_data, sam_internal_data.user_data_size);
497
498 pthread_mutex_unlock (&sam_internal_data.lock);
499
500 return (CS_OK);
501
502 error_unlock:
503 pthread_mutex_unlock (&sam_internal_data.lock);
504
505 return (err);
506 }
507
508 cs_error_t sam_data_store (
509 const void *data,
510 size_t size)
511 {
512 cs_error_t err;
513 char command;
514 char *new_data;
515
516 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED &&
517 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED &&
518 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
519
520 return (CS_ERR_BAD_HANDLE);
521 }
522
523
524 if (data == NULL) {
525 size = 0;
526 }
527
528 pthread_mutex_lock (&sam_internal_data.lock);
529
530 if (sam_internal_data.am_i_child) {
531 /*
532 * We are child so we must send data to parent
533 */
534 command = SAM_COMMAND_DATA_STORE;
535 if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) {
536 err = CS_ERR_LIBRARY;
537
538 goto error_unlock;
539 }
540
541 if (sam_safe_write (sam_internal_data.child_fd_out, &size, sizeof (size)) != sizeof (size)) {
542 err = CS_ERR_LIBRARY;
543
544 goto error_unlock;
545 }
546
547 if (data != NULL && sam_safe_write (sam_internal_data.child_fd_out, data, size) != size) {
548 err = CS_ERR_LIBRARY;
549
550 goto error_unlock;
551 }
552
553 /*
554 * And wait for reply
555 */
556 if ((err = sam_read_reply (sam_internal_data.child_fd_in)) != CS_OK) {
557 goto error_unlock;
558 }
559 }
560
561 /*
562 * We are parent or we received OK reply from parent -> do required action
563 */
564 if (data == NULL) {
565 free (sam_internal_data.user_data);
566 sam_internal_data.user_data = NULL;
567 sam_internal_data.user_data_allocated = 0;
568 sam_internal_data.user_data_size = 0;
569 } else {
570 if (sam_internal_data.user_data_allocated < size) {
571 if ((new_data = realloc (sam_internal_data.user_data, size)) == NULL) {
572 err = CS_ERR_NO_MEMORY;
573
574 goto error_unlock;
575 }
576
577 sam_internal_data.user_data_allocated = size;
578 } else {
579 new_data = sam_internal_data.user_data;
580 }
581 sam_internal_data.user_data = new_data;
582 sam_internal_data.user_data_size = size;
583
584 memcpy (sam_internal_data.user_data, data, size);
585 }
586
587 pthread_mutex_unlock (&sam_internal_data.lock);
588
589 return (CS_OK);
590
591 error_unlock:
592 pthread_mutex_unlock (&sam_internal_data.lock);
593
594 return (err);
595 }
596
597 cs_error_t sam_start (void)
598 {
599 char command;
600 cs_error_t err;
601 sam_recovery_policy_t recpol;
602
603 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED) {
604 return (CS_ERR_BAD_HANDLE);
605 }
606
607 recpol = sam_internal_data.recovery_policy;
608
609 if (recpol & SAM_RECOVERY_POLICY_QUORUM || recpol & SAM_RECOVERY_POLICY_CONFDB) {
610 pthread_mutex_lock (&sam_internal_data.lock);
611 }
612
613 command = SAM_COMMAND_START;
614
615 if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) {
616 if (recpol & SAM_RECOVERY_POLICY_QUORUM || recpol & SAM_RECOVERY_POLICY_CONFDB) {
617 pthread_mutex_unlock (&sam_internal_data.lock);
618 }
619
620 return (CS_ERR_LIBRARY);
621 }
622
623 if (recpol & SAM_RECOVERY_POLICY_QUORUM || recpol & SAM_RECOVERY_POLICY_CONFDB) {
624 /*
625 * Wait for parent reply
626 */
627 if ((err = sam_read_reply (sam_internal_data.child_fd_in)) != CS_OK) {
628 pthread_mutex_unlock (&sam_internal_data.lock);
629
630 return (err);
631 }
632
633 pthread_mutex_unlock (&sam_internal_data.lock);
634 }
635
636 if (sam_internal_data.hc_callback)
637 if (sam_safe_write (sam_internal_data.cb_wpipe_fd, &command, sizeof (command)) != sizeof (command))
638 return (CS_ERR_LIBRARY);
639
640 sam_internal_data.internal_status = SAM_INTERNAL_STATUS_STARTED;
641
642 return (CS_OK);
643 }
644
645 cs_error_t sam_stop (void)
646 {
647 char command;
648 cs_error_t err;
649
650 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
651 return (CS_ERR_BAD_HANDLE);
652 }
653
654 command = SAM_COMMAND_STOP;
655
656 if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CONFDB) {
657 pthread_mutex_lock (&sam_internal_data.lock);
658 }
659
660 if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) {
661 if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CONFDB) {
662 pthread_mutex_unlock (&sam_internal_data.lock);
663 }
664
665 return (CS_ERR_LIBRARY);
666 }
667
668 if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CONFDB) {
669 /*
670 * Wait for parent reply
671 */
672 if ((err = sam_read_reply (sam_internal_data.child_fd_in)) != CS_OK) {
673 pthread_mutex_unlock (&sam_internal_data.lock);
674
675 return (err);
676 }
677
678 pthread_mutex_unlock (&sam_internal_data.lock);
679 }
680
681 if (sam_internal_data.hc_callback)
682 if (sam_safe_write (sam_internal_data.cb_wpipe_fd, &command, sizeof (command)) != sizeof (command))
683 return (CS_ERR_LIBRARY);
684
685 sam_internal_data.internal_status = SAM_INTERNAL_STATUS_REGISTERED;
686
687 return (CS_OK);
688 }
689
690 cs_error_t sam_hc_send (void)
691 {
692 char command;
693
694 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
695 return (CS_ERR_BAD_HANDLE);
696 }
697
698 command = SAM_COMMAND_HB;
699
700 if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command))
701 return (CS_ERR_LIBRARY);
702
703 return (CS_OK);
704 }
705
706 cs_error_t sam_finalize (void)
707 {
708 cs_error_t error;
709
710 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED &&
711 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED &&
712 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
713 return (CS_ERR_BAD_HANDLE);
714 }
715
716 if (sam_internal_data.internal_status == SAM_INTERNAL_STATUS_STARTED) {
717 error = sam_stop ();
718 if (error != CS_OK)
719 goto exit_error;
720 }
721
722 sam_internal_data.internal_status = SAM_INTERNAL_STATUS_FINALIZED;
723
724 free (sam_internal_data.user_data);
725
726 exit_error:
727 return (CS_OK);
728 }
729
730 cs_error_t sam_mark_failed (void)
731 {
732 char command;
733
734 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED &&
735 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED) {
736 return (CS_ERR_BAD_HANDLE);
737 }
738
739 if (!(sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CONFDB)) {
740 return (CS_ERR_INVALID_PARAM);
741 }
742
743 command = SAM_COMMAND_MARK_FAILED;
744
745 if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command))
746 return (CS_ERR_LIBRARY);
747
748 return (CS_OK);
749 }
750
751 cs_error_t sam_warn_signal_set (int warn_signal)
752 {
753 char command;
754 cs_error_t err;
755
756 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED &&
757 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED &&
758 sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
759 return (CS_ERR_BAD_HANDLE);
760 }
761
762 pthread_mutex_lock (&sam_internal_data.lock);
763
764 if (sam_internal_data.am_i_child) {
765 /*
766 * We are child so we must send data to parent
767 */
768 command = SAM_COMMAND_WARN_SIGNAL_SET;
769 if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) {
770 err = CS_ERR_LIBRARY;
771
772 goto error_unlock;
773 }
774
775 if (sam_safe_write (sam_internal_data.child_fd_out, &warn_signal, sizeof (warn_signal)) !=
776 sizeof (warn_signal)) {
777 err = CS_ERR_LIBRARY;
778
779 goto error_unlock;
780 }
781
782 /*
783 * And wait for reply
784 */
785 if ((err = sam_read_reply (sam_internal_data.child_fd_in)) != CS_OK) {
786 goto error_unlock;
787 }
788 }
789
790 /*
791 * We are parent or we received OK reply from parent -> do required action
792 */
793 sam_internal_data.warn_signal = warn_signal;
794
795 pthread_mutex_unlock (&sam_internal_data.lock);
796
797 return (CS_OK);
798
799 error_unlock:
800 pthread_mutex_unlock (&sam_internal_data.lock);
801
802 return (err);
803 }
804
805 static cs_error_t sam_parent_reply_send (
806 cs_error_t err,
807 int parent_fd_in,
808 int parent_fd_out)
809 {
810 char reply;
811
812 if (err == CS_OK) {
813 reply = SAM_REPLY_OK;
814
815 if (sam_safe_write (parent_fd_out, &reply, sizeof (reply)) != sizeof (reply)) {
816 err = CS_ERR_LIBRARY;
817 goto error_reply;
818 }
819
820 return (CS_OK);
821 }
822
823 error_reply:
824 reply = SAM_REPLY_ERROR;
825 if (sam_safe_write (parent_fd_out, &reply, sizeof (reply)) != sizeof (reply)) {
826 return (CS_ERR_LIBRARY);
827 }
828 if (sam_safe_write (parent_fd_out, &err, sizeof (err)) != sizeof (err)) {
829 return (CS_ERR_LIBRARY);
830 }
831
832 return (err);
833 }
834
835
836 static cs_error_t sam_parent_warn_signal_set (
837 int parent_fd_in,
838 int parent_fd_out)
839 {
840 int warn_signal;
841 cs_error_t err;
842
843 err = CS_OK;
844
845 if (sam_safe_read (parent_fd_in, &warn_signal, sizeof (warn_signal)) != sizeof (warn_signal)) {
846 err = CS_ERR_LIBRARY;
847 goto error_reply;
848 }
849
850 err = sam_warn_signal_set (warn_signal);
851 if (err != CS_OK) {
852 goto error_reply;
853 }
854
855
856 return (sam_parent_reply_send (CS_OK, parent_fd_in, parent_fd_out));
857
858 error_reply:
859 return (sam_parent_reply_send (err, parent_fd_in, parent_fd_out));
860 }
861
862 static cs_error_t sam_parent_wait_for_quorum (
863 int parent_fd_in,
864 int parent_fd_out)
865 {
866 cs_error_t err;
867 struct pollfd pfds[2];
868 int poll_err;
869
870 if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CONFDB) {
871 if ((err = sam_confdb_update_key (SAM_CONFDB_KEY_STATE, SAM_CONFDB_S_Q_WAIT)) != CS_OK) {
872 goto error_reply;
873 }
874 }
875
876 /*
877 * Update current quorum
878 */
879 if ((err = quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ALL)) != CS_OK) {
880 goto error_reply;
881 }
882
883 /*
884 * Wait for quorum
885 */
886 while (!sam_internal_data.quorate) {
887 pfds[0].fd = parent_fd_in;
888 pfds[0].events = 0;
889 pfds[0].revents = 0;
890
891 pfds[1].fd = sam_internal_data.quorum_fd;
892 pfds[1].events = POLLIN;
893 pfds[1].revents = 0;
894
895 poll_err = poll (pfds, 2, -1);
896
897 if (poll_err == -1) {
898 /*
899 * Error in poll
900 * If it is EINTR, continue, otherwise QUIT
901 */
902 if (errno != EINTR) {
903 err = CS_ERR_LIBRARY;
904 goto error_reply;
905 }
906 }
907
908 if (pfds[0].revents != 0) {
909 if (pfds[0].revents == POLLERR || pfds[0].revents == POLLHUP ||pfds[0].revents == POLLNVAL) {
910 /*
911 * Child has exited
912 */
913 return (CS_OK);
914 }
915 }
916
917 if (pfds[1].revents != 0) {
918 if ((err = quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ONE)) != CS_OK) {
919 goto error_reply;
920 }
921 }
922 }
923
924 if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CONFDB) {
925 if ((err = sam_confdb_update_key (SAM_CONFDB_KEY_STATE, SAM_CONFDB_S_STARTED)) != CS_OK) {
926 goto error_reply;
927 }
928 }
929
930 return (sam_parent_reply_send (CS_OK, parent_fd_in, parent_fd_out));
931
932 error_reply:
933 if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CONFDB) {
934 sam_confdb_update_key (SAM_CONFDB_KEY_STATE, SAM_CONFDB_S_REGISTERED);
935 }
936
937 return (sam_parent_reply_send (err, parent_fd_in, parent_fd_out));
938 }
939
940 static cs_error_t sam_parent_confdb_state_set (
941 int parent_fd_in,
942 int parent_fd_out,
943 int state)
944 {
945 cs_error_t err;
946 const char *state_s;
947
948 if (state == 1) {
949 state_s = SAM_CONFDB_S_STARTED;
950 } else {
951 state_s = SAM_CONFDB_S_REGISTERED;
952 }
953
954 if ((err = sam_confdb_update_key (SAM_CONFDB_KEY_STATE, state_s)) != CS_OK) {
955 goto error_reply;
956 }
957
958 return (sam_parent_reply_send (CS_OK, parent_fd_in, parent_fd_out));
959
960 error_reply:
961 return (sam_parent_reply_send (err, parent_fd_in, parent_fd_out));
962 }
963
964 static cs_error_t sam_parent_kill_child (
965 int *action,
966 pid_t child_pid)
967 {
968 /*
969 * Kill child process
970 */
971 if (!sam_internal_data.term_send) {
972 /*
973 * We didn't send warn_signal yet.
974 */
975 kill (child_pid, sam_internal_data.warn_signal);
976
977 sam_internal_data.term_send = 1;
978 } else {
979 /*
980 * We sent child warning. Now, we will not be so nice
981 */
982 kill (child_pid, SIGKILL);
983 *action = SAM_PARENT_ACTION_RECOVERY;
984 }
985
986 return (CS_OK);
987 }
988
989 static cs_error_t sam_parent_mark_child_failed (
990 int *action,
991 pid_t child_pid)
992 {
993 sam_recovery_policy_t recpol;
994
995 recpol = sam_internal_data.recovery_policy;
996
997 sam_internal_data.term_send = 1;
998 sam_internal_data.recovery_policy = SAM_RECOVERY_POLICY_QUIT |
999 (SAM_RP_MASK_C (recpol) ? SAM_RECOVERY_POLICY_CONFDB : 0) |
1000 (SAM_RP_MASK_Q (recpol) ? SAM_RECOVERY_POLICY_QUORUM : 0);
1001
1002 return (sam_parent_kill_child (action, child_pid));
1003 }
1004
1005 static cs_error_t sam_parent_data_store (
1006 int parent_fd_in,
1007 int parent_fd_out)
1008 {
1009 char *user_data;
1010 ssize_t size;
1011 cs_error_t err;
1012
1013 err = CS_OK;
1014 user_data = NULL;
1015
1016 if (sam_safe_read (parent_fd_in, &size, sizeof (size)) != sizeof (size)) {
1017 err = CS_ERR_LIBRARY;
1018 goto error_reply;
1019 }
1020
1021 if (size > 0) {
1022 user_data = malloc (size);
1023 if (user_data == NULL) {
1024 err = CS_ERR_NO_MEMORY;
1025 goto error_reply;
1026 }
1027
1028 if (sam_safe_read (parent_fd_in, user_data, size) != size) {
1029 err = CS_ERR_LIBRARY;
1030 goto free_error_reply;
1031 }
1032 }
1033
1034 err = sam_data_store (user_data, size);
1035 if (err != CS_OK) {
1036 goto free_error_reply;
1037 }
1038
1039 free (user_data);
1040
1041 return (sam_parent_reply_send (CS_OK, parent_fd_in, parent_fd_out));
1042
1043 free_error_reply:
1044 free (user_data);
1045 error_reply:
1046 return (sam_parent_reply_send (err, parent_fd_in, parent_fd_out));
1047 }
1048
1049 static enum sam_parent_action_t sam_parent_handler (
1050 int parent_fd_in,
1051 int parent_fd_out,
1052 pid_t child_pid)
1053 {
1054 int poll_error;
1055 int action;
1056 int status;
1057 ssize_t bytes_read;
1058 char command;
1059 int time_interval;
1060 struct pollfd pfds[2];
1061 nfds_t nfds;
1062 cs_error_t err;
1063 sam_recovery_policy_t recpol;
1064
1065 status = 0;
1066
1067 action = SAM_PARENT_ACTION_CONTINUE;
1068 recpol = sam_internal_data.recovery_policy;
1069
1070 while (action == SAM_PARENT_ACTION_CONTINUE) {
1071 pfds[0].fd = parent_fd_in;
1072 pfds[0].events = POLLIN;
1073 pfds[0].revents = 0;
1074 nfds = 1;
1075
1076 if (status == 1 && sam_internal_data.time_interval != 0) {
1077 time_interval = sam_internal_data.time_interval;
1078 } else {
1079 time_interval = -1;
1080 }
1081
1082 if (recpol & SAM_RECOVERY_POLICY_QUORUM) {
1083 pfds[nfds].fd = sam_internal_data.quorum_fd;
1084 pfds[nfds].events = POLLIN;
1085 pfds[nfds].revents = 0;
1086 nfds++;
1087 }
1088
1089 poll_error = poll (pfds, nfds, time_interval);
1090
1091 if (poll_error == -1) {
1092 /*
1093 * Error in poll
1094 * If it is EINTR, continue, otherwise QUIT
1095 */
1096 if (errno != EINTR) {
1097 action = SAM_PARENT_ACTION_ERROR;
1098 }
1099 }
1100
1101 if (poll_error == 0) {
1102 /*
1103 * Time limit expires
1104 */
1105 if (status == 0) {
1106 action = SAM_PARENT_ACTION_QUIT;
1107 } else {
1108 sam_parent_kill_child (&action, child_pid);
1109 }
1110 }
1111
1112 if (poll_error > 0) {
1113 if (pfds[0].revents != 0) {
1114 /*
1115 * We have EOF or command in pipe
1116 */
1117 bytes_read = sam_safe_read (parent_fd_in, &command, 1);
1118
1119 if (bytes_read == 0) {
1120 /*
1121 * Handle EOF -> Take recovery action or quit if sam_start wasn't called
1122 */
1123 if (status == 0)
1124 action = SAM_PARENT_ACTION_QUIT;
1125 else
1126 action = SAM_PARENT_ACTION_RECOVERY;
1127
1128 continue;
1129 }
1130
1131 if (bytes_read == -1) {
1132 action = SAM_PARENT_ACTION_ERROR;
1133 goto action_exit;
1134 }
1135
1136 if (recpol & SAM_RECOVERY_POLICY_CONFDB) {
1137 sam_confdb_update_key (SAM_CONFDB_KEY_LAST_HC, NULL);
1138 }
1139
1140 /*
1141 * We have read command
1142 */
1143 switch (command) {
1144 case SAM_COMMAND_START:
1145 if (status == 0) {
1146 /*
1147 * Not started yet
1148 */
1149 if (recpol & SAM_RECOVERY_POLICY_QUORUM) {
1150 if (sam_parent_wait_for_quorum (parent_fd_in,
1151 parent_fd_out) != CS_OK) {
1152 continue;
1153 }
1154 }
1155
1156 if (recpol & SAM_RECOVERY_POLICY_CONFDB) {
1157 if (sam_parent_confdb_state_set (parent_fd_in,
1158 parent_fd_out, 1) != CS_OK) {
1159 continue;
1160 }
1161 }
1162
1163 status = 1;
1164 }
1165 break;
1166 case SAM_COMMAND_STOP:
1167 if (status == 1) {
1168 /*
1169 * Started
1170 */
1171 if (recpol & SAM_RECOVERY_POLICY_CONFDB) {
1172 if (sam_parent_confdb_state_set (parent_fd_in,
1173 parent_fd_out, 0) != CS_OK) {
1174 continue;
1175 }
1176 }
1177
1178 status = 0;
1179 }
1180 break;
1181 case SAM_COMMAND_DATA_STORE:
1182 sam_parent_data_store (parent_fd_in, parent_fd_out);
1183 break;
1184 case SAM_COMMAND_WARN_SIGNAL_SET:
1185 sam_parent_warn_signal_set (parent_fd_in, parent_fd_out);
1186 break;
1187 case SAM_COMMAND_MARK_FAILED:
1188 status = 1;
1189 sam_parent_mark_child_failed (&action, child_pid);
1190 break;
1191 }
1192 } /* if (pfds[0].revents != 0) */
1193
1194 if ((sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_QUORUM) &&
1195 pfds[1].revents != 0) {
1196 /*
1197 * Handle quorum change
1198 */
1199 err = quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ALL);
1200
1201 if (status == 1 &&
1202 (!sam_internal_data.quorate || (err != CS_ERR_TRY_AGAIN && err != CS_OK))) {
1203 sam_parent_kill_child (&action, child_pid);
1204 }
1205 }
1206 } /* select_error > 0 */
1207 } /* action == SAM_PARENT_ACTION_CONTINUE */
1208
1209 action_exit:
1210 return action;
1211 }
1212
1213 cs_error_t sam_register (
1214 unsigned int *instance_id)
1215 {
1216 cs_error_t error;
1217 pid_t pid;
1218 int pipe_error;
1219 int pipe_fd_out[2], pipe_fd_in[2];
1220 enum sam_parent_action_t action, old_action;
1221 int child_status;
1222 sam_recovery_policy_t recpol;
1223
1224 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED) {
1225 return (CS_ERR_BAD_HANDLE);
1226 }
1227
1228 recpol = sam_internal_data.recovery_policy;
1229
1230 if (recpol & SAM_RECOVERY_POLICY_CONFDB) {
1231 /*
1232 * Register to objdb
1233 */
1234 if ((error = sam_confdb_register ()) != CS_OK) {
1235 goto error_exit;
1236 }
1237 }
1238
1239 error = CS_OK;
1240
1241 while (1) {
1242 if ((pipe_error = pipe (pipe_fd_out)) != 0) {
1243 error = CS_ERR_LIBRARY;
1244 goto error_exit;
1245 }
1246
1247 if ((pipe_error = pipe (pipe_fd_in)) != 0) {
1248 close (pipe_fd_out[0]);
1249 close (pipe_fd_out[1]);
1250
1251 error = CS_ERR_LIBRARY;
1252 goto error_exit;
1253 }
1254
1255 if (recpol & SAM_RECOVERY_POLICY_CONFDB) {
1256 if ((error = sam_confdb_update_key (SAM_CONFDB_KEY_STATE, SAM_CONFDB_S_REGISTERED)) != CS_OK) {
1257 goto error_exit;
1258 }
1259 }
1260
1261 sam_internal_data.instance_id++;
1262
1263 sam_internal_data.term_send = 0;
1264
1265 pid = fork ();
1266
1267 if (pid == -1) {
1268 /*
1269 * Fork error
1270 */
1271 sam_internal_data.instance_id--;
1272
1273 error = CS_ERR_LIBRARY;
1274 goto error_exit;
1275 }
1276
1277 if (pid == 0) {
1278 /*
1279 * Child process
1280 */
1281 close (pipe_fd_out[0]);
1282 close (pipe_fd_in[1]);
1283
1284 sam_internal_data.child_fd_out = pipe_fd_out[1];
1285 sam_internal_data.child_fd_in = pipe_fd_in[0];
1286
1287 if (instance_id)
1288 *instance_id = sam_internal_data.instance_id;
1289
1290 sam_internal_data.am_i_child = 1;
1291 sam_internal_data.internal_status = SAM_INTERNAL_STATUS_REGISTERED;
1292
1293 pthread_mutex_init (&sam_internal_data.lock, NULL);
1294
1295 goto error_exit;
1296 } else {
1297 /*
1298 * Parent process
1299 */
1300 close (pipe_fd_out[1]);
1301 close (pipe_fd_in[0]);
1302
1303 action = sam_parent_handler (pipe_fd_out[0], pipe_fd_in[1], pid);
1304
1305 close (pipe_fd_out[0]);
1306 close (pipe_fd_in[1]);
1307
1308 if (action == SAM_PARENT_ACTION_ERROR) {
1309 error = CS_ERR_LIBRARY;
1310 goto error_exit;
1311 }
1312
1313 /*
1314 * We really don't like zombies
1315 */
1316 while (waitpid (pid, &child_status, 0) == -1 && errno == EINTR)
1317 ;
1318
1319 old_action = action;
1320
1321 if (action == SAM_PARENT_ACTION_RECOVERY) {
1322 if (SAM_RP_MASK (sam_internal_data.recovery_policy) == SAM_RECOVERY_POLICY_QUIT)
1323 action = SAM_PARENT_ACTION_QUIT;
1324 }
1325
1326
1327 if (action == SAM_PARENT_ACTION_QUIT) {
1328 if (recpol & SAM_RECOVERY_POLICY_QUORUM) {
1329 quorum_finalize (sam_internal_data.quorum_handle);
1330 }
1331
1332 if (recpol & SAM_RECOVERY_POLICY_CONFDB) {
1333 if (old_action == SAM_PARENT_ACTION_RECOVERY) {
1334 /*
1335 * Mark as failed
1336 */
1337 sam_confdb_update_key (SAM_CONFDB_KEY_STATE, SAM_CONFDB_S_FAILED);
1338 } else {
1339 sam_confdb_destroy_pid_obj ();
1340 }
1341 }
1342
1343 exit (WEXITSTATUS (child_status));
1344 }
1345
1346
1347 }
1348 }
1349
1350 error_exit:
1351 return (error);
1352 }
1353
1354 static void *hc_callback_thread (void *unused_param)
1355 {
1356 int poll_error;
1357 int status;
1358 ssize_t bytes_readed;
1359 char command;
1360 int time_interval, tmp_time_interval;
1361 int counter;
1362 struct pollfd pfds;
1363
1364 status = 0;
1365 counter = 0;
1366
1367 time_interval = sam_internal_data.time_interval >> 2;
1368
1369 while (1) {
1370 pfds.fd = sam_internal_data.cb_rpipe_fd;
1371 pfds.events = POLLIN;
1372 pfds.revents = 0;
1373
1374 if (status == 1) {
1375 tmp_time_interval = time_interval;
1376 } else {
1377 tmp_time_interval = -1;
1378 }
1379
1380 poll_error = poll (&pfds, 1, tmp_time_interval);
1381
1382 if (poll_error == 0) {
1383 if (sam_hc_send () == CS_OK) {
1384 counter++;
1385 }
1386
1387 if (counter >= 4) {
1388 if (sam_internal_data.hc_callback () != 0) {
1389 status = 3;
1390 }
1391
1392 counter = 0;
1393 }
1394 }
1395
1396 if (poll_error > 0) {
1397 bytes_readed = sam_safe_read (sam_internal_data.cb_rpipe_fd, &command, 1);
1398
1399 if (bytes_readed > 0) {
1400 if (status == 0 && command == SAM_COMMAND_START)
1401 status = 1;
1402
1403 if (status == 1 && command == SAM_COMMAND_STOP)
1404 status = 0;
1405
1406 }
1407 }
1408 }
1409
1410 /*
1411 * This makes compiler happy, it's same as return (NULL);
1412 */
1413 return (unused_param);
1414 }
1415
1416 cs_error_t sam_hc_callback_register (sam_hc_callback_t cb)
1417 {
1418 cs_error_t error = CS_OK;
1419 pthread_attr_t thread_attr;
1420 int pipe_error;
1421 int pipe_fd[2];
1422
1423 if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED) {
1424 return (CS_ERR_BAD_HANDLE);
1425 }
1426
1427 if (sam_internal_data.time_interval == 0) {
1428 return (CS_ERR_INVALID_PARAM);
1429 }
1430
1431 if (sam_internal_data.cb_registered) {
1432 sam_internal_data.hc_callback = cb;
1433
1434 return (CS_OK);
1435 }
1436
1437 /*
1438 * We know, this is first registration
1439 */
1440
1441 if (cb == NULL) {
1442 return (CS_ERR_INVALID_PARAM);
1443 }
1444
1445 pipe_error = pipe (pipe_fd);
1446
1447 if (pipe_error != 0) {
1448 /*
1449 * Pipe creation error
1450 */
1451 error = CS_ERR_LIBRARY;
1452 goto error_exit;
1453 }
1454
1455 sam_internal_data.cb_rpipe_fd = pipe_fd[0];
1456 sam_internal_data.cb_wpipe_fd = pipe_fd[1];
1457
1458 /*
1459 * Create thread attributes
1460 */
1461 error = pthread_attr_init (&thread_attr);
1462 if (error != 0) {
1463 error = CS_ERR_LIBRARY;
1464 goto error_close_fd_exit;
1465 }
1466
1467
1468 pthread_attr_setdetachstate (&thread_attr, PTHREAD_CREATE_DETACHED);
1469 pthread_attr_setstacksize (&thread_attr, 32768);
1470
1471 /*
1472 * Create thread
1473 */
1474 error = pthread_create (&sam_internal_data.cb_thread, &thread_attr, hc_callback_thread, NULL);
1475
1476 if (error != 0) {
1477 error = CS_ERR_LIBRARY;
1478 goto error_attr_destroy_exit;
1479 }
1480
1481 /*
1482 * Cleanup
1483 */
1484 pthread_attr_destroy(&thread_attr);
1485
1486 sam_internal_data.cb_registered = 1;
1487 sam_internal_data.hc_callback = cb;
1488
1489 return (CS_OK);
1490
1491 error_attr_destroy_exit:
1492 pthread_attr_destroy(&thread_attr);
1493 error_close_fd_exit:
1494 sam_internal_data.cb_rpipe_fd = sam_internal_data.cb_wpipe_fd = 0;
1495 close (pipe_fd[0]);
1496 close (pipe_fd[1]);
1497 error_exit:
1498 return (error);
1499 }