From: Kern Sibbald Date: Thu, 26 May 2005 18:58:17 +0000 (+0000) Subject: - Make JCR a class and implement inc_use_count() and X-Git-Tag: Release-1.38.0~411 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=ca4fb05c797d800d0bcf4bf04b77870df2dbcedb;p=bacula%2Fbacula - Make JCR a class and implement inc_use_count() and dec_use_count() methods that ensure that the jcr is locked when inc/dec the use count. - Remove the global jcr lock when traversing the jcr chain. - Use dlist to implement the jcr chain rather than hand crafted next and prev links. - Lock the jcr chain inside each function that modifies the chain. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@2089 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/kernstodo b/bacula/kernstodo index f64d347891..c3d0325758 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -1,5 +1,5 @@ Kern's ToDo List - 20 May 2005 + 26 May 2005 Major development: Project Developer @@ -52,13 +52,9 @@ Document: - Document testing - Document that ChangerDevice is used for Alert command. - Document new CDROM directory. +- Document Heartbeat Interval in the dealing with firewalls section. For 1.37: -- From Chris Hull: - it seems to be complaining about 12:00pm which should be a valid 12 - hour time. I changed the time to 11:59am and everything works fine. - Also 12:00am works fine. 0:00pm also works (which I don't think - should). None of the values 12:00pm - 12:59pm work for that matter. === rate design jcr->last_rate jcr->last_runtime @@ -1284,3 +1280,9 @@ Block Position: 0 - Add "limit=n" for "list jobs" - Make bootstrap filename unique. - Make Dmsg look at global before calling subroutine. +- From Chris Hull: + it seems to be complaining about 12:00pm which should be a valid 12 + hour time. I changed the time to 11:59am and everything works fine. + Also 12:00am works fine. 0:00pm also works (which I don't think + should). None of the values 12:00pm - 12:59pm work for that matter. + diff --git a/bacula/kes-1.37 b/bacula/kes-1.37 index edd1500e03..b5a483f514 100644 --- a/bacula/kes-1.37 +++ b/bacula/kes-1.37 @@ -3,6 +3,18 @@ General: +Changes to 1.37.20: +26May05 +- Make JCR a class and implement inc_use_count() and + dec_use_count() methods that ensure that the jcr is + locked when inc/dec the use count. +- Remove the global jcr lock when traversing the jcr + chain. +- Use dlist to implement the jcr chain rather than hand + crafted next and prev links. +- Lock the jcr chain inside each function that modifies + the chain. + Changes to 1.37.19: 26May05 - Fix compile problem of ua_restore.c on broken compilers. diff --git a/bacula/src/dird/dird.c b/bacula/src/dird/dird.c index e28738c4e8..b8ee906569 100644 --- a/bacula/src/dird/dird.c +++ b/bacula/src/dird/dird.c @@ -392,8 +392,6 @@ void reload_config(int sig) sigaddset(&set, SIGHUP); sigprocmask(SIG_BLOCK, &set, NULL); -// Jmsg(NULL, M_INFO, 0, "Entering experimental reload config code. Bug reports will not be accepted.\n"); - lock_jcr_chain(); LockRes(); @@ -437,7 +435,7 @@ void reload_config(int sig) job_end_push(jcr, reload_job_end_cb, (void *)((long int)table)); njobs++; } - free_locked_jcr(jcr); + free_jcr(jcr); } } @@ -447,8 +445,6 @@ void reload_config(int sig) SDConnectTimeout = director->SDConnectTimeout; Dmsg0(0, "Director's configuration file reread.\n"); -// init_device_resources(); /* Update Device resources */ - /* Now release saved resources, if no jobs using the resources */ if (njobs == 0) { free_saved_resources(table); diff --git a/bacula/src/dird/job.c b/bacula/src/dird/job.c index 5f5de77d8d..9c6ba26e34 100644 --- a/bacula/src/dird/job.c +++ b/bacula/src/dird/job.c @@ -10,19 +10,14 @@ Copyright (C) 2000-2005 Kern Sibbald This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. + modify it under the terms of the GNU General Public License + version 2 as ammended with additional clauses defined in the + file LICENSE in the main source directory. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + the file LICENSE for additional details. */ @@ -445,8 +440,6 @@ static void job_monitor_watchdog(watchdog_t *self) Dmsg1(800, "job_monitor_watchdog %p called\n", self); - lock_jcr_chain(); - foreach_jcr(jcr) { bool cancel; @@ -454,7 +447,7 @@ static void job_monitor_watchdog(watchdog_t *self) Dmsg2(800, "Skipping JCR %p (%s) with JobId 0\n", jcr, jcr->Job); /* Keep reference counts correct */ - free_locked_jcr(jcr); + free_jcr(jcr); continue; } @@ -477,9 +470,8 @@ static void job_monitor_watchdog(watchdog_t *self) } /* Keep reference counts correct */ - free_locked_jcr(jcr); + free_jcr(jcr); } - unlock_jcr_chain(); } /* diff --git a/bacula/src/dird/jobq.c b/bacula/src/dird/jobq.c index ccc794e929..acbdba743f 100755 --- a/bacula/src/dird/jobq.c +++ b/bacula/src/dird/jobq.c @@ -229,7 +229,6 @@ int jobq_add(jobq_t *jq, JCR *jcr) sched_pkt = (wait_pkt *)malloc(sizeof(wait_pkt)); sched_pkt->jcr = jcr; sched_pkt->jq = jq; -// jcr->use_count--; /* release our use of jcr */ stat = pthread_create(&id, &jq->attr, sched_wait, (void *)sched_pkt); if (stat != 0) { /* thread not created */ berrno be; diff --git a/bacula/src/dird/pythondir.c b/bacula/src/dird/pythondir.c index 77245b07db..d7dbe335c8 100644 --- a/bacula/src/dird/pythondir.c +++ b/bacula/src/dird/pythondir.c @@ -7,24 +7,18 @@ * Version $Id$ * */ - /* Copyright (C) 2004-2005 Kern Sibbald This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. + modify it under the terms of the GNU General Public License + version 2 as ammended with additional clauses defined in the + file LICENSE in the main source directory. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + the file LICENSE for additional details. */ @@ -296,23 +290,20 @@ static PyObject *job_cancel(PyObject *self, PyObject *args) Dmsg0(000, "Parse tuple error in job_write\n"); return NULL; } - lock_jcr_chain(); foreach_jcr(jcr) { if (jcr->JobId == 0) { - free_locked_jcr(jcr); /* OK to free now cuz chain is locked */ + free_jcr(jcr); continue; } if (jcr->JobId == JobId) { found = true; - break; + break; } } if (!found) { - unlock_jcr_chain(); /* ***FIXME*** raise exception */ return NULL; } - unlock_jcr_chain(); PyEval_ReleaseLock(); UAContext *ua = new_ua_context(jcr); ua->batch = true; @@ -321,7 +312,7 @@ static PyObject *job_cancel(PyObject *self, PyObject *args) return NULL; } free_ua_context(ua); - free_locked_jcr(jcr); + free_jcr(jcr); PyEval_AcquireLock(); Py_INCREF(Py_None); return Py_None; diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index 77aedf191e..471315ed06 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -6,24 +6,18 @@ * * Version $Id$ */ - /* Copyright (C) 2000-2005 Kern Sibbald This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. + modify it under the terms of the GNU General Public License + version 2 as ammended with additional clauses defined in the + file LICENSE in the main source directory. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + the file LICENSE for additional details. */ @@ -399,33 +393,29 @@ static int cancel_cmd(UAContext *ua, const char *cmd) if (!jcr) { char buf[1000]; /* Count Jobs running */ - lock_jcr_chain(); foreach_jcr(jcr) { if (jcr->JobId == 0) { /* this is us */ - free_locked_jcr(jcr); + free_jcr(jcr); continue; } - free_locked_jcr(jcr); + free_jcr(jcr); njobs++; } - unlock_jcr_chain(); if (njobs == 0) { bsendmsg(ua, _("No Jobs running.\n")); return 1; } start_prompt(ua, _("Select Job:\n")); - lock_jcr_chain(); foreach_jcr(jcr) { if (jcr->JobId == 0) { /* this is us */ - free_locked_jcr(jcr); + free_jcr(jcr); continue; } bsnprintf(buf, sizeof(buf), "JobId=%d Job=%s", jcr->JobId, jcr->Job); add_prompt(ua, buf); - free_locked_jcr(jcr); + free_jcr(jcr); } - unlock_jcr_chain(); if (do_prompt(ua, _("Job"), _("Choose Job to cancel"), buf, sizeof(buf)) < 0) { return 1; @@ -1355,16 +1345,14 @@ int wait_cmd(UAContext *ua, const char *cmd) bmicrosleep(0, 200000); /* let job actually start */ for (bool running=true; running; ) { running = false; - lock_jcr_chain(); foreach_jcr(jcr) { if (jcr->JobId != 0) { running = true; - free_locked_jcr(jcr); + free_jcr(jcr); break; } - free_locked_jcr(jcr); + free_jcr(jcr); } - unlock_jcr_chain(); if (running) { bmicrosleep(1, 0); } diff --git a/bacula/src/dird/ua_status.c b/bacula/src/dird/ua_status.c index 9e97944a2c..499d0c8c73 100644 --- a/bacula/src/dird/ua_status.c +++ b/bacula/src/dird/ua_status.c @@ -6,27 +6,22 @@ * * Version $Id$ */ - /* - Copyright (C) 2000-2005 Kern Sibbald + Copyright (C) 2001-2005 Kern Sibbald This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. + modify it under the terms of the GNU General Public License + version 2 as ammended with additional clauses defined in the + file LICENSE in the main source directory. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + the file LICENSE for additional details. */ + #include "bacula.h" #include "dird.h" @@ -65,20 +60,18 @@ int qstatus_cmd(UAContext *ua, const char *cmd) if (strcasecmp(ua->argk[2], "current") == 0) { bsendmsg(ua, OKqstatus, ua->argk[2]); - lock_jcr_chain(); foreach_jcr(njcr) { - if (njcr->JobId != 0) { - bsendmsg(ua, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors); - } - free_locked_jcr(njcr); + if (njcr->JobId != 0) { + bsendmsg(ua, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors); + } + free_jcr(njcr); } - unlock_jcr_chain(); } else if (strcasecmp(ua->argk[2], "last") == 0) { bsendmsg(ua, OKqstatus, ua->argk[2]); if ((last_jobs) && (last_jobs->size() > 0)) { - job = (s_last_job*)last_jobs->last(); - bsendmsg(ua, DotStatusJob, job->JobId, job->JobStatus, job->Errors); + job = (s_last_job*)last_jobs->last(); + bsendmsg(ua, DotStatusJob, job->JobId, job->JobStatus, job->Errors); } } else { @@ -105,24 +98,24 @@ int status_cmd(UAContext *ua, const char *cmd) for (i=1; iargc; i++) { if (strcasecmp(ua->argk[i], _("all")) == 0) { - do_all_status(ua); - return 1; + do_all_status(ua); + return 1; } else if (strcasecmp(ua->argk[i], _("dir")) == 0 || strcasecmp(ua->argk[i], _("director")) == 0) { - do_director_status(ua); - return 1; + do_director_status(ua); + return 1; } else if (strcasecmp(ua->argk[i], _("client")) == 0) { - client = get_client_resource(ua); - if (client) { - do_client_status(ua, client); - } - return 1; + client = get_client_resource(ua); + if (client) { + do_client_status(ua, client); + } + return 1; } else { - store = get_storage_resource(ua, 0); - if (store) { - do_storage_status(ua, store); - } - return 1; + store = get_storage_resource(ua, 0); + if (store) { + do_storage_status(ua, store); + } + return 1; } } /* If no args, ask for status type */ @@ -136,30 +129,30 @@ int status_cmd(UAContext *ua, const char *cmd) add_prompt(ua, _("All")); Dmsg0(20, "do_prompt: select daemon\n"); if ((item=do_prompt(ua, "", _("Select daemon type for status"), prmt, sizeof(prmt))) < 0) { - return 1; + return 1; } Dmsg1(20, "item=%d\n", item); switch (item) { - case 0: /* Director */ - do_director_status(ua); - break; + case 0: /* Director */ + do_director_status(ua); + break; case 1: - store = select_storage_resource(ua); - if (store) { - do_storage_status(ua, store); - } - break; + store = select_storage_resource(ua); + if (store) { + do_storage_status(ua, store); + } + break; case 2: - client = select_client_resource(ua); - if (client) { - do_client_status(ua, client); - } - break; + client = select_client_resource(ua); + if (client) { + do_client_status(ua, client); + } + break; case 3: - do_all_status(ua); - break; + do_all_status(ua); + break; default: - break; + break; } } return 1; @@ -186,17 +179,17 @@ static void do_all_status(UAContext *ua) foreach_res(store, R_STORAGE) { found = false; if (!acl_access_ok(ua, Storage_ACL, store->hdr.name)) { - continue; + continue; } for (j=0; jaddress, store->address) == 0 && - unique_store[j]->SDport == store->SDport) { - found = true; - break; - } + if (strcmp(unique_store[j]->address, store->address) == 0 && + unique_store[j]->SDport == store->SDport) { + found = true; + break; + } } if (!found) { - unique_store[i++] = store; + unique_store[i++] = store; Dmsg2(40, "Stuffing: %s:%d\n", store->address, store->SDport); } } @@ -220,17 +213,17 @@ static void do_all_status(UAContext *ua) foreach_res(client, R_CLIENT) { found = false; if (!acl_access_ok(ua, Client_ACL, client->hdr.name)) { - continue; + continue; } for (j=0; jaddress, client->address) == 0 && - unique_client[j]->FDport == client->FDport) { - found = true; - break; - } + if (strcmp(unique_client[j]->address, client->address) == 0 && + unique_client[j]->FDport == client->FDport) { + found = true; + break; + } } if (!found) { - unique_client[i++] = client; + unique_client[i++] = client; Dmsg2(40, "Stuffing: %s:%d\n", client->address, client->FDport); } } @@ -249,17 +242,17 @@ static void do_director_status(UAContext *ua) char dt[MAX_TIME_LENGTH]; bsendmsg(ua, "%s Version: " VERSION " (" BDATE ") %s %s %s\n", my_name, - HOST_OS, DISTNAME, DISTVER); + HOST_OS, DISTNAME, DISTVER); bstrftime_nc(dt, sizeof(dt), daemon_start_time); bsendmsg(ua, _("Daemon started %s, %d Job%s run since started.\n"), dt, num_jobs_run, num_jobs_run == 1 ? "" : "s"); if (debug_level > 0) { char b1[35], b2[35], b3[35], b4[35]; bsendmsg(ua, _(" Heap: bytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"), - edit_uint64_with_commas(sm_bytes, b1), - edit_uint64_with_commas(sm_max_bytes, b2), - edit_uint64_with_commas(sm_buffers, b3), - edit_uint64_with_commas(sm_max_buffers, b4)); + edit_uint64_with_commas(sm_bytes, b1), + edit_uint64_with_commas(sm_max_bytes, b2), + edit_uint64_with_commas(sm_buffers, b3), + edit_uint64_with_commas(sm_max_buffers, b4)); } /* * List scheduled Jobs @@ -288,10 +281,10 @@ static void do_storage_status(UAContext *ua, STORE *store) store->hdr.name, store->address, store->SDport); if (!connect_to_storage_daemon(ua->jcr, 1, 15, 0)) { bsendmsg(ua, _("\nFailed to connect to Storage daemon %s.\n====\n"), - store->hdr.name); + store->hdr.name); if (ua->jcr->store_bsock) { - bnet_close(ua->jcr->store_bsock); - ua->jcr->store_bsock = NULL; + bnet_close(ua->jcr->store_bsock); + ua->jcr->store_bsock = NULL; } return; } @@ -326,10 +319,10 @@ static void do_client_status(UAContext *ua, CLIENT *client) client->hdr.name, client->address, client->FDport); if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) { bsendmsg(ua, _("Failed to connect to Client %s.\n====\n"), - client->hdr.name); + client->hdr.name); if (ua->jcr->file_bsock) { - bnet_close(ua->jcr->file_bsock); - ua->jcr->file_bsock = NULL; + bnet_close(ua->jcr->file_bsock); + ua->jcr->file_bsock = NULL; } return; } @@ -355,7 +348,7 @@ static void prt_runhdr(UAContext *ua) /* Scheduling packet */ struct sched_pkt { - dlink link; /* keep this as first item!!! */ + dlink link; /* keep this as first item!!! */ JOB *job; int level; int priority; @@ -377,11 +370,11 @@ static void prt_runtime(UAContext *ua, sched_pkt *sp) jcr->db = NULL; ok = complete_jcr_for_job(jcr, sp->job, sp->pool); if (jcr->db) { - close_db = true; /* new db opened, remember to close it */ + close_db = true; /* new db opened, remember to close it */ } if (ok) { mr.PoolId = jcr->PoolId; - ok = find_next_volume_for_append(jcr, &mr, 0); + ok = find_next_volume_for_append(jcr, &mr, 0); } if (!ok) { bstrncpy(mr.VolumeName, "*unknown*", sizeof(mr.VolumeName)); @@ -403,7 +396,7 @@ static void prt_runtime(UAContext *ua, sched_pkt *sp) if (close_db) { db_close_database(jcr, jcr->db); } - jcr->db = ua->db; /* restore ua db to jcr */ + jcr->db = ua->db; /* restore ua db to jcr */ } @@ -448,29 +441,29 @@ static void list_scheduled_jobs(UAContext *ua) LockRes(); foreach_res(job, R_JOB) { if (!acl_access_ok(ua, Job_ACL, job->hdr.name)) { - continue; + continue; } for (run=NULL; (run = find_next_run(run, job, runtime)); ) { - level = job->JobLevel; - if (run->level) { - level = run->level; - } - priority = job->Priority; - if (run->Priority) { - priority = run->Priority; - } - if (!hdr_printed) { - prt_runhdr(ua); - hdr_printed = true; - } - sp = (sched_pkt *)malloc(sizeof(sched_pkt)); - sp->job = job; - sp->level = level; - sp->priority = priority; - sp->runtime = runtime; - sp->pool = run->pool; - sched.binary_insert(sp, my_compare); - num_jobs++; + level = job->JobLevel; + if (run->level) { + level = run->level; + } + priority = job->Priority; + if (run->Priority) { + priority = run->Priority; + } + if (!hdr_printed) { + prt_runhdr(ua); + hdr_printed = true; + } + sp = (sched_pkt *)malloc(sizeof(sched_pkt)); + sp->job = job; + sp->level = level; + sp->priority = priority; + sp->runtime = runtime; + sp->pool = run->pool; + sched.binary_insert(sp, my_compare); + num_jobs++; } } /* end for loop over resources */ UnlockRes(); @@ -489,30 +482,28 @@ static void list_running_jobs(UAContext *ua) JCR *jcr; int njobs = 0; const char *msg; - char *emsg; /* edited message */ + char *emsg; /* edited message */ char dt[MAX_TIME_LENGTH]; char level[10]; bool pool_mem = false; Dmsg0(200, "enter list_run_jobs()\n"); bsendmsg(ua, _("\nRunning Jobs:\n")); - lock_jcr_chain(); foreach_jcr(jcr) { njobs++; - if (jcr->JobId == 0) { /* this is us */ - /* this is a console or other control job. We only show console - * jobs in the status output. - */ - if (jcr->JobType == JT_CONSOLE) { - bstrftime_nc(dt, sizeof(dt), jcr->start_time); + if (jcr->JobId == 0) { /* this is us */ + /* this is a console or other control job. We only show console + * jobs in the status output. + */ + if (jcr->JobType == JT_CONSOLE) { + bstrftime_nc(dt, sizeof(dt), jcr->start_time); bsendmsg(ua, _("Console connected at %s\n"), dt); - } - njobs--; + } + njobs--; } - free_locked_jcr(jcr); + free_jcr(jcr); } if (njobs == 0) { - unlock_jcr_chain(); /* Note the following message is used in regress -- don't change */ bsendmsg(ua, _("No Jobs running.\n====\n")); Dmsg0(200, "leave list_run_jobs()\n"); @@ -523,128 +514,127 @@ static void list_running_jobs(UAContext *ua) bsendmsg(ua, _("======================================================================\n")); foreach_jcr(jcr) { if (jcr->JobId == 0 || !acl_access_ok(ua, Job_ACL, jcr->job->hdr.name)) { - free_locked_jcr(jcr); - continue; + free_jcr(jcr); + continue; } njobs++; switch (jcr->JobStatus) { case JS_Created: msg = _("is waiting execution"); - break; + break; case JS_Running: msg = _("is running"); - break; + break; case JS_Blocked: msg = _("is blocked"); - break; + break; case JS_Terminated: msg = _("has terminated"); - break; + break; case JS_ErrorTerminated: msg = _("has erred"); - break; + break; case JS_Error: msg = _("has errors"); - break; + break; case JS_FatalError: msg = _("has a fatal error"); - break; + break; case JS_Differences: msg = _("has verify differences"); - break; + break; case JS_Canceled: msg = _("has been canceled"); - break; + break; case JS_WaitFD: - emsg = (char *) get_pool_memory(PM_FNAME); + emsg = (char *) get_pool_memory(PM_FNAME); Mmsg(emsg, _("is waiting on Client %s"), jcr->client->hdr.name); - pool_mem = true; - msg = emsg; - break; + pool_mem = true; + msg = emsg; + break; case JS_WaitSD: - emsg = (char *) get_pool_memory(PM_FNAME); + emsg = (char *) get_pool_memory(PM_FNAME); Mmsg(emsg, _("is waiting on Storage %s"), jcr->store->hdr.name); - pool_mem = true; - msg = emsg; - break; + pool_mem = true; + msg = emsg; + break; case JS_WaitStoreRes: msg = _("is waiting on max Storage jobs"); - break; + break; case JS_WaitClientRes: msg = _("is waiting on max Client jobs"); - break; + break; case JS_WaitJobRes: msg = _("is waiting on max Job jobs"); - break; + break; case JS_WaitMaxJobs: msg = _("is waiting on max total jobs"); - break; + break; case JS_WaitStartTime: msg = _("is waiting for its start time"); - break; + break; case JS_WaitPriority: msg = _("is waiting for higher priority jobs to finish"); - break; + break; default: - emsg = (char *) get_pool_memory(PM_FNAME); + emsg = (char *) get_pool_memory(PM_FNAME); Mmsg(emsg, _("is in unknown state %c"), jcr->JobStatus); - pool_mem = true; - msg = emsg; - break; + pool_mem = true; + msg = emsg; + break; } /* * Now report Storage daemon status code */ switch (jcr->SDJobStatus) { case JS_WaitMount: - if (pool_mem) { - free_pool_memory(emsg); - pool_mem = false; - } + if (pool_mem) { + free_pool_memory(emsg); + pool_mem = false; + } msg = _("is waiting for a mount request"); - break; + break; case JS_WaitMedia: - if (pool_mem) { - free_pool_memory(emsg); - pool_mem = false; - } + if (pool_mem) { + free_pool_memory(emsg); + pool_mem = false; + } msg = _("is waiting for an appendable Volume"); - break; + break; case JS_WaitFD: - if (!pool_mem) { - emsg = (char *) get_pool_memory(PM_FNAME); - pool_mem = true; - } + if (!pool_mem) { + emsg = (char *) get_pool_memory(PM_FNAME); + pool_mem = true; + } Mmsg(emsg, _("is waiting for Client %s to connect to Storage %s"), - jcr->client->hdr.name, jcr->store->hdr.name); - msg = emsg; - break; + jcr->client->hdr.name, jcr->store->hdr.name); + msg = emsg; + break; } switch (jcr->JobType) { case JT_ADMIN: case JT_RESTORE: bstrncpy(level, " ", sizeof(level)); - break; + break; default: - bstrncpy(level, level_to_str(jcr->JobLevel), sizeof(level)); - level[7] = 0; - break; + bstrncpy(level, level_to_str(jcr->JobLevel), sizeof(level)); + level[7] = 0; + break; } bsendmsg(ua, _("%6d %-6s %-20s %s\n"), - jcr->JobId, - level, - jcr->Job, - msg); + jcr->JobId, + level, + jcr->Job, + msg); if (pool_mem) { - free_pool_memory(emsg); - pool_mem = false; + free_pool_memory(emsg); + pool_mem = false; } - free_locked_jcr(jcr); + free_jcr(jcr); } - unlock_jcr_chain(); bsendmsg(ua, "====\n"); Dmsg0(200, "leave list_run_jobs()\n"); } @@ -672,12 +662,12 @@ static void list_terminated_jobs(UAContext *ua) char *p; for (int i=0; i<3; i++) { if ((p=strrchr(JobName, '.')) != NULL) { - *p = 0; - } + *p = 0; + } } if (!acl_access_ok(ua, Job_ACL, JobName)) { - continue; + continue; } bstrftime_nc(dt, sizeof(dt), je->end_time); @@ -685,40 +675,40 @@ static void list_terminated_jobs(UAContext *ua) case JT_ADMIN: case JT_RESTORE: bstrncpy(level, " ", sizeof(level)); - break; + break; default: - bstrncpy(level, level_to_str(je->JobLevel), sizeof(level)); - level[4] = 0; - break; + bstrncpy(level, level_to_str(je->JobLevel), sizeof(level)); + level[4] = 0; + break; } switch (je->JobStatus) { case JS_Created: termstat = "Created"; - break; + break; case JS_FatalError: case JS_ErrorTerminated: termstat = "Error"; - break; + break; case JS_Differences: termstat = "Diffs"; - break; + break; case JS_Canceled: termstat = "Cancel"; - break; + break; case JS_Terminated: termstat = "OK"; - break; + break; default: termstat = "Other"; - break; + break; } bsendmsg(ua, _("%6d %-6s %8s %14s %-7s %-8s %s\n"), - je->JobId, - level, - edit_uint64_with_commas(je->JobFiles, b1), - edit_uint64_with_commas(je->JobBytes, b2), - termstat, - dt, JobName); + je->JobId, + level, + edit_uint64_with_commas(je->JobFiles, b1), + edit_uint64_with_commas(je->JobBytes, b2), + termstat, + dt, JobName); } bsendmsg(ua, "\n"); unlock_last_jobs_list(); diff --git a/bacula/src/filed/status.c b/bacula/src/filed/status.c index 7fa0829aa0..398ad67319 100755 --- a/bacula/src/filed/status.c +++ b/bacula/src/filed/status.c @@ -63,16 +63,16 @@ static void do_status(void sendit(const char *msg, int len, void *sarg), void *a msg = (char *)get_pool_memory(PM_MESSAGE); found = 0; len = Mmsg(msg, "%s Version: " VERSION " (" BDATE ") %s %s %s\n", my_name, - HOST_OS, DISTNAME, DISTVER); + HOST_OS, DISTNAME, DISTVER); sendit(msg, len, arg); bstrftime_nc(dt, sizeof(dt), daemon_start_time); len = Mmsg(msg, _("Daemon started %s, %d Job%s run since started.\n"), - dt, num_jobs_run, num_jobs_run == 1 ? "" : "s"); + dt, num_jobs_run, num_jobs_run == 1 ? "" : "s"); sendit(msg, len, arg); #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32) if (/*debug_level > 0*/ true) { if (!privs) { - privs = enable_backup_privileges(NULL, 1); + privs = enable_backup_privileges(NULL, 1); } len = Mmsg(msg, _(" Priv 0x%x\n APIs=%sOPT,%sATP,%sLPV,%sCFA,%sCFW,\n" @@ -80,12 +80,12 @@ static void do_status(void sendit(const char *msg, int len, void *sarg), void *a " %sWC2MB,%sMB2WC,%sFFFA,%sFFFW,%sFNFA,%sFNFW,%sSCDA,%sSCDW,\n" " %sGCDA,%sGCDW\n"), privs, - p_OpenProcessToken?"":"!", - p_AdjustTokenPrivileges?"":"!", - p_LookupPrivilegeValue?"":"!", + p_OpenProcessToken?"":"!", + p_AdjustTokenPrivileges?"":"!", + p_LookupPrivilegeValue?"":"!", p_CreateFileA?"":"!", - p_CreateFileW?"":"!", + p_CreateFileW?"":"!", p_wunlink?"":"!", p_wmkdir?"":"!", @@ -95,13 +95,13 @@ static void do_status(void sendit(const char *msg, int len, void *sarg), void *a p_GetFileAttributesW?"":"!", p_GetFileAttributesExA?"":"!", - p_GetFileAttributesExW?"":"!", + p_GetFileAttributesExW?"":"!", p_SetFileAttributesA?"":"!", - p_SetFileAttributesW?"":"!", - p_BackupRead?"":"!", - p_BackupWrite?"":"!", - p_SetProcessShutdownParameters?"":"!", + p_SetFileAttributesW?"":"!", + p_BackupRead?"":"!", + p_BackupWrite?"":"!", + p_SetProcessShutdownParameters?"":"!", p_WideCharToMultiByte?"":"!", p_MultiByteToWideChar?"":"!", @@ -122,13 +122,13 @@ static void do_status(void sendit(const char *msg, int len, void *sarg), void *a #endif if (debug_level > 0) { len = Mmsg(msg, _(" Heap: bytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"), - edit_uint64_with_commas(sm_bytes, b1), - edit_uint64_with_commas(sm_max_bytes, b2), - edit_uint64_with_commas(sm_buffers, b3), - edit_uint64_with_commas(sm_max_buffers, b4)); + edit_uint64_with_commas(sm_bytes, b1), + edit_uint64_with_commas(sm_max_bytes, b2), + edit_uint64_with_commas(sm_buffers, b3), + edit_uint64_with_commas(sm_max_buffers, b4)); sendit(msg, len, arg); len = Mmsg(msg, _(" Sizeof: off_t=%d size_t=%d debug=%d trace=%d\n"), - sizeof(off_t), sizeof(size_t), debug_level, get_trace()); + sizeof(off_t), sizeof(size_t), debug_level, get_trace()); sendit(msg, len, arg); } @@ -140,55 +140,53 @@ static void do_status(void sendit(const char *msg, int len, void *sarg), void *a Dmsg0(1000, "Begin status jcr loop.\n"); len = Mmsg(msg, _("Running Jobs:\n")); sendit(msg, len, arg); - lock_jcr_chain(); foreach_jcr(njcr) { bstrftime_nc(dt, sizeof(dt), njcr->start_time); if (njcr->JobId == 0) { - len = Mmsg(msg, _("Director connected at: %s\n"), dt); + len = Mmsg(msg, _("Director connected at: %s\n"), dt); } else { - len = Mmsg(msg, _("JobId %d Job %s is running.\n"), - njcr->JobId, njcr->Job); - sendit(msg, len, arg); - len = Mmsg(msg, _(" %s Job started: %s\n"), - job_type_to_str(njcr->JobType), dt); + len = Mmsg(msg, _("JobId %d Job %s is running.\n"), + njcr->JobId, njcr->Job); + sendit(msg, len, arg); + len = Mmsg(msg, _(" %s Job started: %s\n"), + job_type_to_str(njcr->JobType), dt); } sendit(msg, len, arg); if (njcr->JobId == 0) { - free_locked_jcr(njcr); - continue; + free_jcr(njcr); + continue; } sec = time(NULL) - njcr->start_time; if (sec <= 0) { - sec = 1; + sec = 1; } bps = (int)(njcr->JobBytes / sec); len = Mmsg(msg, _(" Files=%s Bytes=%s Bytes/sec=%s\n"), - edit_uint64_with_commas(njcr->JobFiles, b1), - edit_uint64_with_commas(njcr->JobBytes, b2), - edit_uint64_with_commas(bps, b3)); + edit_uint64_with_commas(njcr->JobFiles, b1), + edit_uint64_with_commas(njcr->JobBytes, b2), + edit_uint64_with_commas(bps, b3)); sendit(msg, len, arg); len = Mmsg(msg, _(" Files Examined=%s\n"), - edit_uint64_with_commas(njcr->num_files_examined, b1)); + edit_uint64_with_commas(njcr->num_files_examined, b1)); sendit(msg, len, arg); if (njcr->JobFiles > 0) { - P(njcr->mutex); - len = Mmsg(msg, _(" Processing file: %s\n"), njcr->last_fname); - V(njcr->mutex); - sendit(msg, len, arg); + P(njcr->mutex); + len = Mmsg(msg, _(" Processing file: %s\n"), njcr->last_fname); + V(njcr->mutex); + sendit(msg, len, arg); } found = 1; if (njcr->store_bsock) { - len = Mmsg(msg, " SDReadSeqNo=%" lld " fd=%d\n", - njcr->store_bsock->read_seqno, njcr->store_bsock->fd); - sendit(msg, len, arg); + len = Mmsg(msg, " SDReadSeqNo=%" lld " fd=%d\n", + njcr->store_bsock->read_seqno, njcr->store_bsock->fd); + sendit(msg, len, arg); } else { - len = Mmsg(msg, _(" SDSocket closed.\n")); - sendit(msg, len, arg); + len = Mmsg(msg, _(" SDSocket closed.\n")); + sendit(msg, len, arg); } - free_locked_jcr(njcr); + free_jcr(njcr); } - unlock_jcr_chain(); Dmsg0(1000, "Begin status jcr loop.\n"); if (!found) { len = Mmsg(msg, _("No Jobs running.\n")); @@ -228,49 +226,49 @@ static void list_terminated_jobs(void sendit(const char *msg, int len, void *sa switch (je->JobType) { case JT_ADMIN: case JT_RESTORE: - bstrncpy(level, " ", sizeof(level)); - break; + bstrncpy(level, " ", sizeof(level)); + break; default: - bstrncpy(level, level_to_str(je->JobLevel), sizeof(level)); - level[4] = 0; - break; + bstrncpy(level, level_to_str(je->JobLevel), sizeof(level)); + level[4] = 0; + break; } switch (je->JobStatus) { case JS_Created: - termstat = "Created"; - break; + termstat = "Created"; + break; case JS_FatalError: case JS_ErrorTerminated: - termstat = "Error"; - break; + termstat = "Error"; + break; case JS_Differences: - termstat = "Diffs"; - break; + termstat = "Diffs"; + break; case JS_Canceled: - termstat = "Cancel"; - break; + termstat = "Cancel"; + break; case JS_Terminated: - termstat = "OK"; - break; + termstat = "OK"; + break; default: - termstat = "Other"; - break; + termstat = "Other"; + break; } bstrncpy(JobName, je->Job, sizeof(JobName)); /* There are three periods after the Job name */ char *p; for (int i=0; i<3; i++) { - if ((p=strrchr(JobName, '.')) != NULL) { - *p = 0; - } + if ((p=strrchr(JobName, '.')) != NULL) { + *p = 0; + } } bsnprintf(buf, sizeof(buf), _("%6d %-6s %8s %14s %-7s %-8s %s\n"), - je->JobId, - level, - edit_uint64_with_commas(je->JobFiles, b1), - edit_uint64_with_commas(je->JobBytes, b2), - termstat, - dt, JobName); + je->JobId, + level, + edit_uint64_with_commas(je->JobFiles, b1), + edit_uint64_with_commas(je->JobBytes, b2), + termstat, + dt, JobName); sendit(buf, strlen(buf), arg); } sendit("====\n", 5, arg); @@ -329,20 +327,18 @@ int qstatus_cmd(JCR *jcr) if (strcmp(time, "current") == 0) { bnet_fsend(dir, OKqstatus, time); - lock_jcr_chain(); foreach_jcr(njcr) { - if (njcr->JobId != 0) { - bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors); - } - free_locked_jcr(njcr); + if (njcr->JobId != 0) { + bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors); + } + free_jcr(njcr); } - unlock_jcr_chain(); } else if (strcmp(time, "last") == 0) { bnet_fsend(dir, OKqstatus, time); if ((last_jobs) && (last_jobs->size() > 0)) { - job = (s_last_job*)last_jobs->last(); - bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors); + job = (s_last_job*)last_jobs->last(); + bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors); } } else { @@ -426,7 +422,7 @@ static void win32_sendit(const char *msg, int len, void *marg) if (len > 0 && msg[len-1] == '\n') { // when compiling with visual studio some strings are read-only - // and cause access violations. So we creat a tmp copy. + // and cause access violations. So we creat a tmp copy. char *_msg = (char *)alloca(len); bstrncpy(_msg, msg, len); msg = _msg; @@ -453,23 +449,21 @@ char *bac_status(char *buf, int buf_len) JCR *njcr; const char *termstat = _("Bacula Idle"); struct s_last_job *job; - int stat = 0; /* Idle */ + int stat = 0; /* Idle */ if (!last_jobs) { goto done; } Dmsg0(1000, "Begin bac_status jcr loop.\n"); - lock_jcr_chain(); foreach_jcr(njcr) { if (njcr->JobId != 0) { - stat = JS_Running; - termstat = _("Bacula Running"); - free_locked_jcr(njcr); - break; + stat = JS_Running; + termstat = _("Bacula Running"); + free_jcr(njcr); + break; } - free_locked_jcr(njcr); + free_jcr(njcr); } - unlock_jcr_chain(); if (stat != 0) { goto done; } @@ -478,17 +472,17 @@ char *bac_status(char *buf, int buf_len) stat = job->JobStatus; switch (job->JobStatus) { case JS_Canceled: - termstat = _("Last Job Canceled"); - break; + termstat = _("Last Job Canceled"); + break; case JS_ErrorTerminated: case JS_FatalError: - termstat = _("Last Job Failed"); - break; + termstat = _("Last Job Failed"); + break; default: - if (job->Errors) { - termstat = _("Last Job had Warnings"); - } - break; + if (job->Errors) { + termstat = _("Last Job had Warnings"); + } + break; } } Dmsg0(1000, "End bac_status jcr loop.\n"); diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index 9fc06e81d5..ba7fd9cea4 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -86,16 +86,19 @@ #define SD_READ 0 /* Forward referenced structures */ -struct JCR; +class JCR; struct FF_PKT; typedef void (JCR_free_HANDLER)(JCR *jcr); /* Job Control Record (JCR) */ -struct JCR { +class JCR { +public: + void inc_use_count(void) {P(mutex); use_count++; V(mutex); }; + void dec_use_count(void) {P(mutex); use_count--; V(mutex); }; + /* Global part of JCR common to all daemons */ - JCR *next; - JCR *prev; + dlink link; /* JCR chain link */ volatile int use_count; /* use count */ pthread_t my_thread_id; /* id of thread controlling jcr */ pthread_mutex_t mutex; /* jcr mutex */ @@ -306,7 +309,6 @@ extern dlist *last_jobs; /* The following routines are found in lib/jcr.c */ extern bool init_jcr_subsystem(void); extern JCR *new_jcr(int size, JCR_free_HANDLER *daemon_free_jcr); -extern void free_locked_jcr(JCR *jcr); extern JCR *get_jcr_by_id(uint32_t JobId); extern JCR *get_jcr_by_session(uint32_t SessionId, uint32_t SessionTime); extern JCR *get_jcr_by_partial_name(char *Job); diff --git a/bacula/src/lib/dlist.h b/bacula/src/lib/dlist.h index 09eccfbb68..7dd1b17562 100644 --- a/bacula/src/lib/dlist.h +++ b/bacula/src/lib/dlist.h @@ -2,7 +2,7 @@ * Version $Id$ */ /* - Copyright (C) 2003-2005 Kern Sibbald + Copyright (C) 2004-2005 Kern Sibbald This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -41,7 +41,7 @@ #ifdef the_old_way #define foreach_dlist(var, list) \ - for((var)=NULL; (((void *)(var))=(list)->next(var)); ) + for((var)=NULL; (((void *)(var))=(list)->next(var)); ) #endif @@ -68,7 +68,7 @@ public: void binary_insert(void *item, int compare(void *item1, void *item2)); void remove(void *item); bool empty() const; - int size() const; + int size() const; void *next(const void *item) const; void *prev(const void *item) const; void destroy(); diff --git a/bacula/src/lib/jcr.c b/bacula/src/lib/jcr.c index 91ad72db91..964d5c3e27 100755 --- a/bacula/src/lib/jcr.c +++ b/bacula/src/lib/jcr.c @@ -1,5 +1,6 @@ /* - * Manipulation routines for Job Control Records + * Manipulation routines for Job Control Records and + * handling of last_jobs_list. * * Kern E. Sibbald, December 2000 * @@ -7,24 +8,32 @@ * * These routines are thread safe. * + * The job list routines were re-written in May 2005 to + * eliminate the global lock while traversing the list, and + * to use the dlist subroutines. The locking is now done + * on the list each time the list is modified or traversed. + * That is it is "micro-locked" rather than globally locked. + * The result is that there is one lock/unlock for each entry + * in the list while traversing it rather than a single lock + * at the beginning of a traversal and one at the end. This + * incurs slightly more overhead, but effectively eliminates + * the possibilty of race conditions. In addition, with the + * exception of the global locking of the list during the + * re-reading of the config file, no recursion is needed. + * */ /* Copyright (C) 2000-2005 Kern Sibbald This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. + modify it under the terms of the GNU General Public License + version 2 as ammended with additional clauses defined in the + file LICENSE in the main source directory. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + the file LICENSE for additional details. */ @@ -42,13 +51,14 @@ static void jcr_timeout_check(watchdog_t *self); int num_jobs_run; dlist *last_jobs = NULL; const int max_last_jobs = 10; - -JCR *jobs = NULL; /* pointer to JCR chain */ + +static dlist *jcrs = NULL; /* JCR chain */ static brwlock_t lock; /* lock for last jobs and JCR chain */ void init_last_jobs_list() { int errstat; + JCR *jcr; struct s_last_job *job_entry = NULL; if (!last_jobs) { last_jobs = New(dlist(job_entry, &job_entry->link)); @@ -57,7 +67,9 @@ void init_last_jobs_list() strerror(errstat)); } } - + if (!jcrs) { + jcrs = New(dlist(jcr, &jcr->link)); + } } void term_last_jobs_list() @@ -71,6 +83,7 @@ void term_last_jobs_list() delete last_jobs; last_jobs = NULL; rwl_destroy(&lock); + delete jcrs; } } @@ -216,13 +229,12 @@ JCR *new_jcr(int size, JCR_free_HANDLER *daemon_free_jcr) sigaction(TIMEOUT_SIGNAL, &sigtimer, NULL); lock_jcr_chain(); - jcr->prev = NULL; - jcr->next = jobs; - if (jobs) { - jobs->prev = jcr; + if (!jcrs) { + jcrs = New(dlist(jcr, &jcr->link)); } - jobs = jcr; + jcrs->append(jcr); unlock_jcr_chain(); + return jcr; } @@ -238,14 +250,7 @@ static void remove_jcr(JCR *jcr) if (!jcr) { Emsg0(M_ABORT, 0, "NULL jcr.\n"); } - if (!jcr->prev) { /* if no prev */ - jobs = jcr->next; /* set new head */ - } else { - jcr->prev->next = jcr->next; /* update prev */ - } - if (jcr->next) { - jcr->next->prev = jcr->prev; - } + jcrs->remove(jcr); Dmsg0(3400, "Leave remove_jcr\n"); } @@ -360,7 +365,7 @@ void free_jcr(JCR *jcr) dequeue_messages(jcr); lock_jcr_chain(); - jcr->use_count--; /* decrement use count */ + jcr->dec_use_count(); /* decrement use count */ if (jcr->use_count < 0) { Emsg2(M_ERROR, 0, _("JCR use_count=%d JobId=%d\n"), jcr->use_count, jcr->JobId); @@ -387,24 +392,6 @@ void free_jcr(JCR *jcr) } -/* - * Global routine to free a jcr - * JCR chain is already locked - */ -void free_locked_jcr(JCR *jcr) -{ - jcr->use_count--; /* decrement use count */ - Dmsg2(3400, "Dec free_locked_jcr 0x%x use_count=%d\n", jcr, jcr->use_count); - if (jcr->use_count > 0) { /* if in use */ - return; - } - remove_jcr(jcr); - jcr->daemon_free_jcr(jcr); /* call daemon free routine */ - free_common_jcr(jcr); -} - - - /* * Given a JobId, find the JCR * Returns: jcr on success @@ -415,11 +402,9 @@ JCR *get_jcr_by_id(uint32_t JobId) JCR *jcr; lock_jcr_chain(); /* lock chain */ - for (jcr = jobs; jcr; jcr=jcr->next) { + foreach_dlist(jcr, jcrs) { if (jcr->JobId == JobId) { - P(jcr->mutex); - jcr->use_count++; - V(jcr->mutex); + jcr->inc_use_count(); Dmsg2(3400, "Inc get_jcr 0x%x use_count=%d\n", jcr, jcr->use_count); break; } @@ -438,12 +423,10 @@ JCR *get_jcr_by_session(uint32_t SessionId, uint32_t SessionTime) JCR *jcr; lock_jcr_chain(); - for (jcr = jobs; jcr; jcr=jcr->next) { + foreach_dlist(jcr, jcrs) { if (jcr->VolSessionId == SessionId && jcr->VolSessionTime == SessionTime) { - P(jcr->mutex); - jcr->use_count++; - V(jcr->mutex); + jcr->inc_use_count(); Dmsg2(3400, "Inc get_jcr 0x%x use_count=%d\n", jcr, jcr->use_count); break; } @@ -470,11 +453,9 @@ JCR *get_jcr_by_partial_name(char *Job) } lock_jcr_chain(); len = strlen(Job); - for (jcr = jobs; jcr; jcr=jcr->next) { + foreach_dlist(jcr, jcrs) { if (strncmp(Job, jcr->Job, len) == 0) { - P(jcr->mutex); - jcr->use_count++; - V(jcr->mutex); + jcr->inc_use_count(); Dmsg2(3400, "Inc get_jcr 0x%x use_count=%d\n", jcr, jcr->use_count); break; } @@ -498,11 +479,9 @@ JCR *get_jcr_by_full_name(char *Job) return NULL; } lock_jcr_chain(); - for (jcr = jobs; jcr; jcr=jcr->next) { + foreach_dlist(jcr, jcrs) { if (strcmp(jcr->Job, Job) == 0) { - P(jcr->mutex); - jcr->use_count++; - V(jcr->mutex); + jcr->inc_use_count(); Dmsg2(3400, "Inc get_jcr 0x%x use_count=%d\n", jcr, jcr->use_count); break; } @@ -578,17 +557,13 @@ JCR *get_next_jcr(JCR *prev_jcr) { JCR *jcr; - if (prev_jcr == NULL) { - jcr = jobs; - } else { - jcr = prev_jcr->next; - } + lock_jcr_chain(); + jcr = (JCR *)jcrs->next(prev_jcr); if (jcr) { - P(jcr->mutex); - jcr->use_count++; - V(jcr->mutex); + jcr->inc_use_count(); Dmsg2(3400, "Inc get_next_jcr 0x%x use_count=%d\n", jcr, jcr->use_count); } + unlock_jcr_chain(); return jcr; } @@ -617,10 +592,9 @@ static void jcr_timeout_check(watchdog_t *self) /* Walk through all JCRs checking if any one is * blocked for more than specified max time. */ - lock_jcr_chain(); foreach_jcr(jcr) { - free_locked_jcr(jcr); /* OK to free now cuz chain is locked */ if (jcr->JobId == 0) { + free_jcr(jcr); continue; } fd = jcr->store_bsock; @@ -659,9 +633,8 @@ static void jcr_timeout_check(watchdog_t *self) pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL); } } - + free_jcr(jcr); } - unlock_jcr_chain(); Dmsg0(3400, "Finished JCR timeout checks\n"); } diff --git a/bacula/src/lib/watchdog.c b/bacula/src/lib/watchdog.c index d6c65dd6d7..985856dc39 100755 --- a/bacula/src/lib/watchdog.c +++ b/bacula/src/lib/watchdog.c @@ -30,7 +30,7 @@ #include "jcr.h" /* Exported globals */ -time_t watchdog_time = 0; /* this has granularity of SLEEP_TIME */ +time_t watchdog_time = 0; /* this has granularity of SLEEP_TIME */ time_t watchdog_sleep_time = 60; /* examine things every 60 seconds */ /* Locals */ @@ -46,7 +46,7 @@ static void wd_unlock(); /* Static globals */ static bool quit = false;; static bool wd_is_init = false; -static brwlock_t lock; /* watchdog lock */ +static brwlock_t lock; /* watchdog lock */ static pthread_t wd_tid; static dlist *wd_queue; @@ -56,7 +56,7 @@ static dlist *wd_inactive; * Start watchdog thread * * Returns: 0 on success - * errno on failure + * errno on failure */ int start_watchdog(void) { @@ -72,7 +72,7 @@ int start_watchdog(void) if ((errstat=rwl_init(&lock)) != 0) { Emsg1(M_ABORT, 0, _("Unable to initialize watchdog lock. ERR=%s\n"), - strerror(errstat)); + strerror(errstat)); } wd_queue = New(dlist(dummy, &dummy->link)); wd_inactive = New(dlist(dummy, &dummy->link)); @@ -99,7 +99,7 @@ static void ping_watchdog() * Terminate the watchdog thread * * Returns: 0 on success - * errno on failure + * errno on failure */ int stop_watchdog(void) { @@ -110,7 +110,7 @@ int stop_watchdog(void) return 0; } - quit = true; /* notify watchdog thread to stop */ + quit = true; /* notify watchdog thread to stop */ wd_is_init = false; ping_watchdog(); @@ -121,7 +121,7 @@ int stop_watchdog(void) wd_queue->remove(item); p = (watchdog_t *)item; if (p->destructor != NULL) { - p->destructor(p); + p->destructor(p); } free(p); } @@ -133,7 +133,7 @@ int stop_watchdog(void) wd_inactive->remove(item); p = (watchdog_t *)item; if (p->destructor != NULL) { - p->destructor(p); + p->destructor(p); } free(p); } @@ -199,19 +199,19 @@ bool unregister_watchdog(watchdog_t *wd) wd_lock(); foreach_dlist(p, wd_queue) { if (wd == p) { - wd_queue->remove(wd); + wd_queue->remove(wd); Dmsg1(800, "Unregistered watchdog %p\n", wd); - ok = true; - goto get_out; + ok = true; + goto get_out; } } foreach_dlist(p, wd_inactive) { if (wd == p) { - wd_inactive->remove(wd); + wd_inactive->remove(wd); Dmsg1(800, "Unregistered inactive watchdog %p\n", wd); - ok = true; - goto get_out; + ok = true; + goto get_out; } } @@ -242,6 +242,10 @@ extern "C" void *watchdog_thread(void *arg) watchdog_t *p; /* + * + * NOTE. lock_jcr_chain removed, but the message below + * was left until we are sure there are no deadlocks. + * * We lock the jcr chain here because a good number of the * callback routines lock the jcr chain. We need to lock * it here *before* the watchdog lock because the SD message @@ -250,32 +254,30 @@ extern "C" void *watchdog_thread(void *arg) * lock in the same order, we get a deadlock -- each holds * the other's needed lock. */ - lock_jcr_chain(); wd_lock(); walk_list: watchdog_time = time(NULL); next_time = watchdog_time + watchdog_sleep_time; foreach_dlist(p, wd_queue) { - if (p->next_fire <= watchdog_time) { - /* Run the callback */ - p->callback(p); + if (p->next_fire <= watchdog_time) { + /* Run the callback */ + p->callback(p); /* Reschedule (or move to inactive list if it's a one-shot timer) */ - if (p->one_shot) { - wd_queue->remove(p); - wd_inactive->append(p); - goto walk_list; - } else { - p->next_fire = watchdog_time + p->interval; - } - } - if (p->next_fire < next_time) { - next_time = p->next_fire; - } + if (p->one_shot) { + wd_queue->remove(p); + wd_inactive->append(p); + goto walk_list; + } else { + p->next_fire = watchdog_time + p->interval; + } + } + if (p->next_fire < next_time) { + next_time = p->next_fire; + } } wd_unlock(); - unlock_jcr_chain(); /* * Wait sleep time or until someone wakes us @@ -284,8 +286,8 @@ walk_list: timeout.tv_nsec = tv.tv_usec * 1000; timeout.tv_sec = tv.tv_sec + next_time - time(NULL); while (timeout.tv_nsec >= 1000000000) { - timeout.tv_nsec -= 1000000000; - timeout.tv_sec++; + timeout.tv_nsec -= 1000000000; + timeout.tv_sec++; } Dmsg1(1900, "pthread_cond_timedwait %d\n", timeout.tv_sec - tv.tv_sec); @@ -309,7 +311,7 @@ static void wd_lock() int errstat; if ((errstat=rwl_writelock(&lock)) != 0) { Emsg1(M_ABORT, 0, "rwl_writelock failure. ERR=%s\n", - strerror(errstat)); + strerror(errstat)); } } @@ -323,6 +325,6 @@ static void wd_unlock() int errstat; if ((errstat=rwl_writeunlock(&lock)) != 0) { Emsg1(M_ABORT, 0, "rwl_writeunlock failure. ERR=%s\n", - strerror(errstat)); + strerror(errstat)); } } diff --git a/bacula/src/stored/askdir.c b/bacula/src/stored/askdir.c index 0fb5fcfa16..d449634709 100644 --- a/bacula/src/stored/askdir.c +++ b/bacula/src/stored/askdir.c @@ -255,22 +255,20 @@ bool dir_find_next_appendable_volume(DCR *dcr) * This would be better done by walking through * all the devices. */ - lock_jcr_chain(); foreach_jcr(njcr) { if (jcr == njcr) { - free_locked_jcr(njcr); + free_jcr(njcr); continue; /* us */ } Dmsg2(300, "Compare to JobId=%d using Vol=%s\n", njcr->JobId, njcr->dcr->VolumeName); if (njcr->dcr && strcmp(dcr->VolumeName, njcr->dcr->VolumeName) == 0) { found = true; Dmsg1(400, "Vol in use by JobId=%u\n", njcr->JobId); - free_locked_jcr(njcr); + free_jcr(njcr); break; } - free_locked_jcr(njcr); + free_jcr(njcr); } - unlock_jcr_chain(); if (!found) { Dmsg0(400, "dir_find_next_appendable_volume return true\n"); return true; /* Got good Volume */ diff --git a/bacula/src/stored/status.c b/bacula/src/stored/status.c index dc18ca4290..0e281357ac 100644 --- a/bacula/src/stored/status.c +++ b/bacula/src/stored/status.c @@ -252,7 +252,6 @@ static void list_running_jobs(BSOCK *user) char b1[30], b2[30], b3[30]; bnet_fsend(user, _("\nRunning Jobs:\n")); - lock_jcr_chain(); foreach_jcr(jcr) { if (jcr->JobStatus == JS_WaitFD) { bnet_fsend(user, _("%s Job %s waiting for Client connection.\n"), @@ -295,9 +294,8 @@ static void list_running_jobs(BSOCK *user) } #endif } - free_locked_jcr(jcr); + free_jcr(jcr); } - unlock_jcr_chain(); if (!found) { bnet_fsend(user, _("No Jobs running.\n")); } @@ -461,14 +459,12 @@ bool qstatus_cmd(JCR *jcr) if (strcmp(time.c_str(), "current") == 0) { bnet_fsend(dir, OKqstatus, time.c_str()); - lock_jcr_chain(); foreach_jcr(njcr) { if (njcr->JobId != 0) { bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors); } - free_locked_jcr(njcr); + free_jcr(njcr); } - unlock_jcr_chain(); } else if (strcmp(time.c_str(), "last") == 0) { bnet_fsend(dir, OKqstatus, time.c_str()); diff --git a/bacula/src/stored/stored.c b/bacula/src/stored/stored.c index 50bb025aa1..8b8a76f7cc 100644 --- a/bacula/src/stored/stored.c +++ b/bacula/src/stored/stored.c @@ -515,11 +515,10 @@ void terminate_stored(int sig) * them up so that they will report back the correct * volume status. */ - lock_jcr_chain(); foreach_jcr(jcr) { BSOCK *fd; - free_locked_jcr(jcr); if (jcr->JobId == 0) { + free_jcr(jcr); continue; /* ignore console */ } set_jcr_job_status(jcr, JS_Canceled); @@ -534,9 +533,9 @@ void terminate_stored(int sig) pthread_cond_broadcast(&wait_device_release); } bmicrosleep(0, 50000); - } + } + free_jcr(jcr); } - unlock_jcr_chain(); bmicrosleep(0, 500000); /* give them 1/2 sec to clean up */ } @@ -545,13 +544,11 @@ void terminate_stored(int sig) Dmsg1(200, "In terminate_stored() sig=%d\n", sig); -// LockRes(); foreach_res(device, R_DEVICE) { if (device->dev) { term_dev(device->dev); } } -// UnlockRes(); if (configfile) free(configfile); diff --git a/bacula/src/version.h b/bacula/src/version.h index 5621dae6b1..53a34e9cf1 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -1,6 +1,6 @@ /* */ #undef VERSION -#define VERSION "1.37.19" +#define VERSION "1.37.20" #define BDATE "26 May 2005" #define LSMDATE "26May05"