When Retrier succeeds, record errors it encountered.
[chromium-blink-merge.git] / ui / surface / transport_dib_gtk.cc
blob31f651328a082d6fa1894926fa5e4eb735a4a8b2
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/surface/transport_dib.h"
7 // Desktop GTK Linux builds use the old-style SYSV SHM based DIBs.
9 #include <errno.h>
10 #include <stdlib.h>
11 #include <sys/ipc.h>
12 #include <sys/shm.h>
14 #include "base/logging.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "skia/ext/platform_canvas.h"
17 #include "ui/base/x/x11_util.h"
18 #include "ui/gfx/size.h"
20 // The shmat system call uses this as it's invalid return address
21 static void *const kInvalidAddress = (void*) -1;
23 TransportDIB::TransportDIB()
24 : address_(kInvalidAddress),
25 x_shm_(0),
26 display_(NULL),
27 inflight_counter_(0),
28 detached_(false),
29 size_(0) {
32 TransportDIB::~TransportDIB() {
33 if (address_ != kInvalidAddress) {
34 shmdt(address_);
35 address_ = kInvalidAddress;
38 if (x_shm_) {
39 DCHECK(display_);
40 ui::DetachSharedMemory(display_, x_shm_);
44 // static
45 TransportDIB* TransportDIB::Create(size_t size, uint32 sequence_num) {
46 const int shmkey = shmget(IPC_PRIVATE, size, 0600);
47 if (shmkey == -1) {
48 DLOG(ERROR) << "Failed to create SysV shared memory region"
49 << " errno:" << errno;
50 return NULL;
51 } else {
52 VLOG(1) << "Created SysV shared memory region " << shmkey;
55 void* address = shmat(shmkey, NULL /* desired address */, 0 /* flags */);
56 // Here we mark the shared memory for deletion. Since we attached it in the
57 // line above, it doesn't actually get deleted but, if we crash, this means
58 // that the kernel will automatically clean it up for us.
59 shmctl(shmkey, IPC_RMID, 0);
60 if (address == kInvalidAddress)
61 return NULL;
63 TransportDIB* dib = new TransportDIB;
65 dib->key_.shmkey = shmkey;
66 dib->address_ = address;
67 dib->size_ = size;
68 return dib;
71 // static
72 TransportDIB* TransportDIB::Map(Handle handle) {
73 scoped_ptr<TransportDIB> dib(CreateWithHandle(handle));
74 if (!dib->Map())
75 return NULL;
76 return dib.release();
79 // static
80 TransportDIB* TransportDIB::CreateWithHandle(Handle shmkey) {
81 TransportDIB* dib = new TransportDIB;
82 dib->key_.shmkey = shmkey;
83 return dib;
86 // static
87 bool TransportDIB::is_valid_handle(Handle dib) {
88 return dib >= 0;
91 // static
92 bool TransportDIB::is_valid_id(Id id) {
93 return id.shmkey != -1;
96 skia::PlatformCanvas* TransportDIB::GetPlatformCanvas(int w, int h) {
97 if ((address_ == kInvalidAddress && !Map()) || !VerifyCanvasSize(w, h))
98 return NULL;
99 return skia::CreatePlatformCanvas(w, h, true,
100 reinterpret_cast<uint8_t*>(memory()),
101 skia::RETURN_NULL_ON_FAILURE);
104 bool TransportDIB::Map() {
105 if (!is_valid_id(key_))
106 return false;
107 if (address_ != kInvalidAddress)
108 return true;
110 struct shmid_ds shmst;
111 if (shmctl(key_.shmkey, IPC_STAT, &shmst) == -1)
112 return false;
114 void* address = shmat(key_.shmkey, NULL /* desired address */, 0 /* flags */);
115 if (address == kInvalidAddress)
116 return false;
118 address_ = address;
119 size_ = shmst.shm_segsz;
120 return true;
123 void* TransportDIB::memory() const {
124 DCHECK_NE(address_, kInvalidAddress);
125 return address_;
128 TransportDIB::Id TransportDIB::id() const {
129 return key_;
132 TransportDIB::Handle TransportDIB::handle() const {
133 return key_.shmkey;
136 XID TransportDIB::MapToX(Display* display) {
137 if (!x_shm_) {
138 x_shm_ = ui::AttachSharedMemory(display, key_.shmkey);
139 display_ = display;
142 return x_shm_;
145 void TransportDIB::DecreaseInFlightCounter() {
146 CHECK(inflight_counter_);
147 inflight_counter_--;
148 if (!inflight_counter_ && detached_)
149 delete this;
152 void TransportDIB::Detach() {
153 CHECK(!detached_);
154 detached_ = true;
155 if (!inflight_counter_)
156 delete this;