blob: c74463af317338a3b24304690c3c298f0815fe92 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "job.h"
#include <string.h>
#include <fbl/algorithm.h>
#include <zircon/status.h>
#include <zircon/syscalls.h>
#include <zx/handle.h>
#include <zxcpp/new.h>
#include "macros.h"
using fbl::unique_ptr;
zx_status_t Job::Create(zx_koid_t koid, zx_handle_t handle,
const char* name, importance_t importance,
const Job* parent, unique_ptr<Job>* out) {
zx::handle job{zx::handle(handle)};
// Importance keys have the form:
// <capped-importance> ':' <importance-chain> '~'
//
// See job.h for details.
//
// Example values:
// 32:c8c8c896c83264~
// 96:c8c8c8c896~
// c8:c8~
unique_ptr<char[]> ik; // Importance key.
fbl::AllocChecker ac;
importance_t capped_importance;
if (parent == nullptr) {
capped_importance = importance;
const size_t ik_len = sizeof("xx:xx~");
ik.reset(new (&ac) char[ik_len]);
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
ZX_DEBUG_ASSERT(importance <= 0xff); // Generate two characters
snprintf(ik.get(), ik_len, "%02x:%02x~",
capped_importance, importance);
} else {
capped_importance = fbl::min(importance, parent->capped_importance());
// Make sure our parent's importance key (PIK) has the expected
// structure so we can safely use substrings of it.
const char* pik = parent->importance_key();
const size_t pik_len = strlen(pik);
ZX_DEBUG_ASSERT(pik_len >= 4);
ZX_DEBUG_ASSERT(pik[2] == ':');
ZX_DEBUG_ASSERT(pik[pik_len - 1] == '~');
// Our importance key (IK) will add two characters to our parent's
// importance key.
const size_t ik_len = pik_len + 2 + 1;
ik.reset(new (&ac) char[ik_len]);
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
// Generate our importance key.
const char* pik_substr = pik + 3; // Skip leading 'xx:'
const size_t pik_substr_len = pik_len - 4; // And skip trailing '~'
ZX_DEBUG_ASSERT(importance <= 0xff); // Generate two characters
snprintf(ik.get(), ik_len, "%02x:%.*s%02x~",
capped_importance,
static_cast<int>(pik_substr_len), pik_substr,
importance);
}
unique_ptr<char[]> namep;
namep.reset(new (&ac) char[strlen(name) + 1]);
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
strcpy(namep.get(), name);
// Create and return the actual Job.
out->reset(new (&ac) Job(koid, job.release(), fbl::move(namep),
importance, capped_importance, fbl::move(ik)));
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
return ZX_OK;
}
Job::Job(zx_koid_t koid, zx_handle_t handle,
unique_ptr<char[]> name, importance_t importance,
importance_t capped_importance, unique_ptr<char[]> importance_key)
: koid_(koid), handle_(handle), name_(fbl::move(name)),
importance_(importance), capped_importance_(capped_importance),
importance_key_(fbl::move(importance_key)) {
}
Job::~Job() {
if (handle_ != ZX_HANDLE_INVALID) {
zx_handle_close(handle_);
}
}
void sort_jobs_by_importance_key(Job::List *jobs) {
Job::List sorted;
// Insertion-sort |jobs| into |sorted|, then swap the lists before
// returning.
// TODO(dbort): This goes quadratic easily; Mergesort would be better.
while (!jobs->is_empty()) {
unique_ptr<Job> job(fbl::move(jobs->pop_front()));
if (sorted.is_empty()) {
sorted.push_front(fbl::move(job));
} else {
auto iter = sorted.begin();
while (iter != sorted.end()) {
int cmp = strcmp(iter->importance_key(), job->importance_key());
if (cmp >= 0) {
// The current item is of greater or equal importance to us;
// insert before it.
sorted.insert(iter, fbl::move(job));
break;
}
iter++;
}
if (job != nullptr) {
// Most important job.
sorted.push_back(fbl::move(job));
}
}
}
jobs->swap(sorted);
}