Toon posts:

[C++] Een object retourneren in een PHP extensie

Pagina: 1
Acties:

Onderwerpen


  • Snow_King
  • Registratie: April 2001
  • Laatst online: 08:11

Snow_King

Konijn is stoer!

Topicstarter
Hallo,

Ik heb bezig om een PHP extensie te (her)schrijven voor RADOS, een onderdeel van Ceph.

Ik zal gelijk maar aangeven, heel erg bedreven ben ik nog niet met C++, maar ik vind een extensie schrijven wel een uitdaging.

Het probleem zit hem in het volgende stukje, laat ik eerst uitschrijven hoe dat in C++ gaat:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "rados/librados.hpp"

using namespace librados;

int main(int argc, const char **argv)
{
  Rados rados;
  IoCtx io_ctx;

  rados.init(NULL);
  rados.conf_read_file("/etc/ceph/ceph.conf");
  rados.connect();

  rados.ioctx_create("data", io_ctx);
  io_ctx.set_auid(0);
}


Hiermee open ik de pool "data" om daar vervolgens dmv van de IoCTX mee aan de slag te gaan.

Nu ben ik echter bezig met een PHP extensie en kan ik dus niet zo maar een object retourneren, deze moet je registreren waarna het PHP script een resource terug krijgt.

Daar heb ik nu het volgende voor gemaakt, echter gaat dit onderuit met een segfault.

Ik post niet mijn gehele extensie, maar de delen die volgens mij relevant zijn:

C: php_rados.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#ifndef PHP_RADOS_H
#define PHP_RADOS_H

#define PHP_RADOS_EXTNAME  "rados"
#define PHP_RADOS_EXTVER   "0.9.1"

extern "C" {
#include "php.h"
#include "php_ini.h"
#include "zend_exceptions.h"
#include "ext/standard/info.h"
#ifdef ZTS
#include "TSRM.h"
#endif
}

#include <rados/librados.hpp>
using namespace librados;

#define PHP_RADOS_POOL_RES_NAME "RADOS Pool"
#define PHP_RADOS_LISTCTX_RES_NAME "RADOS List CTX"
/** FIXME Should correspond with librados! */
#define PHP_RADOS_POOL_MAX_LENGTH 128
#define PHP_RADOS_MAX_OBJECTS 1024

struct rados_object
{
    zend_object std;
    Rados *rados;
    bool initialized;
    std::vector<const char*> argv;

    rados_object() :
    initialized(false),
    argv(NULL)
    {}
};

PHP_MINIT_FUNCTION(rados);
PHP_MSHUTDOWN_FUNCTION(rados);
PHP_MINFO_FUNCTION(rados);

PHP_METHOD(Rados, __construct);
PHP_METHOD(Rados, init);
..
..
PHP_METHOD(Rados, ioctx_create);

extern zend_module_entry rados_module_entry;
#define phpext_rados_ptr &rados_module_entry;

extern const zend_function_entry php_rados_ioctx_methods[];

#endif


C++: rados.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <sstream>
#include <vector>

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php_rados.h"
#include "ioctx.h"

zend_object_handlers rados_object_handlers;
zend_object_handlers rados_ioctx_object_handlers;

zend_class_entry *rados_rados_ce;
zend_class_entry *rados_radosexception_ce;
zend_class_entry *rados_radosioctx_ce;

...
...
...

