text:
using System;
using System.Text;
using System.IO;
using Google.GData.Apps;
using Google.GData.Apps.Groups;
using Google.GData.Extensions;

namespace GoogleAppsConsoleApplication
{
    class AppsDemo
    {
        private static string domain;
        private static string adminEmail;
        private static string adminPassword;

        // If desired, you may replace these values of username, nickname
        // and email list name with others that do not already exist on
        // your domain.
        private static string testUserName = "testUserName" + new Random().Next().ToString();
        private const string testNickname = "testNickname";
        private static string testGroup = "testGroup" + new Random().Next().ToString();

        private static void UserOperations(AppsService service)
        {
            // Create a new user.
            UserEntry insertedEntry = service.CreateUser(testUserName, "Jane",
                "Doe", "testuser-password");
            Console.WriteLine("Created new user '{0}'", insertedEntry.Login.UserName);

            // Suspend the user.
            UserEntry suspendedEntry = service.SuspendUser(testUserName);
            Console.WriteLine("Suspended account for {0}", suspendedEntry.Login.UserName);

            // Restore the user.
            UserEntry restoredEntry = service.RestoreUser(testUserName);
            Console.WriteLine("Restored user {0}", restoredEntry.Login.UserName);

            // Query for a single user.
            UserEntry entry = service.RetrieveUser(testUserName);
            Console.WriteLine("Retrieved user {0}", entry.Login.UserName);

            // Query for a page of users.
            UserFeed feed = service.RetrievePageOfUsers(testUserName);
            entry = feed.Entries[0] as UserEntry;
            Console.WriteLine("Retrieved page of {0} users, beginning with '{1}'", feed.Entries.Count,
                entry.Login.UserName);

            // Query for all users.
            feed = service.RetrieveAllUsers();
            entry = feed.Entries[0] as UserEntry;
            Console.WriteLine("Retrieved all {0} users in the domain, beginning with '{1}'",
                feed.Entries.Count, entry.Login.UserName);

            // Update the user's given name.
            restoredEntry.Name.GivenName = "John";
            UserEntry updatedEntry = service.UpdateUser(entry);
            Console.WriteLine("Updated user with new given name '{0}'", updatedEntry.Name.GivenName);
        }

        private static void NicknameOperations(AppsService service)
        {
            // Create a new nickname.
            NicknameEntry insertedEntry = service.CreateNickname(testUserName, testNickname);
            Console.WriteLine("Created nickname '{0}' for user {1}", insertedEntry.Nickname.Name,
                insertedEntry.Login.UserName);

            // Retrieve the newly-created nickname.
            NicknameEntry entry = service.RetrieveNickname(testNickname);
            Console.WriteLine("Retrieved nickname {0}", entry.Nickname.Name);

            // Retrieve all nicknames for testUserName (really, just this one).
            NicknameFeed feed = service.RetrieveNicknames(testUserName);
            entry = feed.Entries[0] as NicknameEntry;
            Console.WriteLine("Retrieved nickname '{0}' for user {1}", entry.Nickname.Name,
                entry.Login.UserName);

            // Retrieve a page of nicknames.
            feed = service.RetrievePageOfNicknames(testNickname);
            entry = feed.Entries[0] as NicknameEntry;
            Console.WriteLine("Retrieved page of {0} nicknames, beginning with '{1}'",
                feed.Entries.Count, entry.Nickname.Name);

            // Retrieve the feed of all nicknames.
            feed = service.RetrieveAllNicknames();
            entry = feed.Entries[0] as NicknameEntry;
            Console.WriteLine("Retrieved all {0} nicknames in the domain, beginning with '{1}'",
                feed.Entries.Count, entry.Nickname.Name);
        }

        private static void GroupOperations(AppsService service)
        {
            // Create a new group.
            AppsExtendedEntry insertedEntry = service.Groups.CreateGroup(testGroup, testGroup, testGroup,null);
            Console.WriteLine("Created new group '{0}'", insertedEntry.getPropertyByName("groupId" ).Value);

            // Retrieve the newly-created group.
            AppsExtendedEntry entry = service.Groups.RetrieveGroup(testGroup);
            Console.WriteLine("Retrieved group '{0}'", entry.getPropertyByName("groupId").Value);

            // Add Member To Group
            AppsExtendedEntry newMemberEntry = service.Groups.AddMemberToGroup(testUserName, testGroup);
            Console.WriteLine("User '{0}' was added as member to group '{1}'",
                newMemberEntry.getPropertyByName("memberId").Value, testGroup);

            // Add Owner to Group
            AppsExtendedEntry newOwnerEntry = service.Groups.AddOwnerToGroup(testUserName, testGroup);
            Console.WriteLine("User '{0}' was added as ownter to group '{1}'",
                newOwnerEntry.getPropertyByName("email").Value, testGroup);

            // Check if a User is a Group Member
            Console.WriteLine("Is User '{0}' member of group '{1}'? '{2}'",
                 testUserName, testGroup, service.Groups.IsMember(testUserName, testGroup));

            // Check if a User is a Group Member
            Console.WriteLine("Is User '{0}' owner of group '{1}'? '{2}'",
                 testUserName, testGroup, service.Groups.IsOwner(testUserName, testGroup));

            // Remove Member from Group
            service.Groups.RemoveMemberFromGroup(testUserName, testGroup);
            Console.WriteLine("User '{0}' was removed as member to group '{1}'",
               testUserName, testGroup);

            // Remove Owner from Group
            service.Groups.RemoveOwnerFromGroup(testUserName, testGroup);
            Console.WriteLine("User '{0}' was removed as ownter to group '{1}'",
                testUserName, testGroup);

            // Retreive all groups
            AppsExtendedFeed groupsFeed = service.Groups.RetrieveAllGroups();
            Console.WriteLine("First Group from All groups: '{0}'",
                (groupsFeed.Entries[0] as AppsExtendedEntry).getPropertyByName("groupId").Value);
        }

        private static void CleanUp(AppsService service)
        {
            // Delete the group that was created
            service.Groups.DeleteGroup(testGroup);
            Console.WriteLine("Deleted group {0}", testGroup);

            // Delete the nickname that was created.
            service.DeleteNickname(testNickname);
            Console.WriteLine("Deleted nickname {0}", testNickname);

            // Delete the user that was created.
            service.DeleteUser(testUserName);
            Console.WriteLine("Deleted user {0}", testUserName);
        }

        private static void RunSample(AppsService service)
        {
            try
            {
                // Demonstrate operations on user accounts.
                UserOperations(service);

                // Demonstrate operations on nicknames.
                NicknameOperations(service);

                // Demostrate operations on groups
                GroupOperations(service);

                // Clean up (delete the username, nickname and email list
                // that were created).
                CleanUp(service);
            }
            catch (AppsException a)
            {
                Console.WriteLine("A Google Apps error occurred.");
                Console.WriteLine();
                Console.WriteLine("Error code: {0}", a.ErrorCode);
                Console.WriteLine("Invalid input: {0}", a.InvalidInput);
                Console.WriteLine("Reason: {0}", a.Reason);
            }
        }

        /// <summary>
        /// This console application demonstrates all the Google Apps
        /// Provisioning API calls.  It accepts authentication information
        /// from the command-line and performs a series of create/
        /// retrieve/update/delete operations on user accounts, nicknames,
        /// and email lists, as described in the comments of RunTests.
        /// </summary>
        /// <param name="args">Command-line arguments: args[0] is
        /// the domain, args[1] is the admin email address, and args[2]
        /// is the admin psasword.
        ///
        /// Example: AppsDemo example.com admin@example.com my_password</param>
        public static void Main(string[] args)
        {
            if (args.Length != 3)
            {
                Console.WriteLine("Syntax: AppsDemo <domain> <admin_email> <admin_password>");
            }
            else
            {
                domain = args[0];
                adminEmail = args[1];
                adminPassword = args[2];

                AppsService service = new AppsService(domain, adminEmail, adminPassword);

                RunSample(service);
            }
        }
    }
}

redpajama_set_name: RedPajamaGithub


text:
name 'lp-redis'
maintainer 'Geoff Gerrietts'
maintainer_email 'geoff@gerrietts.net'
license 'mit'
description 'Installs redis'
long_description 'Installs redis'
version '0.1.0'

depends 'lp-foundation', '~> 0.1.0'


