lock.c
来自「distcc编译器的源代码.好像是readhat公司开发的.」· C语言 代码 · 共 248 行
C
248 行
/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78; -*- * * distcc -- A simple distributed compiler system * * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> * * 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. * * 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 */ /* Power is nothing without control * -- Pirelli tyre advertisment. *//** * @file * * @brief Manage lockfiles. * * distcc uses a simple disk-based lockfile system to keep track of how many * jobs are queued on various machines. These locks might be used for * something else in the future. * * We use locks rather than e.g. a database or a central daemon because we * want to make sure that the lock will be removed if the client terminates * unexpectedly. * * The files themselves (as opposed to the lock on them) are never cleaned up; * since locking & creation is nonatomic I can't think of a clean way to do * it. There shouldn't be many of them, and dead ones will be caught by the * tmpreaper. In any case they're zero bytes. * * Sys V semaphores might work well here, but the interface is a bit ugly and * they are probably not portable to Cygwin. In particular they can leak if * the process is abruptly terminated, which is likely to happen to distcc. */#include "config.h"#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <fcntl.h>#include <errno.h>#include <time.h>#include <sys/stat.h>#include <sys/file.h>#include "distcc.h"#include "trace.h"#include "util.h"#include "hosts.h"#include "lock.h"#include "exitcode.h"#include "snprintf.h"struct dcc_hostdef _dcc_local = { DCC_MODE_LOCAL, NULL, (char *) "localhost", 0, NULL, 4, /* number of tasks */ (char *)"localhost", /* verbatim string */ DCC_VER_1, /* protocol (ignored) */ DCC_COMPRESS_NONE, /* compression (ignored) */ NULL };struct dcc_hostdef *dcc_hostdef_local = &_dcc_local;/** * Returns a newly allocated buffer. **/int dcc_make_lock_filename(const char *lockname, const struct dcc_hostdef *host, int iter, char **filename_ret){ char * buf; int ret; char *lockdir; if ((ret = dcc_get_lock_dir(&lockdir))) return ret; if (host->mode == DCC_MODE_LOCAL) { if (asprintf(&buf, "%s/%s_localhost_%d", lockdir, lockname, iter) == -1) return EXIT_OUT_OF_MEMORY; } else if (host->mode == DCC_MODE_TCP) { if (asprintf(&buf, "%s/%s_tcp_%s_%d_%d", lockdir, lockname, host->hostname, host->port, iter) == -1) return EXIT_OUT_OF_MEMORY; } else if (host->mode == DCC_MODE_SSH) { if (asprintf(&buf, "%s/%s_ssh_%s_%d", lockdir, lockname, host->hostname, iter) == -1) return EXIT_OUT_OF_MEMORY; } else { rs_log_crit("oops"); return EXIT_PROTOCOL_ERROR; } *filename_ret = buf; return 0;}/** * Get an exclusive, non-blocking lock on a file using whatever method * is available on this system. * * @retval 0 if we got the lock * @retval -1 with errno set if the file is already locked. **/static int sys_lock(int fd, int block){#if defined(F_SETLK) struct flock lockparam; lockparam.l_type = F_WRLCK; lockparam.l_whence = SEEK_SET; lockparam.l_start = 0; lockparam.l_len = 0; /* whole file */ return fcntl(fd, block ? F_SETLKW : F_SETLK, &lockparam);#elif defined(HAVE_FLOCK) return flock(fd, LOCK_EX | (block ? 0 : LOCK_NB));#elif defined(HAVE_LOCKF) return lockf(fd, block ? F_LOCK : F_TLOCK, 0);#else# error "No supported lock method. Please port this code."#endif}int dcc_unlock(int lock_fd){ rs_trace("release lock fd%d", lock_fd); /* All our current locks can just be closed */ if (close(lock_fd)) { rs_log_error("close failed: %s", strerror(errno)); return EXIT_IO_ERROR; } return 0;}/** * Open a lockfile, creating if it does not exist. **/int dcc_open_lockfile(const char *fname, int *plockfd){ /* Create if it doesn't exist. We don't actually do anything with * the file except lock it. * * The file is created with the loosest permissions allowed by the user's * umask, to give the best chance of avoiding problems if they should * happen to use a shared lock dir. */ /* FIXME: If we fail to open with EPERM or something similar, try deleting * the file and try again. That might fix problems with root-owned files * in user home directories. */ *plockfd = open(fname, O_WRONLY|O_CREAT, 0666); if (*plockfd == -1 && errno != EEXIST) { rs_log_error("failed to creat %s: %s", fname, strerror(errno)); return EXIT_IO_ERROR; } return 0;}/** * Lock a server slot, in either blocking or nonblocking mode. * * In blocking mode, this function will not return until either the lock has * been acquired, or an error occured. In nonblocking mode, it will instead * return EXIT_BUSY if some other process has this slot locked. * * @param slot 0-based index of available slots on this host. * @param block True for blocking mode. * * @param lock_fd On return, contains the lock file descriptor to allow * it to be closed. **/int dcc_lock_host(const char *lockname, const struct dcc_hostdef *host, int slot, int block, int *lock_fd){ char *fname; int ret; if ((ret = dcc_make_lock_filename(lockname, host, slot, &fname))) return ret; if ((ret = dcc_open_lockfile(fname, lock_fd)) != 0) { free(fname); return ret; } if (sys_lock(*lock_fd, block) == 0) { rs_trace("got %s lock on %s slot %d as fd%d", lockname, host->hostdef_string, slot, *lock_fd); free(fname); return 0; } else { switch (errno) {#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN case EWOULDBLOCK:#endif case EAGAIN: case EACCES: /* HP-UX and Cygwin give this for exclusion */ rs_trace("%s is busy", fname); ret = EXIT_BUSY; break; default: rs_log_error("lock %s failed: %s", fname, strerror(errno)); ret = EXIT_IO_ERROR; break; } dcc_close(*lock_fd); free(fname); return ret; }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?