blob: a40df451e4f3c03521a74c8ae31c96d6501620dc [file]
/****************************************************************************
* apps/examples/fdpicxip/modules/libshape/libshape.cpp
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/* A C++ shared library, executed in place out of flash.
*
* The point of this file is g_registry. It is a global object with a real
* constructor, and the constructor is the only thing that ever writes
* m_magic. If the loader does not walk DT_INIT_ARRAY, the object simply
* stays in .bss and every field reads back zero -- the library still loads,
* still links, and still runs, and quietly answers wrong. That is why the
* demo checks for a magic rather than just printing a total: the failure
* this is here to catch does not announce itself.
*
* m_total is the second half: it lives in the library's writable segment,
* of which there is one. A library named in DT_NEEDED is opened with
* dlopen(), which returns the object already in the module registry, so
* two tasks naming this library share its data as well as its
* flash-resident code, and m_total ends up counting both of them.
*/
#include <nuttx/compiler.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#define SHAPE_MAGIC 0x5ba9e0
class Registry
{
public:
Registry() : m_magic(SHAPE_MAGIC), m_total(0), m_adds(0)
{
m_marker[0] = '\0';
syslog(LOG_INFO, " [libshape] Registry() ran\n");
}
/* Runs last of the two objects, because destruction mirrors construction
* and this library was constructed first. So a marker written here is
* evidence that the whole DT_FINI_ARRAY chain ran, not just the module's
* half -- which is why the marker is written from the library rather than
* from the module that knows the path.
*/
~Registry()
{
syslog(LOG_INFO, " [libshape] ~Registry() ran after %d adds\n", m_adds);
if (m_marker[0] != '\0')
{
char text[16];
int len;
int fd;
len = snprintf(text, sizeof(text), "%d", m_total);
fd = open(m_marker, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd >= 0)
{
/* xipfs wants the size declared up front so it can reserve one
* contiguous extent.
*/
if (ftruncate(fd, len) >= 0)
{
write(fd, text, len);
}
close(fd);
}
else
{
syslog(LOG_INFO, " [libshape] marker %s failed\n", m_marker);
}
}
}
/* Where ~Registry() should record its final total. Optional: the demo
* does not set one and simply logs instead.
*/
void marker(const char *path)
{
strlcpy(m_marker, path, sizeof(m_marker));
}
bool constructed() const
{
return m_magic == SHAPE_MAGIC;
}
int add(int by)
{
m_adds++;
m_total += by;
return m_total;
}
int total() const
{
return m_total;
}
private:
int m_magic;
int m_total;
int m_adds;
char m_marker[64];
};
static Registry g_registry;
/* C linkage, because the module imports these by name and the loader
* matches dynamic symbols as plain strings.
*/
extern "C"
{
visibility_default int shape_add(int by);
visibility_default int shape_total(void);
visibility_default bool shape_constructed(void);
visibility_default void shape_marker(const char *path);
}
int shape_add(int by)
{
return g_registry.add(by);
}
void shape_marker(const char *path)
{
g_registry.marker(path);
}
int shape_total(void)
{
return g_registry.total();
}
bool shape_constructed(void)
{
return g_registry.constructed();
}