text:
describe("TCP packet class", function()
	local ffi = require "ffi"
	local pkt = require "proto.proto"
	it("should set TCP", function()
		local raw = ffi.new("struct tcp_header")
		local set = ffi.new("struct tcp_header")

		raw.src = hton16(1234)
		set:setSrcPort(1234)
		assert.are.same(raw.src, set.src)

		raw.dst = hton16(5678)
		set:setDstPort(5678)
		assert.are.same(raw.dst, set.dst)

		raw.seq = hton(122334)
		set:setSeqNumber(122334)
		assert.are.same(raw.seq, set.seq)

		raw.ack = hton(566778)
		set:setAckNumber(566778)
		assert.are.same(raw.ack, set.ack)

		-- TODO offset reserved flags

		raw.window = hton16(9876)
		set:setWindow(9876)
		assert.are.same(raw.window, set.window)

		raw.cs = hton16(1928)
		set:setChecksum(1928)
		assert.are.same(raw.cs, set.cs)

		raw.urg = hton16(3746)
		set:setUrgentPointer(3746)
		assert.are.same(raw.urg, set.urg)
	end)
	it("should set/get with named args (TCPv4)", function()
		local pkt = ffi.new("struct __ethernet_eth__ip4_ip4__tcp_tcp")

		local tcpSrc			= 456
		local tcpDst			= 789
		local tcpSeqNumber		= 1337
		local tcpAckNumber		= 4207
		local tcpDataOffset		= 0xf
		local tcpReserved		= 0x11
		local tcpFlags			= 0x22
		local tcpWindow			= 23
		local tcpChecksum		= 0x9876
		local tcpUrgentPointer	= 91
		local tcpUrg			= 1
		local tcpAck			= 0
		local tcpPsh			= 0
		local tcpRst			= 0
		local tcpSyn			= 1
		local tcpFin			= 0

		local args = pkt:get()
		args.tcpSrc = tcpSrc
		args.tcpDst = tcpDst
		args.tcpSeqNumber = tcpSeqNumber
		args.tcpAckNumber = tcpAckNumber
		args.tcpDataOffset = tcpDataOffset
		args.tcpReserved = tcpReserved
		args.tcpFlags = tcpFlags
		args.tcpWindow = tcpWindow
		args.tcpChecksum = tcpChecksum
		args.tcpUrgentPointer = tcpUrgentPointer
		args.tcpUrg = tcpUrg
		args.tcpAck	= tcpAck
		args.tcpPsh = tcpPsh
		args.tcpRst = tcpRst
		args.tcpSyn = tcpSyn
		args.tcpFin = tcpFin

		pkt:fill(args)
		assert.are.same(tcpSrc, pkt.tcp:getSrcPort())
		assert.are.same(tcpDst, pkt.tcp:getDstPort())
		assert.are.same(tcpSeqNumber, pkt.tcp:getSeqNumber())
		assert.are.same(tcpAckNumber, pkt.tcp:getAckNumber())
		assert.are.same(tcpDataOffset, pkt.tcp:getDataOffset())
		assert.are.same(tcpReserved, pkt.tcp:getReserved())
		assert.are.same(tcpFlags, pkt.tcp:getFlags())
		assert.are.same(tcpWindow, pkt.tcp:getWindow())
		assert.are.same(tcpChecksum, pkt.tcp:getChecksum())
		assert.are.same(tcpUrgentPointer, pkt.tcp:getUrgentPointer())
		assert.are.same(tcpUrg, pkt.tcp:getUrg())
		assert.are.same(tcpAck, pkt.tcp:getAck())
		assert.are.same(tcpPsh, pkt.tcp:getPsh())
		assert.are.same(tcpRst, pkt.tcp:getRst())
		assert.are.same(tcpSyn, pkt.tcp:getSyn())
		assert.are.same(tcpFin, pkt.tcp:getFin())

		local args2 = pkt:get()
		assert.are.same(args, args2)
	end)
end)


text:
Wslay - The WebSocket library
=============================

Wslay is a WebSocket library written in C.
It implements the protocol version 13 described in
`RFC 6455 <http://tools.ietf.org/html/rfc6455>`_.
This library offers 2 levels of API:
event-based API and frame-based low-level API. For event-based API, it
is suitable for non-blocking reactor pattern style. You can set
callbacks in various events. For frame-based API, you can send
WebSocket frame directly. Wslay only supports data transfer part of
WebSocket protocol and does not perform opening handshake in HTTP.

Wslay supports:

* Text/Binary messages.
* Automatic ping reply.
* Callback interface.
* External event loop.

Wslay does not perform any I/O operations for its own. Instead, it
offers callbacks for them. This makes Wslay independent on any I/O
frameworks, SSL, sockets, etc.  This makes Wslay protable across
various platforms and the application authors can choose freely I/O
frameworks.

See Autobahn test reports:
`server <http://wslay.sourceforge.net/autobahn/reports/servers/index.html>`_
and
`client <http://wslay.sourceforge.net/autobahn/reports/clients/index.html>`_.

This project is hosted at http://sourceforge.net/projects/wslay/

Source code is hosted at https://github.com/tatsuhiro-t/wslay

Contents:

.. toctree::
   :maxdepth: 2

   tutorial
   api_reference


text:
<script>
  top.postMessage("ready", "*");
  window.history.back();
</script>


text:
module Akarui.FOL.LiteralSign where

import Akarui.ShowTxt
import Akarui.FOL.Symbols
import Akarui.FOL.PrettyPrint

data LiteralSign = Positive | Negative
  deriving (Eq, Ord, Show, Read)

instance ShowTxt LiteralSign where
  showTxt Positive = "Positive"
  showTxt Negative = "Negative"

instance PrettyPrint LiteralSign where
  prettyPrint _ Positive = ""
  prettyPrint s Negative = symNot s


text:
#include "EventListReader.hpp"

#include "T3RLookupTables.hpp"

#include <VoxieClient/Exception.hpp>

#include <QDebug>
#include <QIODevice>

namespace vx {
namespace t3r {

const EventListReader::Size EventListReader::eventSize = 8;

EventListReader::EventListReader(QIODevice* device) : device(device) {
  readHeader();
}

void EventListReader::seek(Size eventIndex) {
  device->seek(startOffset + eventIndex * eventSize);
}

bool EventListReader::endReached() const {
  return (device->pos() - startOffset) / eventSize >= eventCount;
}

EventListEntry EventListReader::readEntry() {
  std::array<char, eventSize> buffer;

  if (device->read(buffer.data(), buffer.size()) < (int64_t)buffer.size()) {
    qWarning() << "Unexpected end of file";
    return InvalidEntry;
  } else {
    auto entry =
        processEntry(reinterpret_cast<const unsigned char*>(buffer.data()));
    if (entry.isValid()) {
      return entry;
    } else {
      // Try correcting the offset for the next read
      device->seek(device->pos() - 4);
      return entry;
    }
  }
}

EventListReader::ReadResult EventListReader::readIntoBufferGroup(
    EventListBufferGroup& bufferGroup, ReadOptions options) {
  ReadResult result;

  // Return "reverse" timestamp bounds if no events were read
  result.minTimestamp = options.maxTimestamp;
  result.maxTimestamp = options.minTimestamp;

  if (options.startIndex >= options.endIndex ||
      options.targetStartIndex >= options.targetEndIndex) {
    return result;
  }

  // Obtain attribute buffers
  auto bufferX = bufferGroup.getBuffer<Coord>("x");
  auto bufferY = bufferGroup.getBuffer<Coord>("y");
  auto bufferTime = bufferGroup.getBuffer<Timestamp>("timestamp");
  auto bufferTot = bufferGroup.getBuffer<ShortTimestamp>("timeOverThreshold");

  if (options.startIndex >= getEventCount()) {
    throw vx::Exception("de.uni_stuttgart.Voxie.ExtDataT3R",
                        "EventListReader: startIndex out of bounds");
  } else if (options.endIndex > getEventCount()) {
    throw vx::Exception("de.uni_stuttgart.Voxie.ExtDataT3R",
                        "EventListReader: endIndex out of bounds");
  } else if (options.targetStartIndex >= bufferGroup.getBufferSize()) {
    throw vx::Exception("de.uni_stuttgart.Voxie.ExtDataT3R",
                        "EventListReader: targetStartIndex out of bounds");
  } else if (options.targetEndIndex > bufferGroup.getBufferSize()) {
    throw vx::Exception("de.uni_stuttgart.Voxie.ExtDataT3R",
                        "EventListReader: targetEndIndex out of bounds");
  }

  seek(options.startIndex);

  Size offset = options.targetStartIndex;

  auto append = [&](const EventListEntry& entry) {
    // Add entry data to buffer group
    bufferX(offset) = entry.x;
    bufferY(offset) = entry.y;
    bufferTime(offset) = entry.timestamp;
    bufferTot(offset) = entry.timeOverThreshold;
    ++offset;
  };

  auto isEntryInRange = [&](const EventListEntry& entry) {
    return entry.isValid() && entry.timestamp >= options.minTimestamp &&
           entry.timestamp <= options.maxTimestamp;
  };

  if (options.sorted) {
    std::size_t limit = options.targetEndIndex - options.targetStartIndex;

    // Read entries into vector first
    std::vector<EventListEntry> entries;
    entries.reserve(limit);

    for (auto index = options.startIndex; index < options.endIndex; ++index) {
      auto entry = readEntry();
      if (isEntryInRange(entry)) {
        entries.push_back(entry);
      }
    }

    std::sort(entries.begin(), entries.end(),
              [](const EventListEntry& e1, const EventListEntry& e2) {
                return e1.timestamp < e2.timestamp;
              });

    // Reduce entry count to size limit
    if (entries.size() > limit) {
      result.bufferExceeded = true;
      entries.resize(limit);
    }

    // Determine minimum/maximum timestamps
    if (!entries.empty()) {
      result.minTimestamp = entries.front().timestamp;
      result.maxTimestamp = entries.back().timestamp;
    }

    // Write entries to buffer
    for (const auto& entry : entries) {
      append(entry);
    }
  } else {
    for (auto index = options.startIndex; index < options.endIndex; ++index) {
      if (offset >= options.targetEndIndex) {
        // Read entry count exceeds target range end index: abort
        result.bufferExceeded = true;
        break;
      }
      auto entry = readEntry();
      if (isEntryInRange(entry)) {
        append(entry);
        result.minTimestamp = std::min(result.minTimestamp, entry.timestamp);
        result.maxTimestamp = std::max(result.maxTimestamp, entry.timestamp);
      }
    }
  }

  result.count = offset - options.targetStartIndex;
  return result;
}

void EventListReader::readHeader() {
  device->seek(0);

  while (true) {
    // Buffer to hold a single packet
    std::array<char, 4> buffer;

    // Peek first byte to check if the packet type matches
    if (device->peek(buffer.data(), 1) < 1) {
      // End of file reached
      break;
    }

    if ((buffer[0] & 0xF0) == 0xB0) {
      // Start of data reached
      break;
    } else if (device->read(buffer.data(), buffer.size()) <
               (int64_t)buffer.size()) {
      throw vx::Exception("de.uni_stuttgart.Voxie.ExtDataT3R",
                          "Malformed T3R (unexpected end of file)");
    }

    // Increment data starting offset
    startOffset += buffer.size();
  }

  eventCount = device->size() / eventSize - startOffset;
}

EventListEntry EventListReader::processEntry(const unsigned char* data) {
  if ((data[0] & 0xF0) != 0xB0) {
    return InvalidEntry;
  }

  EventListEntry entry;

  uint32_t address =
      ((data[0] & 0x0F) << 12) | (data[1] << 4) | ((data[2] >> 4) & 0x0F);

  uint32_t pix = address & 0x07;
  entry.x = ((address >> 9) & 0x7F) * 2 + pix / 4;
  entry.y = ((address >> 3) & 0x3F) * 4 + pix % 4;

  uint32_t timeOverThreshold =
      ((data[4] & 0x3F) << 4) | ((data[5] >> 4) & 0x0F);

  if (timeOverThreshold >= lookup::TimeOverThreshold.size()) {
    return InvalidEntry;
  } else {
    entry.timeOverThreshold = lookup::TimeOverThreshold[timeOverThreshold];
  }

  uint64_t timeOfActivation =
      ((data[2] & 0x0F) << 10) | (data[3] << 2) | ((data[4] >> 6) & 0x03);

  if (timeOfActivation >= lookup::TimeOfActivation.size()) {
    return InvalidEntry;
  } else {
    timeOfActivation = lookup::TimeOfActivation[timeOfActivation] +
                       (data[6] << 22) + (data[7] << 14);
  }

  uint32_t fastTimeOfActivation =
      (data[5] & 0x0F) + lookup::ColumnShift[entry.x];

  entry.timestamp = timeOfActivation * 16 + fastTimeOfActivation;

  return entry;
}

EventListReader::Size EventListReader::getEventCount() const {
  return eventCount;
}

}  // namespace t3r
}  // namespace vx