const zend_function_entry rados_rados_methods[] = {
    PHP_ME(Rados, __construct, arginfo_rados___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
    ...
    ...
    PHP_ME(Rados, ioctx_create, arginfo_rados_ioctx_create, ZEND_ACC_PUBLIC)
    {NULL, NULL, NULL}
};

...
...
...

PHP_METHOD(Rados, ioctx_create)
{
    char *name = NULL;
    int name_len = 0;
    IoCtx pioctx;
    struct radosioctx_object *riob;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
        RETURN_NULL();
    }

    rados_object *obj = (rados_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
    if (obj->rados->ioctx_create(name, pioctx) < 0) {
        RETURN_FALSE;
    }

    if (object_init_ex(return_value, rados_radosioctx_ce) != SUCCESS) {
        RETURN_FALSE;
    }

    riob = (struct radosioctx_object *) zend_object_store_get_object(return_value TSRMLS_CC);
    riob->ioctx = &pioctx;
}

PHP_MINIT_FUNCTION(rados)
{
    zend_class_entry ce;

    INIT_CLASS_ENTRY(ce, "Rados", rados_rados_methods);
    rados_rados_ce = zend_register_internal_class(&ce TSRMLS_CC);
    rados_rados_ce->create_object = rados_create_handler;
    memcpy(&rados_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    rados_object_handlers.clone_obj = NULL;

    INIT_CLASS_ENTRY(ce, "RadosException", php_rados_radosexception_methods);
    rados_radosexception_ce = zend_register_internal_class_ex(&ce, zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC);
    rados_radosexception_ce->ce_flags |= ZEND_ACC_FINAL;
    zend_declare_property_long(rados_radosexception_ce, "code", sizeof("code")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC);

    INIT_CLASS_ENTRY(ce, "RadosIoCtx", php_rados_ioctx_methods);
    rados_radosioctx_ce = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
    rados_radosioctx_ce->ce_flags |= ZEND_ACC_FINAL;
    memcpy(&rados_ioctx_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    rados_ioctx_object_handlers.clone_obj = NULL;

    return SUCCESS;
}

...
...

#ifdef COMPILE_DL_RADOS
extern "C" {
    ZEND_GET_MODULE(rados)
}
#endif


Ik test vervolgens met het volgende PHP script:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

$r = new Rados();
$r->init();
$r->conf_read_file('ceph.conf');
$r->connect();

$io = $r->ioctx_create("data");
$io->set_auid(0);

$r->shutdown();

?>


Dit levert me een segfault op, GDB vertelt me:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
(gdb) run testrados.php
Starting program: /usr/bin/php testrados.php
[Thread debugging using libthread_db enabled]
[New Thread 0x7fffed04e700 (LWP 14354)]
[Thread 0x7fffed04e700 (LWP 14354) exited]
[New Thread 0x7fffed04e700 (LWP 14355)]
[New Thread 0x7fffec84d700 (LWP 14356)]
[New Thread 0x7fffec04c700 (LWP 14357)]
[New Thread 0x7fffeb84b700 (LWP 14358)]
[New Thread 0x7fffeb04a700 (LWP 14359)]
[New Thread 0x7fffeaf49700 (LWP 14360)]
[New Thread 0x7fffeae48700 (LWP 14361)]

Program received signal SIGSEGV, Segmentation fault.
Objecter::change_pool_auid (this=0x0, pool=-136073112, onfinish=0x1047800, auid=0) at osdc/Objecter.cc:1063
warning: Source file is more recent than executable.
1063      op->tid = ++last_tid;
(gdb) bt
#0  Objecter::change_pool_auid (this=0x0, pool=-136073112, onfinish=0x1047800, auid=0) at osdc/Objecter.cc:1063
#1  0x00007fffee9469d9 in librados::RadosClient::pool_change_auid (this=0x7ffff7e3b390, io=<value optimized out>, auid=0) at librados.cc:1116
#2  0x00007fffeeca44fa in zim_RadosIoCtx_set_auid (ht=<value optimized out>, return_value=0x1019fd8, return_value_ptr=<value optimized out>, this_ptr=0x1018118, return_value_used=<value optimized out>)
    at /home/employee/wido/repos/phprados/ioctx.cc:45
#3  0x00000000006e876a in zend_do_fcall_common_helper_SPEC (execute_data=0x7ffff7e3b068) at /build/buildd/php5-5.3.2/Zend/zend_vm_execute.h:313
#4  0x00000000006bf870 in execute (op_array=0x1018ba0) at /build/buildd/php5-5.3.2/Zend/zend_vm_execute.h:104
#5  0x00000000006972bd in zend_execute_scripts (type=0, retval=0x7fffffffbfd0, file_count=3) at /build/buildd/php5-5.3.2/Zend/zend.c:1266
#6  0x0000000000642e88 in php_execute_script (primary_file=0x7ffff5605e40) at /build/buildd/php5-5.3.2/main/main.c:2288
#7  0x0000000000728886 in main (argc=0, argv=0x1) at /build/buildd/php5-5.3.2/sapi/cli/php_cli.c:1196
(gdb)


Ik word daar persoonlijk niet veel wijzer van. Mijn gevoel zegt dat de IoCTX klasse niet volledig alle informatie heeft om met het RADOS cluster te verbinden, maar dat zou moeten komen doordat de PHP extensie hier iets niet goed doet.

Het zelfde stukje code werkt in C++ prima, dat is het probleem niet.

Heeft iemand enig idee wat hier aan kan schorten?

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03 21:53

MLM

aka Zolo

Ik ben geen guru mbt GDB (of GCC/linux for that matter), maar in je stackframe #0 staat een this pointer van 0, dat is een veelvoorkomende oorzaak van een access violation/segfault

-niks-


  • Snow_King
  • Registratie: April 2001
  • Laatst online: 08:11

Snow_King

Konijn is stoer!

Topicstarter
MLM schreef op donderdag 30 juni 2011 @ 14:42:
Ik ben geen guru mbt GDB (of GCC/linux for that matter), maar in je stackframe #0 staat een this pointer van 0, dat is een veelvoorkomende oorzaak van een access violation/segfault
Ja, dat viel me ook op. Ik heb dus het idee dat het IoCTX object alle referentie met het RADOS object kwijt is en daardoor ook de connectie naar het RADOS cluster.

De 0 lijkt me daar dan ook verklaarbaar.

Heeft er iemand hier ervaring met het schrijven van PHP extensie waar objecten worden geretourneerd? De PHP documentatie hierover is schaars, eigenlijk is er niets over te vinden en moet je een beetje afkijken bij andere extensies.

  • user109731
  • Registratie: Maart 2004
  • Niet online
Ik zou eens naar SWIG kijken. Daarmee kun je extensies/wrappers voor allerlei talen (waaronder PHP) genereren. Hier is de documentatie voor PHP.

SWIG neemt het meeste werk voor je uit handen. In de documentatie zie je een aantal voorbeelden waarin ze bijvoorbeeld een header file hebben met een class definitie en vervolgens die class in PHP kunnen gebruiken.

En mocht je de extensie liever met de hand schrijven dan kun je altijd de gegenereerde code gebruiken om te zien wat er gedaan wordt :)

[Voor 5% gewijzigd door user109731 op 30-06-2011 20:05]



Tweakers maakt gebruik van cookies

Tweakers plaatst functionele en analytische cookies voor het functioneren van de website en het verbeteren van de website-ervaring. Deze cookies zijn noodzakelijk. Om op Tweakers relevantere advertenties te tonen en om ingesloten content van derden te tonen (bijvoorbeeld video's), vragen we je toestemming. Via ingesloten content kunnen derde partijen diensten leveren en verbeteren, bezoekersstatistieken bijhouden, gepersonaliseerde content tonen, gerichte advertenties tonen en gebruikersprofielen opbouwen. Hiervoor worden apparaatgegevens, IP-adres, geolocatie en surfgedrag vastgelegd.

Meer informatie vind je in ons cookiebeleid.

Sluiten

Toestemming beheren

Hieronder kun je per doeleinde of partij toestemming geven of intrekken. Meer informatie vind je in ons cookiebeleid.

Functioneel en analytisch

Deze cookies zijn noodzakelijk voor het functioneren van de website en het verbeteren van de website-ervaring. Klik op het informatie-icoon voor meer informatie. Meer details

janee

    Relevantere advertenties

    Dit beperkt het aantal keer dat dezelfde advertentie getoond wordt (frequency capping) en maakt het mogelijk om binnen Tweakers contextuele advertenties te tonen op basis van pagina's die je hebt bezocht. Meer details

    Tweakers genereert een willekeurige unieke code als identifier. Deze data wordt niet gedeeld met adverteerders of andere derde partijen en je kunt niet buiten Tweakers gevolgd worden. Indien je bent ingelogd, wordt deze identifier gekoppeld aan je account. Indien je niet bent ingelogd, wordt deze identifier gekoppeld aan je sessie die maximaal 4 maanden actief blijft. Je kunt deze toestemming te allen tijde intrekken.

    Ingesloten content van derden

    Deze cookies kunnen door derde partijen geplaatst worden via ingesloten content. Klik op het informatie-icoon voor meer informatie over de verwerkingsdoeleinden. Meer details

    janee