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.
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
),
32 TransportDIB::~TransportDIB() {
33 if (address_
!= kInvalidAddress
) {
35 address_
= kInvalidAddress
;
40 ui::DetachSharedMemory(display_
, x_shm_
);
45 TransportDIB
* TransportDIB::Create(size_t size
, uint32 sequence_num
) {
46 const int shmkey
= shmget(IPC_PRIVATE
, size
, 0600);
48 DLOG(ERROR
) << "Failed to create SysV shared memory region"
49 << " errno:" << errno
;
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
)
63 TransportDIB
* dib
= new TransportDIB
;
65 dib
->key_
.shmkey
= shmkey
;
66 dib
->address_
= address
;
72 TransportDIB
* TransportDIB::Map(Handle handle
) {
73 scoped_ptr
<TransportDIB
> dib(CreateWithHandle(handle
));
80 TransportDIB
* TransportDIB::CreateWithHandle(Handle shmkey
) {
81 TransportDIB
* dib
= new TransportDIB
;
82 dib
->key_
.shmkey
= shmkey
;
87 bool TransportDIB::is_valid_handle(Handle dib
) {
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
))
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_
))
107 if (address_
!= kInvalidAddress
)
110 struct shmid_ds shmst
;
111 if (shmctl(key_
.shmkey
, IPC_STAT
, &shmst
) == -1)
114 void* address
= shmat(key_
.shmkey
, NULL
/* desired address */, 0 /* flags */);
115 if (address
== kInvalidAddress
)
119 size_
= shmst
.shm_segsz
;
123 void* TransportDIB::memory() const {
124 DCHECK_NE(address_
, kInvalidAddress
);
128 TransportDIB::Id
TransportDIB::id() const {
132 TransportDIB::Handle
TransportDIB::handle() const {
136 XID
TransportDIB::MapToX(Display
* display
) {
138 x_shm_
= ui::AttachSharedMemory(display
, key_
.shmkey
);
145 void TransportDIB::DecreaseInFlightCounter() {
146 CHECK(inflight_counter_
);
148 if (!inflight_counter_
&& detached_
)
152 void TransportDIB::Detach() {
155 if (!inflight_counter_
)