text:
---
layout:     post
title:      "Android的智能指针"
date:       2017-04-23 13:00:00
author:     "hxg_"
comments:	true
header-img: "img/post-bg-01.jpg"
---

## 安卓系统中的智能指针

### 背景

	在使用C++来编写代码的过程中,指针使用不当造成内存泄漏一般就是因为new了一个对象并且使用完之后,忘记了delete这个对象,而造成系统崩溃一般就是因为一个地方delete了这个对象之后,其它地方还在继续使原来指向这个对象的指针。为了避免出现上述问题,一般的做法就是使用引用计数的方法,每当有一个指针指向了一个new出来的对象时,就对这个对象的引用计数增加1,每当有一个指针不再使用这个对象时,就对这个对象的引用计数减少1,每次减1之后,如果发现引用计数值为0时,那么,就要delete这个对象了,这样就避免了忘记delete对象或者这个对象被delete之后其它地方还在使用的问题了。但是,如何实现这个对象的引用计数呢?肯定不是由开发人员来手动地维护了,要开发人员时刻记住什么时候该对这个对象的引用计数加1,什么时候该对这个对象的引用计数减1,一来是不方便开发,二来是不可靠,一不小心哪里多加了一个1或者多减了一个1,就会造成灾难性的后果。这时候,智能指针就粉墨登场了。首先,智能指针是一个对象,不过这个对象代表的是另外一个真实使用的对象,当智能指针指向实际对象的时候,就是智能指针对象创建的时候,当智能指针不再指向实际对象的时候,就是智能指针对象销毁的时候,我们知道,在C++中,对象的创建和销毁时会分别自动地调用对象的构造函数和析构函数,这样,负责对真实对象的引用计数加1和减1的工作就落实到智能指针对象的构造函数和析构函数的身上了,这也是为什么称这个指针对象为智能指针的原因。
        在计算机科学领域中,提供垃圾收集(Garbage Collection)功能的系统框架,即提供对象托管功能的系统框架,例如Java应用程序框架,也是采用上述的引用计数技术方案来实现的,然而,简单的引用计数技术不能处理系统中对象间循环引用的情况。如:系统中有两个对象A和B,在对象A的内部引用了对象B,而在对象B的内部也引用了对象A。当两个对象A和B都不再使用时,垃圾收集系统会发现无法回收这两个对象的所占据的内存的,因为系统一次只能收集一个对象,而无论系统决定要收回对象A还是要收回对象B时,都会发现这个对象被其它的对象所引用,因而就都回收不了,这样就造成了内存泄漏。这样,就要采取另外的一种引用计数技术了,即对象的引用计数同时存在强引用和弱引用两种计数,例如,Apple公司提出的Cocoa框架,当父对象要引用子对象时,就对子对象使用强引用计数技术,而当子对象要引用父对象时,就对父对象使用弱引用计数技术,而当垃圾收集系统执行对象回收工作时,只要发现对象的强引用计数为0,而不管它的弱引用计数是否为0,都可以回收这个对象,但是,如果我们只对一个对象持有弱引用计数,当我们要使用这个对象时,就不直接使用了,必须要把这个弱引用升级成为强引用时,才能使用这个对象,在转换的过程中,如果对象已经不存在,那么转换就失败了,这时候就说明这个对象已经被销毁了,不能再使用了。

### 轻量级指针

引用计数器类LightRefBase,位置:system/core/include/utils/RefBase.h

```
template <class T>
class LightRefBase
{
public:
    inline LightRefBase() : mCount(0) { }
    inline void incStrong(__attribute__((unused)) const void* id) const {
        mCount.fetch_add(1, std::memory_order_relaxed);
    }
    inline void decStrong(__attribute__((unused)) const void* id) const {
        if (mCount.fetch_sub(1, std::memory_order_release) == 1) {
            std::atomic_thread_fence(std::memory_order_acquire);
            delete static_cast<const T*>(this);
        }
    }
    //! DEBUGGING ONLY: Get current strong ref count.
    inline int32_t getStrongCount() const {
        return mCount.load(std::memory_order_relaxed);
    }

    typedef LightRefBase<T> basetype;

protected:
    inline ~LightRefBase() { }

private:
    friend class ReferenceMover;
    inline static void renameRefs(size_t n, const ReferenceRenamer& renamer) { }
    inline static void renameRefId(T* ref,
            const void* old_id, const void* new_id) { }

private:
    mutable std::atomic<int32_t> mCount;
};
```

`
	unused:This attribute, attached to a function, means that the function is meant to be possibly unused. GCC will not produce a warning for this function
`

此类只有一个成员变量`mCount`,即引用计数器,在构造方法中初始化为0。
此外,提供了incStrong和decStrong方法来操作此计数器的值。在decStrong方法中,若当前mCount的值为1,则delete此对象。

配合LightRefBase引用计数器使用的是sp类,位置:system/core/include/utils/StrongPointer.h

```
template<typename T>
class sp {
public:
    inline sp() : m_ptr(0) { }

    sp(T* other);
    sp(const sp<T>& other);
    sp(sp<T>&& other);
    template<typename U> sp(U* other);
    template<typename U> sp(const sp<U>& other);
    template<typename U> sp(sp<U>&& other);

    ~sp();

    // Assignment

    sp& operator = (T* other);
    sp& operator = (const sp<T>& other);
    sp& operator = (sp<T>&& other);

    template<typename U> sp& operator = (const sp<U>& other);
    template<typename U> sp& operator = (sp<U>&& other);
    template<typename U> sp& operator = (U* other);

    //! Special optimization for use by ProcessState (and nobody else).
    void force_set(T* other);

    // Reset

    void clear();

    // Accessors

    inline  T&      operator* () const  { return *m_ptr; }
    inline  T*      operator-> () const { return m_ptr;  }
    inline  T*      get() const         { return m_ptr; }

    // Operators

    COMPARE(==)
    COMPARE(!=)
    COMPARE(>)
    COMPARE(<)
    COMPARE(<=)
    COMPARE(>=)

private:
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;
    void set_pointer(T* ptr);
    T* m_ptr;
};
```

同样,只看成员变量m_prt、构造函数、析构函数。

```
template<typename T>
sp<T>::sp(T* other)
        : m_ptr(other) {
    if (other)
        other->incStrong(this);
}

template<typename T>
sp<T>::sp(const sp<T>& other)
        : m_ptr(other.m_ptr) {
    if (m_ptr)
        m_ptr->incStrong(this);
}

template<typename T>
sp<T>::sp(sp<T>&& other)
        : m_ptr(other.m_ptr) {
    other.m_ptr = nullptr;
}

template<typename T> template<typename U>
sp<T>::sp(U* other)
        : m_ptr(other) {
    if (other)
        ((T*) other)->incStrong(this);
}

template<typename T> template<typename U>
sp<T>::sp(const sp<U>& other)
        : m_ptr(other.m_ptr) {
    if (m_ptr)
        m_ptr->incStrong(this);
}

template<typename T> template<typename U>
sp<T>::sp(sp<U>&& other)
        : m_ptr(other.m_ptr) {
    other.m_ptr = nullptr;
}
```

构造方法中,都是先初始化m_ptr,然后调用`incStrong`方法增加对象的引用计数。

