2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2 only,
7 * as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include <sys/types.h>
35 #include <common/common.h>
36 #include <common/utils.h>
37 #include <common/compat/getenv.h>
38 #include <common/compat/prctl.h>
39 #include <common/unix.h>
40 #include <common/defaults.h>
41 #include <common/lttng-elf.h>
43 #include <lttng/constant.h>
49 typedef int (*run_as_fct
)(struct run_as_data
*data
, struct run_as_ret
*ret_value
);
51 struct run_as_mkdir_data
{
56 struct run_as_open_data
{
62 struct run_as_unlink_data
{
66 struct run_as_rmdir_recursive_data
{
70 struct run_as_extract_elf_symbol_offset_data
{
71 char function
[LTTNG_SYMBOL_NAME_LEN
];
74 struct run_as_mkdir_ret
{
78 struct run_as_open_ret
{
82 struct run_as_unlink_ret
{
86 struct run_as_rmdir_recursive_ret
{
90 struct run_as_extract_elf_symbol_offset_ret
{
98 RUN_AS_RMDIR_RECURSIVE
,
99 RUN_AS_MKDIR_RECURSIVE
,
100 RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
,
107 struct run_as_mkdir_data mkdir
;
108 struct run_as_open_data open
;
109 struct run_as_unlink_data unlink
;
110 struct run_as_rmdir_recursive_data rmdir_recursive
;
111 struct run_as_extract_elf_symbol_offset_data extract_elf_symbol_offset
;
118 * The run_as_ret structure holds the returned value and status of the command.
120 * The `u` union field holds the return value of the command; in most cases it
121 * represents the success or the failure of the command. In more complex
122 * commands, it holds a computed value.
124 * The _errno field is the errno recorded after the execution of the command.
126 * The _error fields is used the signify that return status of the command. For
127 * simple commands returning `int` the _error field will be the same as the
128 * ret_int field. In complex commands, it signify the success or failure of the
135 struct run_as_mkdir_ret mkdir
;
136 struct run_as_open_ret open
;
137 struct run_as_unlink_ret unlink
;
138 struct run_as_rmdir_recursive_ret rmdir_recursive
;
139 struct run_as_extract_elf_symbol_offset_ret extract_elf_symbol_offset
;
145 struct run_as_worker
{
146 pid_t pid
; /* Worker PID. */
151 /* Single global worker per process (for now). */
152 static struct run_as_worker
*global_worker
;
153 /* Lock protecting the worker. */
154 static pthread_mutex_t worker_lock
= PTHREAD_MUTEX_INITIALIZER
;
166 return !lttng_secure_getenv("LTTNG_DEBUG_NOCLONE");
171 int _utils_mkdir_recursive_unsafe(const char *path
, mode_t mode
);
174 * Create recursively directory using the FULL path.
177 int _mkdir_recursive(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
182 path
= data
->u
.mkdir
.path
;
183 mode
= data
->u
.mkdir
.mode
;
185 /* Safe to call as we have transitioned to the requested uid/gid. */
186 ret_value
->u
.mkdir
.ret
= _utils_mkdir_recursive_unsafe(path
, mode
);
187 ret_value
->_errno
= errno
;
188 ret_value
->_error
= (ret_value
->u
.mkdir
.ret
) ? true : false;
189 return ret_value
->u
.mkdir
.ret
;
193 int _mkdir(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
195 ret_value
->u
.mkdir
.ret
= mkdir(data
->u
.mkdir
.path
, data
->u
.mkdir
.mode
);
196 ret_value
->_errno
= errno
;
197 ret_value
->_error
= (ret_value
->u
.mkdir
.ret
) ? true : false;
198 return ret_value
->u
.mkdir
.ret
;
202 int _open(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
204 ret_value
->u
.open
.ret
= open(data
->u
.open
.path
, data
->u
.open
.flags
, data
->u
.open
.mode
);
205 ret_value
->fd
= ret_value
->u
.open
.ret
;
206 ret_value
->_errno
= errno
;
207 ret_value
->_error
= (ret_value
->u
.open
.ret
) ? true : false;
208 return ret_value
->u
.open
.ret
;
212 int _unlink(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
214 ret_value
->u
.unlink
.ret
= unlink(data
->u
.unlink
.path
);
215 ret_value
->_errno
= errno
;
216 ret_value
->_error
= (ret_value
->u
.unlink
.ret
) ? true : false;
217 return ret_value
->u
.unlink
.ret
;
221 int _rmdir_recursive(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
223 ret_value
->u
.rmdir_recursive
.ret
= utils_recursive_rmdir(data
->u
.rmdir_recursive
.path
);
224 ret_value
->_errno
= errno
;
225 ret_value
->_error
= (ret_value
->u
.rmdir_recursive
.ret
) ? true : false;
226 return ret_value
->u
.rmdir_recursive
.ret
;
230 int _extract_elf_symbol_offset(struct run_as_data
*data
,
231 struct run_as_ret
*ret_value
)
234 ret_value
->_error
= false;
236 ret
= lttng_elf_get_symbol_offset(data
->fd
,
237 data
->u
.extract_elf_symbol_offset
.function
,
238 &ret_value
->u
.extract_elf_symbol_offset
.offset
);
240 DBG("Failed to extract ELF function offset");
241 ret_value
->_error
= true;
249 run_as_fct
run_as_enum_to_fct(enum run_as_cmd cmd
)
258 case RUN_AS_RMDIR_RECURSIVE
:
259 return _rmdir_recursive
;
260 case RUN_AS_MKDIR_RECURSIVE
:
261 return _mkdir_recursive
;
262 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
:
263 return _extract_elf_symbol_offset
;
265 ERR("Unknown command %d", (int) cmd
);
271 int do_send_fd(int sock
, int fd
)
276 ERR("Invalid file description");
280 len
= lttcomm_send_fds_unix_sock(sock
, &fd
, 1);
282 PERROR("lttcomm_send_fds_unix_sock");
289 int do_recv_fd(int sock
, int *fd
)
294 ERR("Invalid file description");
298 len
= lttcomm_recv_fds_unix_sock(sock
, fd
, 1);
302 } else if (len
< 0) {
303 PERROR("lttcomm_recv_fds_unix_sock");
310 int send_fd_to_worker(struct run_as_worker
*worker
, enum run_as_cmd cmd
, int fd
)
315 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
:
321 ret
= do_send_fd(worker
->sockpair
[0], fd
);
323 PERROR("do_send_fd");
331 int send_fd_to_master(struct run_as_worker
*worker
, enum run_as_cmd cmd
, int fd
)
333 int ret
= 0, ret_close
= 0;
342 ret
= do_send_fd(worker
->sockpair
[1], fd
);
344 PERROR("do_send_fd error");
348 ret_close
= close(fd
);
357 int recv_fd_from_worker(struct run_as_worker
*worker
, enum run_as_cmd cmd
, int *fd
)
368 ret
= do_recv_fd(worker
->sockpair
[0], fd
);
370 PERROR("do_recv_fd error");
378 int recv_fd_from_master(struct run_as_worker
*worker
, enum run_as_cmd cmd
, int *fd
)
383 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
:
389 ret
= do_recv_fd(worker
->sockpair
[1], fd
);
391 PERROR("do_recv_fd error");
399 int cleanup_received_fd(enum run_as_cmd cmd
, int fd
)
404 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
:
412 PERROR("close error");
419 * Return < 0 on error, 0 if OK, 1 on hangup.
422 int handle_one_cmd(struct run_as_worker
*worker
)
425 struct run_as_data data
;
426 ssize_t readlen
, writelen
;
427 struct run_as_ret sendret
;
432 * Stage 1: Receive run_as_data struct from the master.
433 * The structure contains the command type and all the parameters needed for
436 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[1], &data
,
443 if (readlen
< sizeof(data
)) {
444 PERROR("lttcomm_recv_unix_sock error");
449 cmd
= run_as_enum_to_fct(data
.cmd
);
456 * Stage 2: Receive file descriptor from master.
457 * Some commands need a file descriptor as input so if it's needed we
458 * receive the fd using the Unix socket.
460 ret
= recv_fd_from_master(worker
, data
.cmd
, &data
.fd
);
462 PERROR("recv_fd_from_master error");
467 prev_euid
= getuid();
468 if (data
.gid
!= getegid()) {
469 ret
= setegid(data
.gid
);
475 if (data
.uid
!= prev_euid
) {
476 ret
= seteuid(data
.uid
);
484 * Also set umask to 0 for mkdir executable bit.
489 * Stage 3: Execute the command
491 ret
= (*cmd
)(&data
, &sendret
);
493 DBG("Execution of command returned an error");
497 ret
= cleanup_received_fd(data
.cmd
, data
.fd
);
499 ERR("Error cleaning up FD");
504 * Stage 4: Send run_as_ret structure to the master.
505 * This structure contain the return value of the command and the errno.
507 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
,
509 if (writelen
< sizeof(sendret
)) {
510 PERROR("lttcomm_send_unix_sock error");
516 * Stage 5: Send file descriptor to the master
517 * Some commands return a file descriptor so if it's needed we pass it back
518 * to the master using the Unix socket.
520 ret
= send_fd_to_master(worker
, data
.cmd
, sendret
.fd
);
522 DBG("Sending FD to master returned an error");
526 if (seteuid(prev_euid
) < 0) {
537 int run_as_worker(struct run_as_worker
*worker
)
541 struct run_as_ret sendret
;
542 size_t proc_orig_len
;
545 * Initialize worker. Set a different process cmdline.
547 proc_orig_len
= strlen(worker
->procname
);
548 memset(worker
->procname
, 0, proc_orig_len
);
549 strncpy(worker
->procname
, DEFAULT_RUN_AS_WORKER_NAME
, proc_orig_len
);
551 ret
= lttng_prctl(PR_SET_NAME
,
552 (unsigned long) DEFAULT_RUN_AS_WORKER_NAME
, 0, 0, 0);
553 if (ret
&& ret
!= -ENOSYS
) {
554 /* Don't fail as this is not essential. */
555 PERROR("prctl PR_SET_NAME");
558 memset(&sendret
, 0, sizeof(sendret
));
560 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
,
562 if (writelen
< sizeof(sendret
)) {
563 PERROR("lttcomm_send_unix_sock error");
569 ret
= handle_one_cmd(worker
);
573 } else if (ret
> 0) {
576 continue; /* Next command. */
585 int run_as_cmd(struct run_as_worker
*worker
,
587 struct run_as_data
*data
,
588 struct run_as_ret
*ret_value
,
589 uid_t uid
, gid_t gid
)
592 ssize_t readlen
, writelen
;
595 * If we are non-root, we can only deal with our own uid.
597 if (geteuid() != 0) {
598 if (uid
!= geteuid()) {
600 ret_value
->_errno
= EPERM
;
601 ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)",
602 (int) uid
, (int) geteuid());
612 * Stage 1: Send the run_as_data struct to the worker process
614 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[0], data
,
616 if (writelen
< sizeof(*data
)) {
617 PERROR("Error writing message to run_as");
619 ret_value
->_errno
= EIO
;
624 * Stage 2: Send file descriptor to the worker process if needed
626 ret
= send_fd_to_worker(worker
, data
->cmd
, data
->fd
);
628 PERROR("do_send_fd error");
630 ret_value
->_errno
= EIO
;
635 * Stage 3: Wait for the execution of the command
639 * Stage 4: Receive the run_as_ret struct containing the return value and
642 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0], ret_value
,
645 ERR("Run-as worker has hung-up during run_as_cmd");
647 ret_value
->_errno
= EIO
;
649 } else if (readlen
< sizeof(*ret_value
)) {
650 PERROR("Error reading response from run_as");
652 ret_value
->_errno
= errno
;
656 * Stage 5: Receive file descriptor if needed
658 ret
= recv_fd_from_worker(worker
, data
->cmd
, &ret_value
->fd
);
660 ERR("Error receiving fd");
662 ret_value
->_errno
= EIO
;
670 * This is for debugging ONLY and should not be considered secure.
673 int run_as_noworker(enum run_as_cmd cmd
,
674 struct run_as_data
*data
, struct run_as_ret
*ret_value
,
675 uid_t uid
, gid_t gid
)
677 int ret
, saved_errno
;
681 fct
= run_as_enum_to_fct(cmd
);
688 ret
= fct(data
, ret_value
);
689 saved_errno
= ret_value
->_errno
;
697 int run_as_restart_worker(struct run_as_worker
*worker
)
700 char *procname
= NULL
;
702 procname
= worker
->procname
;
704 /* Close socket to run_as worker process and clean up the zombie process */
705 run_as_destroy_worker();
707 /* Create a new run_as worker process*/
708 ret
= run_as_create_worker(procname
);
710 ERR("Restarting the worker process failed");
719 int run_as(enum run_as_cmd cmd
, struct run_as_data
*data
,
720 struct run_as_ret
*ret_value
, uid_t uid
, gid_t gid
)
722 int ret
, saved_errno
;
725 DBG("Using run_as worker");
726 pthread_mutex_lock(&worker_lock
);
727 assert(global_worker
);
729 ret
= run_as_cmd(global_worker
, cmd
, data
, ret_value
, uid
, gid
);
730 saved_errno
= ret_value
->_errno
;
732 pthread_mutex_unlock(&worker_lock
);
734 * If the worker thread crashed the errno is set to EIO. we log
735 * the error and start a new worker process.
737 if (ret
== -1 && saved_errno
== EIO
) {
738 DBG("Socket closed unexpectedly... "
739 "Restarting the worker process");
740 ret
= run_as_restart_worker(global_worker
);
743 ERR("Failed to restart worker process.");
748 DBG("Using run_as without worker");
749 ret
= run_as_noworker(cmd
, data
, ret_value
, uid
, gid
);
756 int run_as_mkdir_recursive(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
758 struct run_as_data data
;
759 struct run_as_ret ret
;
761 memset(&data
, 0, sizeof(data
));
762 memset(&ret
, 0, sizeof(ret
));
763 DBG3("mkdir() recursive %s with mode %d for uid %d and gid %d",
764 path
, (int) mode
, (int) uid
, (int) gid
);
765 strncpy(data
.u
.mkdir
.path
, path
, PATH_MAX
- 1);
766 data
.u
.mkdir
.path
[PATH_MAX
- 1] = '\0';
767 data
.u
.mkdir
.mode
= mode
;
769 run_as(RUN_AS_MKDIR_RECURSIVE
, &data
, &ret
, uid
, gid
);
771 return ret
.u
.mkdir
.ret
;
775 int run_as_mkdir(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
777 struct run_as_data data
;
778 struct run_as_ret ret
;
780 memset(&data
, 0, sizeof(data
));
781 memset(&ret
, 0, sizeof(ret
));
783 DBG3("mkdir() %s with mode %d for uid %d and gid %d",
784 path
, (int) mode
, (int) uid
, (int) gid
);
785 strncpy(data
.u
.mkdir
.path
, path
, PATH_MAX
- 1);
786 data
.u
.mkdir
.path
[PATH_MAX
- 1] = '\0';
787 data
.u
.mkdir
.mode
= mode
;
788 run_as(RUN_AS_MKDIR
, &data
, &ret
, uid
, gid
);
790 return ret
.u
.mkdir
.ret
;
794 int run_as_open(const char *path
, int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
796 struct run_as_data data
;
797 struct run_as_ret ret
;
799 memset(&data
, 0, sizeof(data
));
800 memset(&ret
, 0, sizeof(ret
));
802 DBG3("open() %s with flags %X mode %d for uid %d and gid %d",
803 path
, flags
, (int) mode
, (int) uid
, (int) gid
);
804 strncpy(data
.u
.open
.path
, path
, PATH_MAX
- 1);
805 data
.u
.open
.path
[PATH_MAX
- 1] = '\0';
806 data
.u
.open
.flags
= flags
;
807 data
.u
.open
.mode
= mode
;
808 run_as(RUN_AS_OPEN
, &data
, &ret
, uid
, gid
);
810 ret
.u
.open
.ret
= ret
.fd
;
811 return ret
.u
.open
.ret
;
815 int run_as_unlink(const char *path
, uid_t uid
, gid_t gid
)
817 struct run_as_data data
;
818 struct run_as_ret ret
;
820 memset(&data
, 0, sizeof(data
));
821 memset(&ret
, 0, sizeof(ret
));
823 DBG3("unlink() %s with for uid %d and gid %d",
824 path
, (int) uid
, (int) gid
);
825 strncpy(data
.u
.unlink
.path
, path
, PATH_MAX
- 1);
826 data
.u
.unlink
.path
[PATH_MAX
- 1] = '\0';
827 run_as(RUN_AS_UNLINK
, &data
, &ret
, uid
, gid
);
829 return ret
.u
.unlink
.ret
;
833 int run_as_rmdir_recursive(const char *path
, uid_t uid
, gid_t gid
)
835 struct run_as_data data
;
836 struct run_as_ret ret
;
838 memset(&data
, 0, sizeof(data
));
839 memset(&ret
, 0, sizeof(ret
));
841 DBG3("rmdir_recursive() %s with for uid %d and gid %d",
842 path
, (int) uid
, (int) gid
);
843 strncpy(data
.u
.rmdir_recursive
.path
, path
, PATH_MAX
- 1);
844 data
.u
.rmdir_recursive
.path
[PATH_MAX
- 1] = '\0';
845 run_as(RUN_AS_RMDIR_RECURSIVE
, &data
, &ret
, uid
, gid
);
847 return ret
.u
.rmdir_recursive
.ret
;
851 int run_as_extract_elf_symbol_offset(int fd
, const char* function
,
852 uid_t uid
, gid_t gid
, uint64_t *offset
)
854 struct run_as_data data
;
855 struct run_as_ret ret
;
857 DBG3("extract_elf_symbol_offset() on fd=%d and function=%s "
858 "with for uid %d and gid %d", fd
, function
, (int) uid
, (int) gid
);
862 strncpy(data
.u
.extract_elf_symbol_offset
.function
, function
, LTTNG_SYMBOL_NAME_LEN
- 1);
864 data
.u
.extract_elf_symbol_offset
.function
[LTTNG_SYMBOL_NAME_LEN
- 1] = '\0';
866 run_as(RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
, &data
, &ret
, uid
, gid
);
874 *offset
= ret
.u
.extract_elf_symbol_offset
.offset
;
879 int reset_sighandler(void)
883 DBG("Resetting run_as worker signal handlers to default");
884 for (sig
= 1; sig
<= 31; sig
++) {
885 (void) signal(sig
, SIG_DFL
);
891 void worker_sighandler(int sig
)
896 * The worker will inherit its parent's signals since they are part of
897 * the same process group. However, in the case of SIGINT and SIGTERM,
898 * we want to give the worker a chance to teardown gracefully when its
899 * parent closes the command socket.
913 DBG("run_as worker received signal %s", signame
);
915 DBG("run_as_worker received signal %d", sig
);
920 int set_worker_sighandlers(void)
926 if ((ret
= sigemptyset(&sigset
)) < 0) {
927 PERROR("sigemptyset");
931 sa
.sa_handler
= worker_sighandler
;
934 if ((ret
= sigaction(SIGINT
, &sa
, NULL
)) < 0) {
935 PERROR("sigaction SIGINT");
939 if ((ret
= sigaction(SIGTERM
, &sa
, NULL
)) < 0) {
940 PERROR("sigaction SIGTERM");
944 DBG("run_as signal handler set for SIGTERM and SIGINT");
950 int run_as_create_worker(char *procname
)
955 struct run_as_ret recvret
;
956 struct run_as_worker
*worker
;
958 pthread_mutex_lock(&worker_lock
);
959 assert(!global_worker
);
962 * Don't initialize a worker, all run_as tasks will be performed
963 * in the current process.
968 worker
= zmalloc(sizeof(*worker
));
973 worker
->procname
= procname
;
974 /* Create unix socket. */
975 if (lttcomm_create_anon_unix_socketpair(worker
->sockpair
) < 0) {
986 } else if (pid
== 0) {
991 set_worker_sighandlers();
993 /* The child has no use for this lock. */
994 pthread_mutex_unlock(&worker_lock
);
995 /* Just close, no shutdown. */
996 if (close(worker
->sockpair
[0])) {
1002 * Close all FDs aside from STDIN, STDOUT, STDERR and sockpair[1]
1003 * Sockpair[1] is used as a control channel with the master
1005 for (i
= 3; i
< sysconf(_SC_OPEN_MAX
); i
++) {
1006 if (i
!= worker
->sockpair
[1]) {
1011 worker
->sockpair
[0] = -1;
1012 ret
= run_as_worker(worker
);
1013 if (lttcomm_close_unix_sock(worker
->sockpair
[1])) {
1017 worker
->sockpair
[1] = -1;
1018 LOG(ret
? PRINT_ERR
: PRINT_DBG
, "run_as worker exiting (ret = %d)", ret
);
1019 exit(ret
? EXIT_FAILURE
: EXIT_SUCCESS
);
1023 /* Just close, no shutdown. */
1024 if (close(worker
->sockpair
[1])) {
1029 worker
->sockpair
[1] = -1;
1031 /* Wait for worker to become ready. */
1032 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0],
1033 &recvret
, sizeof(recvret
));
1034 if (readlen
< sizeof(recvret
)) {
1035 ERR("readlen: %zd", readlen
);
1036 PERROR("Error reading response from run_as at creation");
1040 global_worker
= worker
;
1043 pthread_mutex_unlock(&worker_lock
);
1046 /* Error handling. */
1048 for (i
= 0; i
< 2; i
++) {
1049 if (worker
->sockpair
[i
] < 0) {
1052 if (lttcomm_close_unix_sock(worker
->sockpair
[i
])) {
1055 worker
->sockpair
[i
] = -1;
1059 pthread_mutex_unlock(&worker_lock
);
1064 void run_as_destroy_worker(void)
1066 struct run_as_worker
*worker
= global_worker
;
1068 DBG("Destroying run_as worker");
1069 pthread_mutex_lock(&worker_lock
);
1073 /* Close unix socket */
1074 DBG("Closing run_as worker socket");
1075 if (lttcomm_close_unix_sock(worker
->sockpair
[0])) {
1078 worker
->sockpair
[0] = -1;
1079 /* Wait for worker. */
1084 wait_ret
= waitpid(worker
->pid
, &status
, 0);
1086 if (errno
== EINTR
) {
1093 if (WIFEXITED(status
)) {
1094 LOG(WEXITSTATUS(status
) == 0 ? PRINT_DBG
: PRINT_ERR
,
1095 DEFAULT_RUN_AS_WORKER_NAME
" terminated with status code %d",
1096 WEXITSTATUS(status
));
1098 } else if (WIFSIGNALED(status
)) {
1099 ERR(DEFAULT_RUN_AS_WORKER_NAME
" was killed by signal %d",
1105 global_worker
= NULL
;
1107 pthread_mutex_unlock(&worker_lock
);