auto-generate Unicorn::Const::UNICORN_VERSION
[unicorn.git] / lib / unicorn / worker.rb
blob1fb6a4ab355045ba6dafc5620edf345a2ddb3f70
1 # -*- encoding: binary -*-
2 require "raindrops"
4 # This class and its members can be considered a stable interface
5 # and will not change in a backwards-incompatible fashion between
6 # releases of \Unicorn.  Knowledge of this class is generally not
7 # not needed for most users of \Unicorn.
9 # Some users may want to access it in the before_fork/after_fork hooks.
10 # See the Unicorn::Configurator RDoc for examples.
11 class Unicorn::Worker
12   # :stopdoc:
13   attr_accessor :nr, :switched
14   attr_writer :tmp
16   PER_DROP = Raindrops::PAGE_SIZE / Raindrops::SIZE
17   DROPS = []
19   def initialize(nr)
20     drop_index = nr / PER_DROP
21     @raindrop = DROPS[drop_index] ||= Raindrops.new(PER_DROP)
22     @offset = nr % PER_DROP
23     @raindrop[@offset] = 0
24     @nr = nr
25     @tmp = @switched = false
26   end
28   # worker objects may be compared to just plain Integers
29   def ==(other_nr) # :nodoc:
30     @nr == other_nr
31   end
33   # called in the worker process
34   def tick=(value) # :nodoc:
35     @raindrop[@offset] = value
36   end
38   # called in the master process
39   def tick # :nodoc:
40     @raindrop[@offset]
41   end
43   # only exists for compatibility
44   def tmp # :nodoc:
45     @tmp ||= begin
46       tmp = Unicorn::TmpIO.new
47       tmp.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
48       tmp
49     end
50   end
52   def close # :nodoc:
53     @tmp.close if @tmp
54   end
56   # :startdoc:
58   # In most cases, you should be using the Unicorn::Configurator#user
59   # directive instead.  This method should only be used if you need
60   # fine-grained control of exactly when you want to change permissions
61   # in your after_fork hooks.
62   #
63   # Changes the worker process to the specified +user+ and +group+
64   # This is only intended to be called from within the worker
65   # process from the +after_fork+ hook.  This should be called in
66   # the +after_fork+ hook after any privileged functions need to be
67   # run (e.g. to set per-worker CPU affinity, niceness, etc)
68   #
69   # Any and all errors raised within this method will be propagated
70   # directly back to the caller (usually the +after_fork+ hook.
71   # These errors commonly include ArgumentError for specifying an
72   # invalid user/group and Errno::EPERM for insufficient privileges
73   def user(user, group = nil)
74     # we do not protect the caller, checking Process.euid == 0 is
75     # insufficient because modern systems have fine-grained
76     # capabilities.  Let the caller handle any and all errors.
77     uid = Etc.getpwnam(user).uid
78     gid = Etc.getgrnam(group).gid if group
79     Unicorn::Util.chown_logs(uid, gid)
80     @tmp.chown(uid, gid) if @tmp
81     if gid && Process.egid != gid
82       Process.initgroups(user, gid)
83       Process::GID.change_privilege(gid)
84     end
85     Process.euid != uid and Process::UID.change_privilege(uid)
86     @switched = true
87   end
88 end