```
template<typename T>
sp<T>::~sp() {
    if (m_ptr)
        m_ptr->decStrong(this);
}
```

析构函数中,调用`decStrong`方法减少引用计数。

### 强指针

引用计数器类RefBase,所在位置:system/core/include/utils/RefBase.h

```
class RefBase
{
public:
            void            incStrong(const void* id) const;
            void            decStrong(const void* id) const;

            void            forceIncStrong(const void* id) const;

            //! DEBUGGING ONLY: Get current strong ref count.
            int32_t         getStrongCount() const;

    class weakref_type
    {
    public:
        RefBase*            refBase() const;

        void                incWeak(const void* id);
        void                decWeak(const void* id);

        // acquires a strong reference if there is already one.
        bool                attemptIncStrong(const void* id);

        // acquires a weak reference if there is already one.
        // This is not always safe. see ProcessState.cpp and BpBinder.cpp
        // for proper use.
        bool                attemptIncWeak(const void* id);

        //! DEBUGGING ONLY: Get current weak ref count.
        int32_t             getWeakCount() const;

        //! DEBUGGING ONLY: Print references held on object.
        void                printRefs() const;

        //! DEBUGGING ONLY: Enable tracking for this object.
        // enable -- enable/disable tracking
        // retain -- when tracking is enable, if true, then we save a stack trace
        //           for each reference and dereference; when retain == false, we
        //           match up references and dereferences and keep only the
        //           outstanding ones.

        void                trackMe(bool enable, bool retain);
    };

            weakref_type*   createWeak(const void* id) const;

            weakref_type*   getWeakRefs() const;

            //! DEBUGGING ONLY: Print references held on object.
    inline  void            printRefs() const { getWeakRefs()->printRefs(); }

            //! DEBUGGING ONLY: Enable tracking of object.
    inline  void            trackMe(bool enable, bool retain)
    {
        getWeakRefs()->trackMe(enable, retain);
    }

    typedef RefBase basetype;

protected:
                            RefBase();
    virtual                 ~RefBase();

    //! Flags for extendObjectLifetime()
    enum {
        OBJECT_LIFETIME_STRONG  = 0x0000,
        OBJECT_LIFETIME_WEAK    = 0x0001,
        OBJECT_LIFETIME_MASK    = 0x0001
    };

            void            extendObjectLifetime(int32_t mode);

    //! Flags for onIncStrongAttempted()
    enum {
        FIRST_INC_STRONG = 0x0001
    };

    virtual void            onFirstRef();
    virtual void            onLastStrongRef(const void* id);
    virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);
    virtual void            onLastWeakRef(const void* id);

private:
    friend class weakref_type;
    class weakref_impl;

                            RefBase(const RefBase& o);
            RefBase&        operator=(const RefBase& o);

private:
    friend class ReferenceMover;

    static void renameRefs(size_t n, const ReferenceRenamer& renamer);

    static void renameRefId(weakref_type* ref,
            const void* old_id, const void* new_id);

    static void renameRefId(RefBase* ref,
            const void* old_id, const void* new_id);

        weakref_impl* const mRefs;
};
```

与LightRefBase类一样,提供了incStrong和decStrong方法来操作计数器。与LightRefBase不同在于,他没有直接提供一直整型对象来维护计数器,而且通过`weakref_impl`类型的成员变量`mRefs`来维护计数器.

weakref_impl明显为实现类,位置:system/core.libutils/RefBase.cpp

```

class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
    std::atomic<int32_t>    mStrong;
    std::atomic<int32_t>    mWeak;
    RefBase* const          mBase;
    std::atomic<int32_t>    mFlags;
    weakref_impl(RefBase* base)
        : mStrong(INITIAL_STRONG_VALUE)
        , mWeak(0)
        , mBase(base)
        , mFlags(0)
    {
    }
    void addStrongRef(const void* /*id*/) { }
    void removeStrongRef(const void* /*id*/) { }
    void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
    void addWeakRef(const void* /*id*/) { }
    void removeWeakRef(const void* /*id*/) { }
    void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
    void printRefs() const { }
    void trackMe(bool, bool) { }
}
```

以上为release版本的代码,方法均为空方法。
此类中提供了4个成员变量来维护引用计数:

```
	std::atomic<int32_t>    mStrong;
    std::atomic<int32_t>    mWeak;
    RefBase* const          mBase;
    std::atomic<int32_t>    mFlags;
```

其中,`mStrong`为对象的强引用计数,`mWeak`为对象的若引用计数。`mFlags`表示对象引用计数器所使用的策略,他的取值包括:

```
enum {
        OBJECT_LIFETIME_STRONG  = 0x0000,
        OBJECT_LIFETIME_WEAK    = 0x0001,
        OBJECT_LIFETIME_MASK    = 0x0001
    };
```

```
// In the OBJECT_LIFETIME_STRONG case, it is deallocated in the RefBase
// destructor iff the strong reference count was never incremented. The
// destructor can be invoked either from decStrong, or from decWeak if there
// was never a strong reference. If the reference count had been incremented,
// it is deallocated directly in decWeak, and hence still lives as long as
// the last weak reference.
// In the OBJECT_LIFETIME_WEAK case, it is always deallocated from the RefBase
// destructor, which is always invoked by decWeak. DecStrong explicitly avoids
// the deletion in this case.
```

强指针类sp,构造方法的实现:

```
template<typename T>
sp<T>::sp(T* other)
    : m_ptr(other)
{
    if (other) other->incStrong(this);
}
```

other继承RefBase类,incStrong方法的实现:

```
void RefBase::incStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->incWeak(id);

    refs->addStrongRef(id);
    const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);

    if (c != INITIAL_STRONG_VALUE)  {
        return;
    }

    int32_t old = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
            std::memory_order_relaxed);
    // A decStrong() must still happen after us.

    refs->mBase->onFirstRef();
}
```

此方法中主要做了3件事:

1、增加弱引用计数;

```
weakref_impl* const refs = mRefs;
refs->incWeak(id);
```

2、增加强引用计数;

```
refs->addStrongRef(id);
const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
```

3、判断是否为首次调用此对象的incStrong方法,如果是则调用对象的onFirstRef方法,让对象在被首次引用时做其他逻辑;

```
if (c != INITIAL_STRONG_VALUE)  {
        return;
}

int32_t old = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
            std::memory_order_relaxed);
// A decStrong() must still happen after us.

refs->mBase->onFirstRef();
```

即:在构造方法中,强引用、弱引用计数+1。

强指针的析构函数:

```
template<typename T>
sp<T>::~sp() {
    if (m_ptr)
        m_ptr->decStrong(this);
}
```

m_ptr是继承RefBase类的对象,因此看RefBase重的decStrong方法。

```
void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->removeStrongRef(id);
    const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);
    ALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
    if (c == 1) {
        std::atomic_thread_fence(std::memory_order_acquire);
        refs->mBase->onLastStrongRef(id);
        int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            delete this;
            // Since mStrong had been incremented, the destructor did not
            // delete refs.
        }
    }
    // Note that even with only strong reference operations, the thread
    // deallocating this may not be the same as the thread deallocating refs.
    // That's OK: all accesses to this happen before its deletion here,
    // and all accesses to refs happen before its deletion in the final decWeak.
    // The destructor can safely access mRefs because either it's deleting
    // mRefs itself, or it's running entirely before the final mWeak decrement.
    refs->decWeak(id);
}
```

在release版本中,`removeStrongRef`方法为空实现,实现强引用计数器-1的为:

```
const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);
```

-1之前发现强引用计数为1,则表示再没有地方引用此对象了,看flags情况是否删除此对象。

```
if (c == 1) {
        std::atomic_thread_fence(std::memory_order_acquire);
        refs->mBase->onLastStrongRef(id);
        int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            delete this;
            // Since mStrong had been incremented, the destructor did not
            // delete refs.
        }
    }
```

如果当前策略是`OBJECT_LIFETIME_STRONG`,则直接删除此对象,否则执行

```
refs->decWeak(id)
```

decWeak的实现:

```
void RefBase::weakref_type::decWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->removeWeakRef(id);
    const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release);
    ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
    if (c != 1) return;
    atomic_thread_fence(std::memory_order_acquire);

    int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
    if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
        // This is the regular lifetime case. The object is destroyed
        // when the last strong reference goes away. Since weakref_impl
        // outlive the object, it is not destroyed in the dtor, and
        // we'll have to do it here.
        if (impl->mStrong.load(std::memory_order_relaxed)
                == INITIAL_STRONG_VALUE) {
            // Special case: we never had a strong reference, so we need to
            // destroy the object now.
            delete impl->mBase;
        } else {
            // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
            delete impl;
        }
    } else {
        // This is the OBJECT_LIFETIME_WEAK case. The last weak-reference
        // is gone, we can destroy the object.
        impl->mBase->onLastWeakRef(id);
        delete impl->mBase;
    }
}
```

同`removeStrongRef`一样,真正实现若引用计数-1的为:

```
const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release);
```

同时,-1之前判断是否为1,若不为1,则return。

```
if (c != 1) return;
```

如果对象的生命周期是受强引用计数器控制的,则:

```
if (impl->mStrong.load(std::memory_order_relaxed)
                == INITIAL_STRONG_VALUE) {
            // Special case: we never had a strong reference, so we need to
            // destroy the object now.
            delete impl->mBase;
        } else {
            // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
            delete impl;
}
```

在这里分了两种情况:

