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.
8 // Linux Aura and Chrome OS do too. This will change very soon.
9 #if defined(TOOLKIT_GTK) || (defined(OS_LINUX) && defined(USE_AURA))
16 #include "base/logging.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "skia/ext/platform_canvas.h"
19 #include "ui/base/x/x11_util.h"
20 #include "ui/gfx/size.h"
22 // The shmat system call uses this as it's invalid return address
23 static void *const kInvalidAddress
= (void*) -1;
25 TransportDIB::TransportDIB()
26 : address_(kInvalidAddress
),
34 TransportDIB::~TransportDIB() {
35 if (address_
!= kInvalidAddress
) {
37 address_
= kInvalidAddress
;
42 ui::DetachSharedMemory(display_
, x_shm_
);
47 TransportDIB
* TransportDIB::Create(size_t size
, uint32 sequence_num
) {
48 const int shmkey
= shmget(IPC_PRIVATE
, size
, 0600);
50 DLOG(ERROR
) << "Failed to create SysV shared memory region"
51 << " errno:" << errno
;
54 VLOG(1) << "Created SysV shared memory region " << shmkey
;
57 void* address
= shmat(shmkey
, NULL
/* desired address */, 0 /* flags */);
58 // Here we mark the shared memory for deletion. Since we attached it in the
59 // line above, it doesn't actually get deleted but, if we crash, this means
60 // that the kernel will automatically clean it up for us.
61 shmctl(shmkey
, IPC_RMID
, 0);
62 if (address
== kInvalidAddress
)
65 TransportDIB
* dib
= new TransportDIB
;
67 dib
->key_
.shmkey
= shmkey
;
68 dib
->address_
= address
;
74 TransportDIB
* TransportDIB::Map(Handle handle
) {
75 scoped_ptr
<TransportDIB
> dib(CreateWithHandle(handle
));
82 TransportDIB
* TransportDIB::CreateWithHandle(Handle shmkey
) {
83 TransportDIB
* dib
= new TransportDIB
;
84 dib
->key_
.shmkey
= shmkey
;
89 bool TransportDIB::is_valid_handle(Handle dib
) {
94 bool TransportDIB::is_valid_id(Id id
) {
95 return id
.shmkey
!= -1;
98 skia::PlatformCanvas
* TransportDIB::GetPlatformCanvas(int w
, int h
) {
99 if ((address_
== kInvalidAddress
&& !Map()) || !VerifyCanvasSize(w
, h
))
101 return skia::CreatePlatformCanvas(w
, h
, true,
102 reinterpret_cast<uint8_t*>(memory()),
103 skia::RETURN_NULL_ON_FAILURE
);
106 bool TransportDIB::Map() {
107 if (!is_valid_id(key_
))
109 if (address_
!= kInvalidAddress
)
112 struct shmid_ds shmst
;
113 if (shmctl(key_
.shmkey
, IPC_STAT
, &shmst
) == -1)
116 void* address
= shmat(key_
.shmkey
, NULL
/* desired address */, 0 /* flags */);
117 if (address
== kInvalidAddress
)
121 size_
= shmst
.shm_segsz
;
125 void* TransportDIB::memory() const {
126 DCHECK_NE(address_
, kInvalidAddress
);
130 TransportDIB::Id
TransportDIB::id() const {
134 TransportDIB::Handle
TransportDIB::handle() const {
138 XID
TransportDIB::MapToX(Display
* display
) {
140 x_shm_
= ui::AttachSharedMemory(display
, key_
.shmkey
);
147 void TransportDIB::DecreaseInFlightCounter() {
148 CHECK(inflight_counter_
);
150 if (!inflight_counter_
&& detached_
)
154 void TransportDIB::Detach() {
157 if (!inflight_counter_
)