Class: Rumai::IXP::Agent
Overview
A thread-safe channel that multiplexes many threads onto a single 9P2000 connection.
The send/recv implementation is based on the XCB cookie approach: www.x.org/releases/X11R7.5/doc/libxcb/tutorial/#requestsreplies
Defined Under Namespace
Classes: FidStream, RangedPool
Constant Summary
- MODES =
{ 'r' => Topen::OREAD, 'w' => Topen::OWRITE, 't' => Topen::ORCLOSE, '+' => Topen::ORDWR, }
Instance Attribute Summary
-
- (Object) msize
readonly
Returns the value of attribute msize.
Instance Method Summary
-
- (Object) attach(root_fid, auth_fid = Fcall::NOFID, auth_name = ENV['USER'])
Associates the given FID with the FS root.
-
- (Object) clunk(fid)
Retires the given FID from use.
-
- (Object) create(path, mode = 'rw', perm = 0644)
Creates a new file at the given path that is accessible using the given modes for a user having the given permission bits.
-
- (Object) entries(path)
Returns the basenames of all files inside the directory at the given path.
-
- (Agent) initialize(stream)
constructor
A new instance of Agent.
-
- (Object) open(path, mode = 'r')
Opens the given path for I/O access through a FidStream object.
-
- (Object) read(path, *args)
Returns the content of the file/directory at the given path.
-
- (Object) recv(tag)
Returns the reply for the given ticket, which was previously given to you when you sent the corresponding request Rumai::IXP::Fcall.
-
- (Object) remove(path)
Deletes the file at the given path.
-
- (Object) remove_fid(path_fid)
Deletes the file corresponding to the given FID and clunks the given FID.
-
- (Object) send(request)
Sends the given request Rumai::IXP::Fcall and returns a ticket that you can use later to receive the reply.
-
- (Object) stat(path)
Returns information about the file at the given path.
-
- (Object) stat_fid(path_fid)
Returns information about the file referenced by the given FID.
-
- (Object) talk(request)
Sends the given request Rumai::IXP::Fcall and returns its reply.
-
- (Object) walk(path)
Returns an FID corresponding to the given path.
-
- (Object) walk_fid(path_fid, path)
Associates the given FID to the given path.
-
- (Object) write(path, content)
Writes the given content to the file at the given path.
Constructor Details
- (Agent) initialize(stream)
A new instance of Agent
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/rumai/ixp/transport.rb', line 22 def initialize stream @stream = stream @recv_buf = {} # tag => message @recv_lock = Mutex.new @tag_pool = RangedPool.new(0...BYTE2_MASK) @fid_pool = RangedPool.new(0...BYTE4_MASK) # establish connection with 9P2000 server req = Tversion.new( :tag => Fcall::NOTAG, :msize => Tversion::MSIZE, :version => Tversion::VERSION ) rsp = talk(req) unless req.version == rsp.version raise Error, "protocol mismatch: self=#{req.version.inspect} server=#{rsp.version.inspect}" end @msize = rsp.msize # authenticate the connection (not necessary for wmii) @auth_fid = Fcall::NOFID # attach to filesystem root @root_fid = @fid_pool.obtain attach @root_fid, @auth_fid end |
Instance Attribute Details
- (Object) msize (readonly)
Returns the value of attribute msize
16 17 18 |
# File 'lib/rumai/ixp/transport.rb', line 16 def msize @msize end |
Instance Method Details
- (Object) attach(root_fid, auth_fid = Fcall::NOFID, auth_name = ENV['USER'])
Associates the given FID with the FS root.
468 469 470 471 472 473 474 475 |
# File 'lib/rumai/ixp/transport.rb', line 468 def attach root_fid, auth_fid = Fcall::NOFID, auth_name = ENV['USER'] talk Tattach.new( :fid => root_fid, :afid => auth_fid, :uname => ENV['USER'], :aname => auth_name ) end |
- (Object) clunk(fid)
Retires the given FID from use.
480 481 482 483 |
# File 'lib/rumai/ixp/transport.rb', line 480 def clunk fid talk Tclunk.new(:fid => fid) @fid_pool.release fid end |
- (Object) create(path, mode = 'rw', perm = 0644)
Creates a new file at the given path that is accessible using the given modes for a user having the given permission bits.
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 |
# File 'lib/rumai/ixp/transport.rb', line 391 def create path, mode = 'rw', perm = 0644 prefix = File.dirname(path) target = File.basename(path) mode = MODES.parse(mode) with_fid do |prefix_fid| walk_fid prefix_fid, prefix # create the file talk Tcreate.new( :fid => prefix_fid, :name => target, :perm => perm, :mode => mode ) end end |
- (Object) entries(path)
Returns the basenames of all files inside the directory at the given path.
369 370 371 372 373 374 375 |
# File 'lib/rumai/ixp/transport.rb', line 369 def entries path unless stat(path).directory? raise ArgumentError, "#{path.inspect} is not a directory" end read(path).map! {|t| t.name} end |
- (Object) open(path, mode = 'r')
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
# File 'lib/rumai/ixp/transport.rb', line 208 def open path, mode = 'r' mode = MODES.parse(mode) # open the file path_fid = walk(path) talk Topen.new( :fid => path_fid, :mode => mode ) stream = FidStream.new(self, path_fid, @msize) # return the file stream if block_given? begin yield stream ensure stream.close end else stream end end |
- (Object) read(path, *args)
Returns the content of the file/directory at the given path.
357 358 359 360 361 |
# File 'lib/rumai/ixp/transport.rb', line 357 def read path, *args open path do |f| f.read(*args) end end |
- (Object) recv(tag)
Returns the reply for the given ticket, which was previously given to you when you sent the corresponding request Rumai::IXP::Fcall.
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/rumai/ixp/transport.rb', line 120 def recv tag loop do reply = @recv_lock.synchronize do if @recv_buf.key? tag @recv_buf.delete tag else # reply was not in receive buffer, so read # the next reply... hoping that it is ours next_reply_available = @recv_buf.empty? || begin # check (in a non-blocking fashion) if # the stream has reply for us right now @stream.ungetc @stream.read_nonblock(1) true rescue Errno::EAGAIN # the stream is empty end if next_reply_available msg = Fcall.from_9p(@stream) if msg.tag == tag msg else # we got someone else's reply, so buffer # it (for them to receive) and try again @recv_buf[msg.tag] = msg nil end end end end if reply @tag_pool.release tag if reply.is_a? Rerror raise Error, reply.ename end return reply else # give other threads a chance to receive Thread.pass end end end |
- (Object) remove(path)
Deletes the file at the given path.
413 414 415 416 |
# File 'lib/rumai/ixp/transport.rb', line 413 def remove path path_fid = walk(path) remove_fid path_fid # remove also does clunk end |
- (Object) remove_fid(path_fid)
Deletes the file corresponding to the given FID and clunks the given FID.
422 423 424 |
# File 'lib/rumai/ixp/transport.rb', line 422 def remove_fid path_fid talk Tremove.new(:fid => path_fid) end |
- (Object) send(request)
Sends the given request Rumai::IXP::Fcall and returns a ticket that you can use later to receive the reply.
107 108 109 110 111 112 113 114 |
# File 'lib/rumai/ixp/transport.rb', line 107 def send request tag = @tag_pool.obtain request.tag = tag @stream << request.to_9p tag end |
- (Object) stat(path)
Returns information about the file at the given path.
429 430 431 432 433 434 |
# File 'lib/rumai/ixp/transport.rb', line 429 def stat path with_fid do |path_fid| walk_fid path_fid, path stat_fid path_fid end end |
- (Object) stat_fid(path_fid)
Returns information about the file referenced by the given FID.
439 440 441 442 443 |
# File 'lib/rumai/ixp/transport.rb', line 439 def stat_fid path_fid req = Tstat.new(:fid => path_fid) rsp = talk(req) rsp.stat end |
- (Object) talk(request)
Sends the given request Rumai::IXP::Fcall and returns its reply.
172 173 174 175 176 177 178 179 180 181 |
# File 'lib/rumai/ixp/transport.rb', line 172 def talk request tag = send(request) begin recv tag rescue Error => e e. << " -- in reply to #{request.inspect}" raise end end |
- (Object) walk(path)
Returns an FID corresponding to the given path.
448 449 450 451 452 |
# File 'lib/rumai/ixp/transport.rb', line 448 def walk path fid = @fid_pool.obtain walk_fid fid, path fid end |
- (Object) walk_fid(path_fid, path)
Associates the given FID to the given path.
457 458 459 460 461 462 463 |
# File 'lib/rumai/ixp/transport.rb', line 457 def walk_fid path_fid, path talk Twalk.new( :fid => @root_fid, :newfid => path_fid, :wname => path.to_s.split(%r{/+}).reject {|s| s.empty? } ) end |
- (Object) write(path, content)
Writes the given content to the file at the given path.
381 382 383 384 385 |
# File 'lib/rumai/ixp/transport.rb', line 381 def write path, content open path, 'w' do |f| f << content end end |