```
1、强引用计数==INITIAL_STRONG_VALUE
2、强引用计数!=INITIAL_STRONG_VALUE
```

增加对象的弱引用计数有两种方式:

```
1、增加对象的强引用计数时,会同时增加弱引用计数;
2、使用弱指针指向对象,只增加弱引用计数;
```

若为第一种方式,则强引用计数必然为0,!=INITIAL_STRONG_VALUE,则此时不需要删除此对象,因为decStrong方法中会删除此对象,此时只需要删除weakref_impl对象。

```
delete impl->mBase;
```

若为第二种方式,则表示没有地方会删除此对象,因此需要`delete impl`.

即:

```
1、在OBJECT_LIFETIME_STRONG case下,强引用计数==0,delete此对象;
2、在OBJECT_LIFETIME_WEAK case下,强引用计数==0 && 弱引用计数==0,delete此对象。
```

### 弱指针

弱指针使用的引用计数器同强指针,是RefBase类。弱指针的位置:system/core/include/utils/RefBase.h

```
template <typename T>
class wp
{
public:
    typedef typename RefBase::weakref_type weakref_type;

    inline wp() : m_ptr(0) { }

    wp(T* other);
    wp(const wp<T>& other);
    wp(const sp<T>& other);
    template<typename U> wp(U* other);
    template<typename U> wp(const sp<U>& other);
    template<typename U> wp(const wp<U>& other);

    ~wp();

    // Assignment

    wp& operator = (T* other);
    wp& operator = (const wp<T>& other);
    wp& operator = (const sp<T>& other);

    template<typename U> wp& operator = (U* other);
    template<typename U> wp& operator = (const wp<U>& other);
    template<typename U> wp& operator = (const sp<U>& other);

    void set_object_and_refs(T* other, weakref_type* refs);

    // promotion to sp

    sp<T> promote() const;

    // Reset

    void clear();

    // Accessors

    inline  weakref_type* get_refs() const { return m_refs; }

    inline  T* unsafe_get() const { return m_ptr; }

    // Operators

    COMPARE_WEAK(==)
    COMPARE_WEAK(!=)
    COMPARE_WEAK(>)
    COMPARE_WEAK(<)
    COMPARE_WEAK(<=)
    COMPARE_WEAK(>=)

    inline bool operator == (const wp<T>& o) const {
        return (m_ptr == o.m_ptr) && (m_refs == o.m_refs);
    }
    template<typename U>
    inline bool operator == (const wp<U>& o) const {
        return m_ptr == o.m_ptr;
    }

    inline bool operator > (const wp<T>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
    }
    template<typename U>
    inline bool operator > (const wp<U>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
    }

    inline bool operator < (const wp<T>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
    }
    template<typename U>
    inline bool operator < (const wp<U>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
    }
                         inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; }
    template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
                         inline bool operator <= (const wp<T>& o) const { return !operator > (o); }
    template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }
                         inline bool operator >= (const wp<T>& o) const { return !operator < (o); }
    template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }

private:
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;

    T*              m_ptr;
    weakref_type*   m_refs;
};
```

同强指针一样,`m_ptr`变量指向目标对象。此外还有一个`weakref_type`类型的成员变量`m_refs`。

构造函数:

```
template<typename T>
wp<T>::wp(T* other)
    : m_ptr(other)
{
    if (other) m_refs = other->createWeak(this);
}
```

同强指针,`other`是继承自`RefBase`类,看`RefBase`的`createWeak`方法。

```
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
    mRefs->incWeak(id);
    return mRefs;
}
```

`mRefs`为`weakref_impl`的指针,`incWeak`方法即为增加对象的弱引用计数。

```
void RefBase::weakref_type::incWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->addWeakRef(id);
    const int32_t c __unused = impl->mWeak.fetch_add(1,
            std::memory_order_relaxed);
    ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
```

析构函数:

```
template<typename T>
wp<T>::~wp()
{
    if (m_ptr) m_refs->decWeak(this);
}
```

即`RefBase`类的`decWeak`方法,再强指针中已介绍。

弱指针的特点是不能直接操作目标对象,是因为没用重载`*`和`->`两个操作符。下面的是在StrongPointer中重载的操作符:

```
inline  T&      operator* () const  { return *m_ptr; }
inline  T*      operator-> () const { return m_ptr;  }
```

弱指针想要操作目标对象,可升级为强指针,通过如下方法:

```
template<typename T>
sp<T> wp<T>::promote() const
{
    sp<T> result;
    if (m_ptr && m_refs->attemptIncStrong(&result)) {
        result.set_pointer(m_ptr);
    }
    return result;
}
```

`attemptIncStrong`方法:

```
bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
    incWeak(id);

    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    int32_t curCount = impl->mStrong.load(std::memory_order_relaxed);

    ALOG_ASSERT(curCount >= 0,
            "attemptIncStrong called on %p after underflow", this);

    while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
        // we're in the easy/common case of promoting a weak-reference
        // from an existing strong reference.
        if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
                std::memory_order_relaxed)) {
            break;
        }
        // the strong count has changed on us, we need to re-assert our
        // situation. curCount was updated by compare_exchange_weak.
    }

    if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
        // we're now in the harder case of either:
        // - there never was a strong reference on us
        // - or, all strong references have been released
        int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            // this object has a "normal" life-time, i.e.: it gets destroyed
            // when the last strong reference goes away
            if (curCount <= 0) {
                // the last strong-reference got released, the object cannot
                // be revived.
                decWeak(id);
                return false;
            }

            // here, curCount == INITIAL_STRONG_VALUE, which means
            // there never was a strong-reference, so we can try to
            // promote this object; we need to do that atomically.
            while (curCount > 0) {
                if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
                        std::memory_order_relaxed)) {
                    break;
                }
                // the strong count has changed on us, we need to re-assert our
                // situation (e.g.: another thread has inc/decStrong'ed us)
                // curCount has been updated.
            }

            if (curCount <= 0) {
                // promote() failed, some other thread destroyed us in the
                // meantime (i.e.: strong count reached zero).
                decWeak(id);
                return false;
            }
        } else {
            // this object has an "extended" life-time, i.e.: it can be
            // revived from a weak-reference only.
            // Ask the object's implementation if it agrees to be revived
            if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
                // it didn't so give-up.
                decWeak(id);
                return false;
            }
            // grab a strong-reference, which is always safe due to the
            // extended life-time.
            curCount = impl->mStrong.fetch_add(1, std::memory_order_relaxed);
        }

        // If the strong reference count has already been incremented by
        // someone else, the implementor of onIncStrongAttempted() is holding
        // an unneeded reference.  So call onLastStrongRef() here to remove it.
        // (No, this is not pretty.)  Note that we MUST NOT do this if we
        // are in fact acquiring the first reference.
        if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
            impl->mBase->onLastStrongRef(id);
        }
    }

    impl->addStrongRef(id);

    // curCount is the value of mStrong before we increment ed it.
    // Now we need to fix-up the count if it was INITIAL_STRONG_VALUE.
    // This must be done safely, i.e.: handle the case where several threads
    // were here in attemptIncStrong().
    // curCount > INITIAL_STRONG_VALUE is OK, and can happen if we're doing
    // this in the middle of another incStrong.  The subtraction is handled
    // by the thread that started with INITIAL_STRONG_VALUE.
    if (curCount == INITIAL_STRONG_VALUE) {
        impl->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
                std::memory_order_relaxed);
    }

    return true;
}
```

此方法为增加对象的强引用计数,有可能因为目标对象已经被delete掉等原因失败。函数开始,即增加对象的弱引用计数,当之后增加强引用计数失败时,会减少弱引用计数。

```
incWeak(id);
```

增加强引用计数的时候,会有两种情况:

```
1、对象正在被其他强指针引用,即:强引用计数大于0并不等于INITIAL_STRONG_VALUE
2、对象未被其他强指针引用
```

当为第1种情况时,则直接增加其强引用计数:

```
while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
        // we're in the easy/common case of promoting a weak-reference
        // from an existing strong reference.
        if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
                std::memory_order_relaxed)) {
            break;
        }
        // the strong count has changed on us, we need to re-assert our
        // situation. curCount was updated by compare_exchange_weak.
    }
```

当为第2种情况时,会有如下情况:

```
if(目标生命周期受强引用计数器控制){
	if(强引用计数<=0){
		decWeak(id);
		return false;
	}
	增加强引用计数;
	if(强引用计数<=0,即上一步增加失败){
		decWeak(id);
		return false;
	}

}else 目标生命周期受弱引用计数器控制{
	if(目标对象不允许onIncStrongAttempted){
		decWeak(id);
       	return false;
	}
	增加强引用计数;
}
```

对应代码:

```
bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
    if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
        // we're now in the harder case of either:
        // - there never was a strong reference on us
        // - or, all strong references have been released
        int32_t flags = impl->mFlags.load(std::memory_order_relaxed);

        //目标生命周期受强引用计数器控制
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            // this object has a "normal" life-time, i.e.: it gets destroyed
            // when the last strong reference goes away

            //强引用计数<=0
            if (curCount <= 0) {
                // the last strong-reference got released, the object cannot
                // be revived.
                decWeak(id);
                return false;
            }

            // here, curCount == INITIAL_STRONG_VALUE, which means
            // there never was a strong-reference, so we can try to
            // promote this object; we need to do that atomically.

            //强引用计数>0
            while (curCount > 0) {
                if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
                        std::memory_order_relaxed)) {
                    break;
                }
                // the strong count has changed on us, we need to re-assert our
                // situation (e.g.: another thread has inc/decStrong'ed us)
                // curCount has been updated.
            }

			//增加失败
            if (curCount <= 0) {
                // promote() failed, some other thread destroyed us in the
                // meantime (i.e.: strong count reached zero).
                decWeak(id);
                return false;
            }
        } else {
            // this object has an "extended" life-time, i.e.: it can be
            // revived from a weak-reference only.
            // Ask the object's implementation if it agrees to be revived

            //目标对象不允许onIncStrongAttempted
            if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
                // it didn't so give-up.
                decWeak(id);
                return false;
            }
            // grab a strong-reference, which is always safe due to the
            // extended life-time.
            curCount = impl->mStrong.fetch_add(1, std::memory_order_relaxed);
        }

        // If the strong reference count has already been incremented by
        // someone else, the implementor of onIncStrongAttempted() is holding
        // an unneeded reference.  So call onLastStrongRef() here to remove it.
        // (No, this is not pretty.)  Note that we MUST NOT do this if we
        // are in fact acquiring the first reference.
        if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
            impl->mBase->onLastStrongRef(id);
        }
    }

    impl->addStrongRef(id);

    // curCount is the value of mStrong before we increment ed it.
    // Now we need to fix-up the count if it was INITIAL_STRONG_VALUE.
    // This must be done safely, i.e.: handle the case where several threads
    // were here in attemptIncStrong().
    // curCount > INITIAL_STRONG_VALUE is OK, and can happen if we're doing
    // this in the middle of another incStrong.  The subtraction is handled
    // by the thread that started with INITIAL_STRONG_VALUE.
    if (curCount == INITIAL_STRONG_VALUE) {
        impl->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
                std::memory_order_relaxed);
    }

    return true;
}
```


text:
package org.apache.ignite.internal.processors.cache;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.UUID;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.internal.IgniteKernal;
import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;

import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
import static org.apache.ignite.cache.CacheMode.PARTITIONED;

/**
 * Test cases for multi-threaded tests in partitioned cache.
 */
public class GridCacheMvccPartitionedSelfTest extends GridCommonAbstractTest {
    /** Grid. */
    private IgniteKernal grid;

    /** VM ip finder for TCP discovery. */
    private static TcpDiscoveryIpFinder ipFinder = new TcpDiscoveryVmIpFinder(true);

    /**
     *
     */
    public GridCacheMvccPartitionedSelfTest() {
        super(true /*start grid. */);
    }

    /** {@inheritDoc} */
    @Override protected void beforeTest() throws Exception {
        grid = (IgniteKernal)grid();
    }

    /** {@inheritDoc} */
    @Override protected void afterTest() throws Exception {
        grid = null;
    }

    /** {@inheritDoc} */
    @Override protected IgniteConfiguration getConfiguration() throws Exception {
        IgniteConfiguration cfg = super.getConfiguration();

        TcpDiscoverySpi disco = new TcpDiscoverySpi();

        disco.setIpFinder(ipFinder);

        cfg.setDiscoverySpi(disco);

        CacheConfiguration cacheCfg = defaultCacheConfiguration();

        cacheCfg.setCacheMode(PARTITIONED);
        cacheCfg.setBackups(1);
        cacheCfg.setAtomicityMode(TRANSACTIONAL);

        cfg.setCacheConfiguration(cacheCfg);

        return cfg;
    }

    /**
     * Tests remote candidates.
     */
    public void testNearLocalsWithPending() {
        GridCacheAdapter<String, String> cache = grid.internalCache();

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(1);
        GridCacheVersion ver2 = version(2);

        GridCacheMvccCandidate c1 = entry.addRemote(node1, 1, ver1, 0, false, true);
        GridCacheMvccCandidate c2 = entry.addNearLocal(node1, 1, ver2, 0, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(ver2, nearLocCands.iterator().next().version());

        assertEquals(1, rmtCands.size());
        assertEquals(ver1, rmtCands.iterator().next().version());

        entry.readyNearLocal(ver2, ver2, empty(), empty(), Arrays.asList(ver1));

        checkLocalOwner(c2, ver2, false);
        checkRemote(c1, ver1, false, false);

        assertNotNull(entry.anyOwner());
        assertEquals(ver2, entry.anyOwner().version());
    }

    /**
     * Tests remote candidates.
     */
    public void testNearLocalsWithCommitted() {
        GridCacheAdapter<String, String> cache = grid.internalCache();

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(1);
        GridCacheVersion ver2 = version(2);

        GridCacheMvccCandidate c1 = entry.addNearLocal(node1, 1, ver1, 0, true);
        GridCacheMvccCandidate c2 = entry.addRemote(node1, 1, ver2, 0, false, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(ver1, nearLocCands.iterator().next().version());

        assertEquals(1, rmtCands.size());
        assertEquals(ver2, rmtCands.iterator().next().version());

        entry.readyNearLocal(ver1, ver1, Arrays.asList(ver2), empty(), empty());

        checkLocal(c1, ver1, true, false, false);
        checkRemote(c2, ver2, true, false);

        assertNull(entry.anyOwner());
    }

    /**
     * Tests remote candidates.
     */
    public void testNearLocalsWithRolledback() {
        GridCacheAdapter<String, String> cache = grid.internalCache();

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(1);
        GridCacheVersion ver2 = version(2);

        GridCacheMvccCandidate c1 = entry.addNearLocal(node1, 1, ver1, 0, true);
        GridCacheMvccCandidate c2 = entry.addRemote(node1, 1, ver2, 0, false, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(ver1, nearLocCands.iterator().next().version());

        assertEquals(1, rmtCands.size());
        assertEquals(ver2, rmtCands.iterator().next().version());

        entry.readyNearLocal(ver1, ver1, empty(), Arrays.asList(ver2), empty());

        checkLocal(c1, ver1, true, false, false);
        checkRemote(c2, ver2, true, false);

        assertNull(entry.anyOwner());
    }

    /**
     * Tests remote candidates.
     */
    public void testNearLocals() {
        GridCacheAdapter<String, String> cache = grid.internalCache();

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(1);
        GridCacheVersion ver2 = version(2);

        GridCacheMvccCandidate c1 = entry.addNearLocal(node1, 1, ver1, 0, true);
        GridCacheMvccCandidate c2 = entry.addNearLocal(node1, 1, ver2, 0, true);

        entry.readyNearLocal(ver2, ver2,  empty(), empty(), empty());

        checkLocalOwner(c2, ver2, false);
        checkLocal(c1, ver1, false, false, false);

        Collection<GridCacheMvccCandidate> cands = entry.localCandidates();

        assert cands.size() == 2;
        assert cands.iterator().next().version().equals(ver2);

        checkLocalOwner(c2, ver2, false);
        checkLocal(c1, ver1, false, false, false);
    }

    /**
     * Tests remote candidates.
     */
    public void testNearLocalsWithOwned() {
        GridCacheAdapter<String, String> cache = grid.internalCache();

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(1);
        GridCacheVersion ver2 = version(2);

        GridCacheMvccCandidate c1 = entry.addRemote(node1, 1, ver1, 0, false, true);
        GridCacheMvccCandidate c2 = entry.addNearLocal(node1, 1, ver2, 0, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(ver2, nearLocCands.iterator().next().version());

        assertEquals(1, rmtCands.size());
        assertEquals(ver1, rmtCands.iterator().next().version());

        entry.orderOwned(ver1, ver2);

        entry.readyNearLocal(ver2, ver2,  empty(), empty(), empty());

        checkRemote(c1, ver1, false, false);

        assertFalse(c1.owner());

        checkLocalOwner(c2, ver2, false);

        assertNotNull(entry.anyOwner());
        assertEquals(ver2, entry.anyOwner().version());
    }

    /**
     * @throws Exception If failed.
     */
    public void testAddPendingRemote0() throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache();

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver0 = version(0);
        GridCacheVersion ver1 = version(1);

        entry.addNearLocal(node1, 1, ver1, 0, true);

        entry.readyNearLocal(ver1, ver1, empty(), empty(), Collections.singletonList(ver0));

        entry.addRemote(node1, 1, ver0, 0, false, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(ver1, nearLocCands.iterator().next().version());

        assertEquals(1, rmtCands.size());
        assertEquals(ver0, rmtCands.iterator().next().version());

        assertNotNull(entry.anyOwner());
        assertEquals(ver1, entry.anyOwner().version());
    }

    /**
     * @throws Exception If failed.
     */
    public void testAddPendingRemote1() throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache();

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver0 = version(0);
        GridCacheVersion ver1 = version(1);
        GridCacheVersion ver2 = version(2);
        GridCacheVersion ver3 = version(3);

        GridCacheMvccCandidate c3 = entry.addNearLocal(node1, 1, ver3, 0, true);

        entry.readyNearLocal(ver3, ver3, empty(), empty(), Arrays.asList(ver0, ver1, ver2));

        GridCacheMvccCandidate c2 = entry.addRemote(node1, 1, ver2, 0, false, true);
        GridCacheMvccCandidate c1 = entry.addRemote(node1, 1, ver1, 0, false, true);
        GridCacheMvccCandidate c0 = entry.addRemote(node1, 1, ver0, 0, false, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();

        assert rmtCands.size() == 3;

        // DHT remote candidates are not reordered and sorted.
        GridCacheMvccCandidate[] candArr = new GridCacheMvccCandidate[] {c2, c1, c0};

        rmtCands = entry.remoteMvccSnapshot();

        int i = 0;

        for (GridCacheMvccCandidate cand : rmtCands) {
            assert cand == candArr[i] : "Invalid candidate in position " + i;

            i++;
        }

        assertEquals(c3, entry.anyOwner());
    }

    /**
     * @throws Exception If failed.
     */
    public void testAddPendingRemote2() throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache();

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver0 = version(0);
        GridCacheVersion ver1 = version(1);
        GridCacheVersion ver2 = version(2);
        GridCacheVersion ver3 = version(3);

        GridCacheMvccCandidate c3 = entry.addNearLocal(node1, 1, ver3, 0, true);
        entry.addNearLocal(node1, 1, ver2, 0, true);

        entry.readyNearLocal(ver3, ver3, empty(), empty(), Arrays.asList(ver0, ver1, ver2));

        GridCacheMvccCandidate c1 = entry.addRemote(node1, 1, ver1, 0, false, true);
        GridCacheMvccCandidate c0 = entry.addRemote(node1, 1, ver0, 0, false, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();

        assertEquals(2, rmtCands.size());

        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(2, nearLocCands.size());

        GridCacheMvccCandidate[] candArr = new GridCacheMvccCandidate[] {c1, c0};

        int i = 0;

        for (GridCacheMvccCandidate cand : rmtCands) {
            assert cand == candArr[i] : "Invalid candidate in position " + i;

            i++;
        }

        assertEquals(c3, entry.anyOwner());
    }

    /**
     * Tests salvageRemote method
     */
    public void testSalvageRemote() {
        GridCacheAdapter<String, String> cache = grid.internalCache();

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(1);
        GridCacheVersion ver2 = version(2);
        GridCacheVersion ver3 = version(3);
        GridCacheVersion ver4 = version(4);
        GridCacheVersion ver5 = version(5);
        GridCacheVersion ver6 = version(6);

        entry.addRemote(node1, 1, ver1, 0, false, true);
        entry.addRemote(node1, 1, ver2, 0, false, true);
        GridCacheMvccCandidate c3 = entry.addNearLocal(node1, 1, ver3, 0, true);
        GridCacheMvccCandidate c4 = entry.addRemote(node1, 1, ver4, 0, false, true);
        entry.addRemote(node1, 1, ver5, 0, false, true);
        entry.addRemote(node1, 1, ver6, 0, false, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();

        assertEquals(5, rmtCands.size());
        assertEquals(ver1, rmtCands.iterator().next().version());

        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(ver3, nearLocCands.iterator().next().version());

        entry.salvageRemote(ver4);

        rmtCands = entry.remoteMvccSnapshot();

        boolean before = true;

        for (GridCacheMvccCandidate cand : rmtCands) {
            if (cand == c4) {
                before = false;

                continue;
            }

            if (before && cand != c3) {
                assertTrue(cand.owner());
                assertTrue(cand.used());
            }
            else {
                assertFalse(cand.owner());
                assertFalse(cand.used());
            }
        }
    }

    /**
     * @throws Exception If failed.
     */
    public void testNearRemoteConsistentOrdering0() throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache();

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(10);
        GridCacheVersion nearVer2 = version(5);
        GridCacheVersion ver2 = version(20);
        GridCacheVersion ver3 = version(30);

        entry.addRemote(node1, 1, ver1, 0, false, true);
        entry.addNearLocal(node1, 1, nearVer2, 0, true);
        entry.addRemote(node1, 1, ver3, 0, false, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(nearVer2, nearLocCands.iterator().next().version());

        assertEquals(2, rmtCands.size());
        assertEquals(ver1, rmtCands.iterator().next().version());

        entry.readyNearLocal(nearVer2, ver2, empty(), empty(), empty());

        assertNull(entry.anyOwner());

        rmtCands = entry.remoteMvccSnapshot();

        assertEquals(ver1, rmtCands.iterator().next().version());
        assertTrue(rmtCands.iterator().next().owner());
    }

    /**
     * @throws Exception If failed.
     */
    public void testNearRemoteConsistentOrdering1() throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache();

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(10);
        GridCacheVersion nearVer2 = version(5);
        GridCacheVersion ver2 = version(20);
        GridCacheVersion ver3 = version(30);

        entry.addRemote(node1, 1, ver1, 0, false, true);
        entry.addNearLocal(node1, 1, nearVer2, 0, true);
        entry.addRemote(node1, 1, ver3, 0, false, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(nearVer2, nearLocCands.iterator().next().version());

        assertEquals(2, rmtCands.size());
        assertEquals(ver1, rmtCands.iterator().next().version());

        entry.orderCompleted(nearVer2, Arrays.asList(ver3), empty());
        entry.readyNearLocal(nearVer2, ver2, empty(), empty(), Arrays.asList(ver1));

        nearLocCands = entry.localCandidates();
        rmtCands = entry.remoteMvccSnapshot();

        assertNull(entry.anyOwner());
        assertEquals(ver3, rmtCands.iterator().next().version());
        assertTrue(rmtCands.iterator().next().owner());

        GridCacheMvccCandidate cand = nearLocCands.iterator().next();

        assertTrue(cand.ready());
        assertFalse(cand.owner());
        assertFalse(cand.used());
    }

    /**
     * @throws Exception If failed.
     */
    public void testNearRemoteConsistentOrdering2() throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache();

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(10);
        GridCacheVersion nearVer2 = version(5);
        GridCacheVersion ver2 = version(20);
        GridCacheVersion ver3 = version(30);

        entry.addRemote(node1, 1, ver1, 0, false, true);
        entry.addNearLocal(node1, 1, nearVer2, 0, true);
        entry.addRemote(node1, 1, ver3, 0, false, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(nearVer2, nearLocCands.iterator().next().version());

        assertEquals(2, rmtCands.size());
        assertEquals(ver1, rmtCands.iterator().next().version());

        entry.orderCompleted(nearVer2, empty(), empty());
        entry.readyNearLocal(nearVer2, ver2, empty(), empty(), empty());

        nearLocCands = entry.localCandidates();
        rmtCands = entry.remoteMvccSnapshot();

        assertNull(entry.anyOwner());
        assertEquals(ver1, rmtCands.iterator().next().version());
        assertTrue(rmtCands.iterator().next().owner());

        GridCacheMvccCandidate cand = nearLocCands.iterator().next();

        assertTrue(cand.ready());
        assertFalse(cand.used());
        assertFalse(cand.owner());
    }

    /**
     * @throws Exception If failed.
     */
    public void testNearRemoteConsistentOrdering3() throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache();

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(10);
        GridCacheVersion nearVer2 = version(5);
        GridCacheVersion ver2 = version(20);
        GridCacheVersion ver3 = version(30);

        entry.addRemote(node1, 1, ver1, 0, false, true);
        entry.addNearLocal(node1, 1, nearVer2, 0, true);
        entry.addRemote(node1, 1, ver3, 0, false, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(nearVer2, nearLocCands.iterator().next().version());

        assertEquals(2, rmtCands.size());
        assertEquals(ver1, rmtCands.iterator().next().version());

        entry.orderCompleted(nearVer2, empty(), empty());
        entry.readyNearLocal(nearVer2, ver2, empty(), empty(), Arrays.asList(ver1));

        rmtCands = entry.remoteMvccSnapshot();

        assertNotNull(entry.anyOwner());
        checkLocalOwner(entry.anyOwner(), nearVer2, false);

        assertEquals(ver1, rmtCands.iterator().next().version());
    }

    /**
     * @throws Exception If failed.
     */
    public void testSerializableLocks() throws Exception {
        checkSerializableAdd(false);

        checkSerializableAdd(true);

        checkNonSerializableConflict();
    }

    /**
     * @throws Exception If failed.
     */
    private void checkNonSerializableConflict() throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache();

        UUID nodeId = UUID.randomUUID();

        GridCacheMvcc mvcc = new GridCacheMvcc(cache.context());

        GridCacheTestEntryEx e = new GridCacheTestEntryEx(cache.context(), "1");

        GridCacheMvccCandidate cand1 = mvcc.addLocal(e,
            nodeId,
            null,
            1,
            version(1),
            0,
            null,
            false,
            true,
            false,
            true
        );

        assertNotNull(cand1);

        GridCacheMvccCandidate cand2 = mvcc.addLocal(e,
            nodeId,
            null,
            1,
            version(2),
            0,
            new GridCacheVersion(0, 0, 30, 1),
            false,
            true,
            false,
            true
        );

        assertNull(cand2);
    }

    /**
     * @param incVer If {@code true} lock version is incremented.
     * @throws Exception If failed.
     */
    private void checkSerializableAdd(boolean incVer) throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache();

        UUID nodeId = UUID.randomUUID();

        GridCacheMvcc mvcc = new GridCacheMvcc(cache.context());

        GridCacheTestEntryEx e = new GridCacheTestEntryEx(cache.context(), "1");

        GridCacheVersion serOrder1 = new GridCacheVersion(0, 0, 10, 1);
        GridCacheVersion serOrder2 = new GridCacheVersion(0, 0, 20, 1);
        GridCacheVersion serOrder3 = new GridCacheVersion(0, 0, 15, 1);
        GridCacheVersion serOrder4 = new GridCacheVersion(0, 0, 30, 1);

        GridCacheVersion ver1 = incVer ? version(1) : version(4);
        GridCacheVersion ver2 = incVer ? version(2) : version(3);
        GridCacheVersion ver3 = incVer ? version(3) : version(2);
        GridCacheVersion ver4 = incVer ? version(4) : version(1);

        GridCacheMvccCandidate cand1 = mvcc.addLocal(e,
            nodeId,
            null,
            1,
            ver1,
            0,
            serOrder1,
            false,
            true,
            false,
            true
            );

        assertNotNull(cand1);

        GridCacheMvccCandidate cand2 = mvcc.addLocal(e,
            nodeId,
            null,
            2,
            ver2,
            0,
            serOrder2,
            false,
            true,
            false,
            true
        );

        assertNotNull(cand2);

        GridCacheMvccCandidate cand3 = mvcc.addLocal(e,
            nodeId,
            null,
            3,
            ver3,
            0,
            serOrder3,
            false,
            true,
            false,
            true
        );

        assertNull(cand3);

        GridCacheMvccCandidate cand4 = mvcc.addLocal(e,
            nodeId,
            null,
            4,
            ver4,
            0,
            serOrder4,
            false,
            true,
            false,
            true
        );

        assertNotNull(cand4);

        GridCacheMvccCandidate owner = mvcc.recheck();

        assertNull(owner);

        cand2.setReady();

        owner = mvcc.recheck();

        assertNull(owner);

        cand1.setReady();

        owner = mvcc.recheck();

        assertSame(cand1, owner);

        owner = mvcc.recheck();

        assertSame(cand1, owner);

        mvcc.remove(cand1.version());

        owner = mvcc.recheck();

        assertSame(cand2, owner);
    }

    /**
     * Gets version based on order.
     *
     * @param order Order.
     * @return Version.
     */
    private GridCacheVersion version(int order) {
        return new GridCacheVersion(1, 0, order, order, 0);
    }

    /**
     * Creates an empty list of {@code GridCacheVersion}.
     *
     * @return Empty list.
     */
    private Collection<GridCacheVersion> empty() {
        return Collections.emptyList();
    }

    /**
     * Checks flags on local owner candidate.
     *
     * @param cand Candidate to check.
     * @param ver Cache version.
     * @param reentry Reentry flag.
     */
    private void checkLocalOwner(GridCacheMvccCandidate cand, GridCacheVersion ver, boolean reentry) {
        assert cand != null;

        info("Done candidate: " + cand);

        assert cand.version().equals(ver);

        // Check flags.
        assert cand.reentry() == reentry;

        assert !cand.used();

        assert cand.ready();
        assert cand.owner();
        assert cand.local();
    }

    /**
     * @param cand Candidate to check.
     * @param ver Version.
     * @param owner Owner flag.
     * @param used Done flag.
     */
    private void checkRemote(GridCacheMvccCandidate cand, GridCacheVersion ver, boolean owner, boolean used) {
        assert cand != null;

        info("Done candidate: " + cand);

        assert cand.version().equals(ver);

        // Check flags.
        assert cand.used() == used;
        assert cand.owner() == owner;

        assert !cand.ready();
        assert !cand.reentry();
        assert !cand.local();
    }

    /**
     * Checks flags on local candidate.
     *
     * @param cand Candidate to check.
     * @param ver Cache version.
     * @param ready Ready flag.
     * @param owner Lock owner.
     * @param reentry Reentry flag.
     */
    private void checkLocal(GridCacheMvccCandidate cand, GridCacheVersion ver, boolean ready,
        boolean owner, boolean reentry) {
        assert cand != null;

        info("Done candidate: " + cand);

        assert cand.version().equals(ver);

        // Check flags.
        assert cand.ready() == ready;
        assert cand.owner() == owner;
        assert cand.reentry() == reentry;

        assert !cand.used();

        assert cand.local();
    }
}


text:
DarksendConfig::DarksendConfig(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::DarksendConfig),
    model(0)
{
    ui->setupUi(this);

    connect(ui->buttonBasic, SIGNAL(clicked()), this, SLOT(clickBasic()));
    connect(ui->buttonHigh, SIGNAL(clicked()), this, SLOT(clickHigh()));
    connect(ui->buttonMax, SIGNAL(clicked()), this, SLOT(clickMax()));
}

DarksendConfig::~DarksendConfig()
{
    delete ui;
}

void DarksendConfig::setModel(WalletModel *model)
{
    this->model = model;
}

void DarksendConfig::clickBasic()
{
    configure(true, 1000, 2);

    QString strAmount(BitcoinUnits::formatWithUnit(
        model->getOptionsModel()->getDisplayUnit(), 1000 * COIN));
    QMessageBox::information(this, tr("Darksend Configuration"),
        tr(
            "Darksend was successfully set to basic (%1 and 2 rounds). You can change this at any time by opening Fortcoin's configuration screen."
        ).arg(strAmount)
    );

    close();
}

void DarksendConfig::clickHigh()
{
    configure(true, 1000, 8);

    QString strAmount(BitcoinUnits::formatWithUnit(
        model->getOptionsModel()->getDisplayUnit(), 1000 * COIN));
    QMessageBox::information(this, tr("Darksend Configuration"),
        tr(
            "Darksend was successfully set to high (%1 and 8 rounds). You can change this at any time by opening Fortcoin's configuration screen."
        ).arg(strAmount)
    );

    close();
}

void DarksendConfig::clickMax()
{
    configure(true, 1000, 16);

    QString strAmount(BitcoinUnits::formatWithUnit(
        model->getOptionsModel()->getDisplayUnit(), 1000 * COIN));
    QMessageBox::information(this, tr("Darksend Configuration"),
        tr(
            "Darksend was successfully set to maximum (%1 and 16 rounds). You can change this at any time by opening Fortcoin's configuration screen."
        ).arg(strAmount)
    );

    close();
}

void DarksendConfig::configure(bool enabled, int coins, int rounds) {

    QSettings settings;

    settings.setValue("nDarksendRounds", rounds);
    settings.setValue("nAnonymizeFortcoinAmount", coins);

    nDarksendRounds = rounds;
    nAnonymizeFortcoinAmount = coins;
}


text:
package com.github.groovylabs.lyre.engine.APIx.websocket.listeners;

import com.github.groovylabs.lyre.config.LyreProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.messaging.SessionSubscribeEvent;

@Component
public class StompSubscribeEventListener implements ApplicationListener<SessionSubscribeEvent> {

    private static final Logger LOGGER = LoggerFactory.getLogger(StompSubscribeEventListener.class);

    @Autowired
    private LyreProperties lyreProperties;

    @Override
    public void onApplicationEvent(SessionSubscribeEvent sessionSubscribeEvent) {
        StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(sessionSubscribeEvent.getMessage());

        if (lyreProperties.isDebug())
            LOGGER.info(headerAccessor.toString());
    }
}


text:
def whyrun_supported?
  true
end

use_inline_resources

action :create do
  template "/etc/fail2ban/jail.d/50-#{new_resource.name}.conf" do
    cookbook "fail2ban"
    source "jail.erb"
    owner "root"
    group "root"
    mode 0o644
    variables :name => new_resource.name,
              :filter => new_resource.filter,
              :logpath => new_resource.logpath,
              :protocol => new_resource.protocol,
              :ports => new_resource.ports,
              :maxretry => new_resource.maxretry
  end
end

action :delete do
  file "/etc/fail2ban/jail.d/50-#{new_resource.name}.conf" do
    action :delete
  end
end


text:
'use strict';

process.on('uncaughtException', function (err) {
  if (err.message === 'oops') {
    console.log("ok got expected message: %s", err.message);
  }
  else {
    throw err;
  }
});

var cls = require('../context.js');
var ns = cls.createNamespace('x');
ns.run(function () { throw new Error('oops'); });


text:
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"

	"github.com/gofiber/fiber/v2"
)

const uploadPath = "./uploads"

var config appConfig

func main() {
	// Load config
	if err := loadConfig("config.json"); err != nil {
		log.Fatalf("failed to load config: %v", err)
	}

	// Create upload directory if it doesn't exist
	if err := os.MkdirAll(uploadPath, 0755); err != nil {
		log.Fatalf("failed to create upload directory: %v", err)
	}

	app := fiber.New()

	// Authentication middleware
	app.Use(authenticate)

	// Upload route
	app.Post("/", func(c *fiber.Ctx) error {
		user := c.Locals("user").(appUser)

		// Get file from form
		file, err := c.FormFile("data")
		if err != nil {
			return c.SendStatus(fiber.StatusBadRequest)
		}

		// Get file extension by Content-Type
		contentType := file.Header.Get(fiber.HeaderContentType)
		ext := getFileExtensionByType(contentType)
		if ext == "" {
			return c.SendStatus(fiber.StatusBadRequest)
		}

		// Build final file name
		fileName := user.Prefix + randomString(4) + ext

		// Save file
		if err := c.SaveFile(file, fmt.Sprintf("%s/%s", uploadPath, fileName)); err != nil {
			return c.SendStatus(fiber.StatusInternalServerError)
		}

		return c.SendString(fmt.Sprintf("%s/%s", config.BaseURL, fileName))
	})

	log.Fatal(app.Listen(":3000"))
}

func authenticate(c *fiber.Ctx) error {
	// Get Authorization header
	auth := c.Get(fiber.HeaderAuthorization)
	if len(auth) == 0 {
		return c.SendStatus(fiber.StatusUnauthorized)
	}

	// Find user
	for _, user := range config.Users {
		if user.Token == auth {
			c.Locals("user", user)
			return c.Next()
		}
	}

	return c.SendStatus(fiber.StatusUnauthorized)
}

func loadConfig(filename string) error {
	f, err := os.Open(filename)
	if err != nil {
		return err
	}
	defer f.Close()

	return json.NewDecoder(f).Decode(&config)
}